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