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 5     5   4238 use strict;
  5         15  
  5         164  
4 5     5   29 use warnings;
  5         11  
  5         140  
5 5     5   108 use 5.012;
  5         19  
6              
7             use overload (
8 5         35 '""' => 'as_string',
9             '<=>' => '_spaceship',
10             'cmp' => '_spaceship',
11 5     5   32 );
  5         10  
12              
13 5     5   523 use Net::IPAddress::Util qw( :constr :manip );
  5         11  
  5         14482  
14             require Net::IPAddress::Util::Collection;
15              
16             our $VERSION = '5.001';
17              
18             sub new {
19 222     222 1 9188 my $class = shift;
20 222   33     683 $class = ref($class) || $class;
21 222         420 my ($arg_ref) = @_;
22 222         355 my ($l, $u);
23 222 100 66     789 if ($arg_ref->{ lower } && $arg_ref->{ upper }) {
    50          
24 112         300 $arg_ref->{ lower } = IP($arg_ref->{ lower });
25 112         307 $arg_ref->{ upper } = IP($arg_ref->{ upper });
26 112 50       378 if ($arg_ref->{ lower } > $arg_ref->{ upper }) {
27 0         0 ($arg_ref->{ lower }, $arg_ref->{ upper }) = ($arg_ref->{ upper }, $arg_ref->{ lower });
28             }
29 112         389 return bless $arg_ref => $class;
30             }
31             elsif ($arg_ref->{ ip }) {
32 110         190 my $ip;
33 110         164 my $nm = 2;
34 110 100       394 if ($arg_ref->{ netmask }) {
    100          
    100          
35 2         11 $ip = IP($arg_ref->{ ip });
36 2         10 my $was_ipv4 = $ip->is_ipv4;
37 2         9 $nm = IP($arg_ref->{ netmask });
38 2         11 $ip &= $nm;
39 2         9 $nm = ~$nm;
40 2 50       11 if ($was_ipv4) {
41 2         8 $nm &= ipv4_mask();
42             }
43 2         9 $l = $ip;
44 2         7 $u = $ip | $nm;
45             }
46             elsif ($arg_ref->{ ip } =~ m{(.*?)/(\d+)}) {
47 8         32 my ($t, $cidr) = ($1, $2);
48 8         29 $ip = IP($t);
49 8         32 my $was_ipv4 = $ip->is_ipv4;
50 8 100       33 my $span
51             = ($was_ipv4
52             ? 32
53             : 128) - $cidr
54             ;
55 8         46 $nm = implode_ip(substr(('1' x 128) . ('0' x $span), -128));
56 8         93 $ip &= $nm;
57 8         27 $l = $ip;
58 8         27 $u = $ip | ~$nm;
59             }
60             elsif ($arg_ref->{ cidr }) {
61 98         260 $ip = IP($arg_ref->{ ip });
62 98         334 my $was_ipv4 = $ip->is_ipv4;
63 98         187 my $cidr = $arg_ref->{ cidr };
64 98 50       218 my $span
65             = ($was_ipv4
66             ? 32
67             : 128) - $cidr
68             ;
69 98         441 $nm = implode_ip(substr(('1' x 128) . ('0' x $span), -128));
70 98         1106 $ip &= $nm;
71 98         219 $l = $ip;
72 98         279 $u = $ip | ~$nm;
73             }
74             else {
75 2         11 $l = IP($arg_ref->{ ip });
76 2         11 $u = IP($arg_ref->{ ip });
77             }
78             }
79 110         660 return bless { lower => $l, upper => $u } => $class;
80             }
81              
82             sub as_string {
83 46     46 1 159 my $self = shift;
84 46         151 return "($self->{ lower } .. $self->{ upper })";
85             }
86              
87             sub outer_bounds {
88 174     174 1 323 my $self = shift;
89 174         518 my @l = explode_ip($self->{ lower });
90 174         1480 my @u = explode_ip($self->{ upper });
91 174         1501 my @cidr = common_prefix(@l, @u);
92 174         399 my $cidr = scalar @cidr;
93 174         442 my $base = implode_ip(ip_pad_prefix(@cidr));
94 174 100       2790 if ($base->is_ipv4()) {
95 172         308 $cidr -= 96;
96             }
97 174         462 my @mask = prefix_mask(@l, @u);
98 174         509 my $nm = implode_ip(ip_pad_prefix(@mask));
99 174         2830 my $x = ~$nm;
100 174 100       692 if ($base->is_ipv4()) {
101 172         423 $nm &= ipv4_mask();
102             }
103 174         634 my $hi = IP($base);
104 174         529 $hi |= $x;
105 174         4944 return bless {
106             lower => $base,
107             cidr => $cidr,
108             netmask => $nm,
109             upper => $hi,
110             } => ref($self);
111             }
112              
113             sub inner_bounds {
114 36     36 1 62 my $self = shift;
115 36 50       127 return $self if $self->{ upper } == $self->{ lower };
116 36         98 my $bounds = $self->outer_bounds();
117 36         131 my $new = ref($self)->new($self);
118 36   100     117 while ($bounds->{ upper } > $self->{ upper } or $bounds->{ lower } < $self->{ lower }) {
119 96         509 $new = ref($self)->new({ ip => $self->{ lower }, cidr => $bounds->{ cidr } + 1 });
120 96         312 $bounds = $new->outer_bounds();
121             }
122 36         175 return $new;
123             }
124              
125             sub as_cidr {
126 18     18 1 35 my $self = shift;
127 18         43 my $hr = $self->outer_bounds();
128 18         66 return "$hr->{ lower }" . '/' . "$hr->{ cidr }";
129             }
130              
131             sub as_netmask {
132 18     18 1 36 my $self = shift;
133 18         40 my $hr = $self->outer_bounds();
134 18         65 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 36     36 1 99 my $self = shift;
155 36         90 my $inner = $self->inner_bounds();
156 36         195 my $rv = Net::IPAddress::Util::Collection->new();
157 36         202 push @$rv, $inner;
158 36 100       126 if ($inner->{ upper } < $self->{ upper }) {
159 32         184 my $remainder = ref($self)->new({ lower => $inner->{ upper } + 1, upper => $self->{ upper } });
160 32         152 push @$rv, @{$remainder->tight()};
  32         144  
161             }
162 36         198 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__