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   30 use strict;
  5         9  
  5         126  
4 5     5   22 use warnings;
  5         9  
  5         99  
5 5     5   69 use 5.012;
  5         14  
6              
7             require Net::IPAddress::Util;
8             require Net::IPAddress::Util::Collection::Tie;
9             require Net::IPAddress::Util::Range;
10              
11             our $VERSION = '5.000';
12              
13             sub new {
14 46 100   46 1 98 my $class = ref($_[0]) ? ref(shift()) : shift;
15 46         92 my @contents = @_;
16 46         59 my @o;
17 46         255 tie @o, 'Net::IPAddress::Util::Collection::Tie', \@contents;
18 46         145 return bless \@o => $class;
19             }
20              
21             sub sorted {
22 4     4 1 7 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         15 my $from = [ map { [ unpack('C32', $_->{ lower }->{ address } . $_->{ upper }->{ address }) ] } @$self ];
  20         89  
27 4         58 my $to;
28 4         18 for (my $i = 31; $i >= 0; $i--) {
29 128         204 $to = [];
30 128         176 for my $card (@$from) {
31 640         655 push @{$to->[ $card->[ $i ] ]}, $card;
  640         984  
32             }
33 128   100     169 $from = [ map { @{$_ // []} } @$to ];
  7826         8310  
  7826         15358  
34             }
35             my @rv = map {
36 4         11 my $n = $_;
  20         25  
37 20         29 my $l = Net::IPAddress::Util->new([@{$n}[0 .. 15]]);
  20         80  
38 20         53 my $r = Net::IPAddress::Util->new([@{$n}[16 .. 31]]);
  20         71  
39 20         86 my $x = Net::IPAddress::Util::Range->new({ lower => $l, upper => $r });
40 20         60 $x;
41             } @$from;
42 4         15 return $self->new(@rv);
43             }
44              
45             sub compacted {
46 4     4 1 10 my $self = shift;
47 4         6 my @sorted = @{$self->sorted()};
  4         54  
48 4         20 my @compacted;
49             my $elem;
50 4         16 while ($elem = shift @sorted) {
51 20 100 66     67 if (scalar @sorted and $elem->{ upper } >= $sorted[0]->{ lower } - 1) {
52 16         63 $elem = ref($elem)->new({ lower => $elem->{ lower }, upper => $sorted[0]->{ upper } });
53 16         44 shift @sorted;
54 16         41 redo;
55             }
56             else {
57 4         14 push @compacted, $elem;
58             }
59             }
60 4         10 return $self->new(@compacted);
61             }
62              
63             sub tight {
64 2     2 1 5 my $self = shift;
65 2         4 my @tight;
66 2         4 map { push @tight, @{$_->tight()} } @{$self->compacted()};
  2         6  
  2         9  
  2         6  
67 2         15 return $self->new(@tight);
68             }
69              
70             sub as_cidrs {
71 2     2 1 6 my $self = shift;
72 2         8 return map { $_->as_cidr() } grep { eval { $_->{ lower } } } @$self;
  18         43  
  18         22  
  18         41  
73             }
74              
75             sub as_netmasks {
76 2     2 1 5 my $self = shift;
77 2         13 return map { $_->as_netmask() } grep { eval { $_->{ lower } } } @$self;
  18         46  
  18         28  
  18         46  
78             }
79              
80             sub as_ranges {
81 2     2 1 5 my $self = shift;
82 2         8 return map { $_->as_string() } grep { eval { $_->{ lower } } } @$self;
  18         41  
  18         28  
  18         39  
83             }
84              
85             1;
86              
87             __END__