File Coverage

blib/lib/Net/IPAddress/Util/Range.pm
Criterion Covered Total %
statement 95 107 88.7
branch 21 30 70.0
condition 6 12 50.0
subroutine 12 16 75.0
pod 10 10 100.0
total 144 175 82.2


line stmt bran cond sub pod time code
1             package Net::IPAddress::Util::Range;
2              
3 3     3   3253 use strict;
  3         15  
  3         125  
4 3     3   24 use warnings;
  3         8  
  3         129  
5 3     3   91 use 5.010;
  3         14  
6              
7             use overload (
8 3         28 '""' => 'as_string',
9             '<=>' => '_spaceship',
10             'cmp' => '_spaceship',
11 3     3   17 );
  3         6  
12              
13 3     3   390 use Net::IPAddress::Util qw( :constr :manip );
  3         8  
  3         7385  
14             require Net::IPAddress::Util::Collection;
15              
16             our $VERSION = '4.004';
17              
18             sub new {
19 111     111 1 6438 my $class = shift;
20 111   33     447 $class = ref($class) || $class;
21 111         291 my ($arg_ref) = @_;
22 111         216 my ($l, $u);
23 111 100 66     549 if ($arg_ref->{ lower } && $arg_ref->{ upper }) {
    50          
24 56         217 $arg_ref->{ lower } = IP($arg_ref->{ lower });
25 56         221 $arg_ref->{ upper } = IP($arg_ref->{ upper });
26 56 50       302 if ($arg_ref->{ lower } > $arg_ref->{ upper }) {
27 0         0 ($arg_ref->{ lower }, $arg_ref->{ upper }) = ($arg_ref->{ upper }, $arg_ref->{ lower });
28             }
29 56         284 return bless $arg_ref => $class;
30             }
31             elsif ($arg_ref->{ ip }) {
32 55         122 my $ip;
33 55         104 my $nm = 2;
34 55 100       284 if ($arg_ref->{ netmask }) {
    100          
    100          
35 1         6 $ip = IP($arg_ref->{ ip });
36 1         7 my $was_ipv4 = $ip->is_ipv4;
37 1         7 $nm = IP($arg_ref->{ netmask });
38 1         6 $ip &= $nm;
39 1         7 $nm = ~$nm;
40 1 50       7 if ($was_ipv4) {
41 1         7 $nm &= ipv4_mask();
42             }
43 1         6 $l = $ip;
44 1         6 $u = $ip | $nm;
45             }
46             elsif ($arg_ref->{ ip } =~ m{(.*?)/(\d+)}) {
47 4         24 my ($t, $cidr) = ($1, $2);
48 4         20 $ip = IP($t);
49 4         22 my $was_ipv4 = $ip->is_ipv4;
50 4 100       22 my $span
51             = ($was_ipv4
52             ? 32
53             : 128) - $cidr
54             ;
55 4         30 $nm = implode_ip(substr(('1' x 128) . ('0' x $span), -128));
56 4         69 $ip &= $nm;
57 4         16 $l = $ip;
58 4         18 $u = $ip | ~$nm;
59             }
60             elsif ($arg_ref->{ cidr }) {
61 49         255 $ip = IP($arg_ref->{ ip });
62 49         168 my $was_ipv4 = $ip->is_ipv4;
63 49         119 my $cidr = $arg_ref->{ cidr };
64 49 50       144 my $span
65             = ($was_ipv4
66             ? 32
67             : 128) - $cidr
68             ;
69 49         282 $nm = implode_ip(substr(('1' x 128) . ('0' x $span), -128));
70 49         597 $ip &= $nm;
71 49         133 $l = $ip;
72 49         174 $u = $ip | ~$nm;
73             }
74             else {
75 1         8 $l = IP($arg_ref->{ ip });
76 1         7 $u = IP($arg_ref->{ ip });
77             }
78             }
79 55         374 return bless { lower => $l, upper => $u } => $class;
80             }
81              
82             sub as_string {
83 23     23 1 123 my $self = shift;
84 23         110 return "($self->{ lower } .. $self->{ upper })";
85             }
86              
87             sub outer_bounds {
88 87     87 1 189 my $self = shift;
89 87         359 my @l = explode_ip($self->{ lower });
90 87         878 my @u = explode_ip($self->{ upper });
91 87         924 my @cidr = common_prefix(@l, @u);
92 87         277 my $cidr = scalar @cidr;
93 87         314 my $base = implode_ip(ip_pad_prefix(@cidr));
94 87 100       1516 if ($base->is_ipv4()) {
95 86         205 $cidr -= 96;
96             }
97 87         332 my @mask = prefix_mask(@l, @u);
98 87         393 my $nm = implode_ip(ip_pad_prefix(@mask));
99 87         1652 my $x = ~$nm;
100 87 100       380 if ($base->is_ipv4()) {
101 86         373 $nm &= ipv4_mask();
102             }
103 87         423 my $hi = IP($base);
104 87         324 $hi |= $x;
105 87         2875 return bless {
106             lower => $base,
107             cidr => $cidr,
108             netmask => $nm,
109             upper => $hi,
110             } => ref($self);
111             }
112              
113             sub inner_bounds {
114 18     18 1 48 my $self = shift;
115 18 50       67 return $self if $self->{ upper } == $self->{ lower };
116 18         78 my $bounds = $self->outer_bounds();
117 18         105 my $new = ref($self)->new($self);
118 18   100     90 while ($bounds->{ upper } > $self->{ upper } or $bounds->{ lower } < $self->{ lower }) {
119 48         310 $new = ref($self)->new({ ip => $self->{ lower }, cidr => $bounds->{ cidr } + 1 });
120 48         219 $bounds = $new->outer_bounds();
121             }
122 18         110 return $new;
123             }
124              
125             sub as_cidr {
126 9     9 1 18 my $self = shift;
127 9         23 my $hr = $self->outer_bounds();
128 9         33 return "$hr->{ lower }" . '/' . "$hr->{ cidr }";
129             }
130              
131             sub as_netmask {
132 9     9 1 19 my $self = shift;
133 9         25 my $hr = $self->outer_bounds();
134 9         2521 return "$hr->{ lower }" . ' (' . "$hr->{ netmask }" . ')';
135             }
136              
137             sub loose {
138 0     0 1 0 my $self = shift;
139 0         0 my $hr = $self->outer_bounds();
140 0         0 return ref($self)->new({ lower => $hr->{ lower }, upper => $hr->{ upper } });
141             }
142              
143             sub _spaceship {
144 0     0   0 my ($self, $rhs, $swapped) = @_;
145 0 0       0 ($self, $rhs) = ($rhs, $self) if $swapped;
146 0 0       0 $rhs = ref($self)->new({ ip => $rhs }) unless ref($self) eq ref($rhs);
147             return
148             $self->{ lower } <=> $rhs->{ lower }
149             || $self->{ upper } <=> $rhs->{ upper }
150 0   0     0 ;
151             }
152              
153             sub tight {
154 18     18 1 67 my $self = shift;
155 18         75 my $inner = $self->inner_bounds();
156 18         146 my $rv = Net::IPAddress::Util::Collection->new();
157 18         112 push @$rv, $inner;
158 18 100       97 if ($inner->{ upper } < $self->{ upper }) {
159 16         94 my $remainder = ref($self)->new({ lower => $inner->{ upper } + 1, upper => $self->{ upper } });
160 16         70 push @$rv, @{$remainder->tight()};
  16         95  
161             }
162 18         157 return $rv;
163             }
164              
165             sub lower {
166 0     0 1   my $self = shift;
167 0           return $self->{ lower };
168             }
169              
170             sub upper {
171 0     0 1   my $self = shift;
172 0           return $self->{ upper };
173             }
174              
175             1;
176              
177             __END__