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   3120 use strict;
  5         12  
  5         125  
4 5     5   21 use warnings;
  5         9  
  5         111  
5 5     5   92 use 5.012;
  5         19  
6              
7             use overload (
8 5         28 '""' => 'as_string',
9             '<=>' => '_spaceship',
10             'cmp' => '_spaceship',
11 5     5   29 );
  5         10  
12              
13 5     5   2167 use Net::IPAddress::Util qw( :constr :manip );
  5         1654  
  5         8505  
14             require Net::IPAddress::Util::Collection;
15              
16             our $VERSION = '5.000';
17              
18             sub new {
19 222     222 1 7561 my $class = shift;
20 222   33     574 $class = ref($class) || $class;
21 222         345 my ($arg_ref) = @_;
22 222         296 my ($l, $u);
23 222 100 66     609 if ($arg_ref->{ lower } && $arg_ref->{ upper }) {
    50          
24 112         285 $arg_ref->{ lower } = IP($arg_ref->{ lower });
25 112         269 $arg_ref->{ upper } = IP($arg_ref->{ upper });
26 112 50       311 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         364 return bless $arg_ref => $class;
30             }
31             elsif ($arg_ref->{ ip }) {
32 110         159 my $ip;
33 110         130 my $nm = 2;
34 110 100       324 if ($arg_ref->{ netmask }) {
    100          
    100          
35 2         11 $ip = IP($arg_ref->{ ip });
36 2         17 my $was_ipv4 = $ip->is_ipv4;
37 2         8 $nm = IP($arg_ref->{ netmask });
38 2         7 $ip &= $nm;
39 2         10 $nm = ~$nm;
40 2 50       9 if ($was_ipv4) {
41 2         6 $nm &= ipv4_mask();
42             }
43 2         6 $l = $ip;
44 2         7 $u = $ip | $nm;
45             }
46             elsif ($arg_ref->{ ip } =~ m{(.*?)/(\d+)}) {
47 8         28 my ($t, $cidr) = ($1, $2);
48 8         23 $ip = IP($t);
49 8         26 my $was_ipv4 = $ip->is_ipv4;
50 8 100       27 my $span
51             = ($was_ipv4
52             ? 32
53             : 128) - $cidr
54             ;
55 8         34 $nm = implode_ip(substr(('1' x 128) . ('0' x $span), -128));
56 8         76 $ip &= $nm;
57 8         19 $l = $ip;
58 8         20 $u = $ip | ~$nm;
59             }
60             elsif ($arg_ref->{ cidr }) {
61 98         211 $ip = IP($arg_ref->{ ip });
62 98         238 my $was_ipv4 = $ip->is_ipv4;
63 98         139 my $cidr = $arg_ref->{ cidr };
64 98 50       189 my $span
65             = ($was_ipv4
66             ? 32
67             : 128) - $cidr
68             ;
69 98         308 $nm = implode_ip(substr(('1' x 128) . ('0' x $span), -128));
70 98         957 $ip &= $nm;
71 98         198 $l = $ip;
72 98         224 $u = $ip | ~$nm;
73             }
74             else {
75 2         10 $l = IP($arg_ref->{ ip });
76 2         10 $u = IP($arg_ref->{ ip });
77             }
78             }
79 110         527 return bless { lower => $l, upper => $u } => $class;
80             }
81              
82             sub as_string {
83 46     46 1 128 my $self = shift;
84 46         116 return "($self->{ lower } .. $self->{ upper })";
85             }
86              
87             sub outer_bounds {
88 174     174 1 257 my $self = shift;
89 174         424 my @l = explode_ip($self->{ lower });
90 174         1260 my @u = explode_ip($self->{ upper });
91 174         1293 my @cidr = common_prefix(@l, @u);
92 174         325 my $cidr = scalar @cidr;
93 174         360 my $base = implode_ip(ip_pad_prefix(@cidr));
94 174 100       2179 if ($base->is_ipv4()) {
95 172         241 $cidr -= 96;
96             }
97 174         380 my @mask = prefix_mask(@l, @u);
98 174         442 my $nm = implode_ip(ip_pad_prefix(@mask));
99 174         2305 my $x = ~$nm;
100 174 100       561 if ($base->is_ipv4()) {
101 172         371 $nm &= ipv4_mask();
102             }
103 174         569 my $hi = IP($base);
104 174         457 $hi |= $x;
105 174         4090 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 50 my $self = shift;
115 36 50       96 return $self if $self->{ upper } == $self->{ lower };
116 36         79 my $bounds = $self->outer_bounds();
117 36         105 my $new = ref($self)->new($self);
118 36   100     94 while ($bounds->{ upper } > $self->{ upper } or $bounds->{ lower } < $self->{ lower }) {
119 96         358 $new = ref($self)->new({ ip => $self->{ lower }, cidr => $bounds->{ cidr } + 1 });
120 96         271 $bounds = $new->outer_bounds();
121             }
122 36         130 return $new;
123             }
124              
125             sub as_cidr {
126 18     18 1 29 my $self = shift;
127 18         29 my $hr = $self->outer_bounds();
128 18         64 return "$hr->{ lower }" . '/' . "$hr->{ cidr }";
129             }
130              
131             sub as_netmask {
132 18     18 1 31 my $self = shift;
133 18         38 my $hr = $self->outer_bounds();
134 18         58 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 60 my $self = shift;
155 36         82 my $inner = $self->inner_bounds();
156 36         177 my $rv = Net::IPAddress::Util::Collection->new();
157 36         127 push @$rv, $inner;
158 36 100       99 if ($inner->{ upper } < $self->{ upper }) {
159 32         106 my $remainder = ref($self)->new({ lower => $inner->{ upper } + 1, upper => $self->{ upper } });
160 32         86 push @$rv, @{$remainder->tight()};
  32         122  
161             }
162 36         222 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__