File Coverage

blib/lib/Net/IPAddress/Util/Collection.pm
Criterion Covered Total %
statement 67 67 100.0
branch 4 4 100.0
condition 4 5 80.0
subroutine 10 10 100.0
pod 7 7 100.0
total 92 93 98.9


line stmt bran cond sub pod time code
1             package Net::IPAddress::Util::Collection;
2              
3 5     5   37 use strict;
  5         10  
  5         157  
4 5     5   25 use warnings;
  5         11  
  5         116  
5 5     5   80 use 5.012;
  5         19  
6              
7             require Net::IPAddress::Util;
8             require Net::IPAddress::Util::Collection::Tie;
9             require Net::IPAddress::Util::Range;
10              
11             our $VERSION = '5.001';
12              
13             sub new {
14 46 100   46 1 126 my $class = ref($_[0]) ? ref(shift()) : shift;
15 46         101 my @contents = @_;
16 46         71 my @o;
17 46         288 tie @o, 'Net::IPAddress::Util::Collection::Tie', \@contents;
18 46         181 return bless \@o => $class;
19             }
20              
21             sub sorted {
22 4     4 1 10 my $self = shift;
23             # In theory, a raw radix sort is O(N), which beats Perl's O(N log N) by
24             # a fair margin. However, it _does_ discard duplicates, so ymmv.
25             # FIXME Should we sort by hi, lo instead of lo, hi?
26 4         66 my $from = [ map { [ unpack('C32', $_->{ lower }->{ address } . $_->{ upper }->{ address }) ] } @$self ];
  20         111  
27 4         13 my $to;
28 4         18 for (my $i = 31; $i >= 0; $i--) {
29 128         297 $to = [];
30 128         213 for my $card (@$from) {
31 640         851 push @{$to->[ $card->[ $i ] ]}, $card;
  640         1278  
32             }
33 128   100     210 $from = [ map { @{$_ // []} } @$to ];
  7826         9999  
  7826         19283  
34             }
35             my @rv = map {
36 4         13 my $n = $_;
  20         34  
37 20         38 my $l = Net::IPAddress::Util->new([@{$n}[0 .. 15]]);
  20         83  
38 20         59 my $r = Net::IPAddress::Util->new([@{$n}[16 .. 31]]);
  20         82  
39 20         109 my $x = Net::IPAddress::Util::Range->new({ lower => $l, upper => $r });
40 20         65 $x;
41             } @$from;
42 4         19 return $self->new(@rv);
43             }
44              
45             sub compacted {
46 4     4 1 11 my $self = shift;
47 4         9 my @sorted = @{$self->sorted()};
  4         13  
48 4         20 my @compacted;
49             my $elem;
50 4         19 while ($elem = shift @sorted) {
51 20 100 66     83 if (scalar @sorted and $elem->{ upper } >= $sorted[0]->{ lower } - 1) {
52 16         77 $elem = ref($elem)->new({ lower => $elem->{ lower }, upper => $sorted[0]->{ upper } });
53 16         51 shift @sorted;
54 16         52 redo;
55             }
56             else {
57 4         16 push @compacted, $elem;
58             }
59             }
60 4         14 return $self->new(@compacted);
61             }
62              
63             sub tight {
64 2     2 1 7 my $self = shift;
65 2         5 my @tight;
66 2         4 map { push @tight, @{$_->tight()} } @{$self->compacted()};
  2         5  
  2         11  
  2         8  
67 2         14 return $self->new(@tight);
68             }
69              
70             sub as_cidrs {
71 2     2 1 7 my $self = shift;
72 2         9 return map { $_->as_cidr() } grep { eval { $_->{ lower } } } @$self;
  18         65  
  18         31  
  18         46  
73             }
74              
75             sub as_netmasks {
76 2     2 1 7 my $self = shift;
77 2         14 return map { $_->as_netmask() } grep { eval { $_->{ lower } } } @$self;
  18         54  
  18         32  
  18         52  
78             }
79              
80             sub as_ranges {
81 2     2 1 8 my $self = shift;
82 2         9 return map { $_->as_string() } grep { eval { $_->{ lower } } } @$self;
  18         52  
  18         30  
  18         51  
83             }
84              
85             1;
86              
87             __END__