Skip Menu |

This queue is for tickets about the NetAddr-IP CPAN distribution.

Report information
The Basics
Id: 68273
Status: resolved
Worked: 1 hour (60 min)
Priority: 0/
Queue: NetAddr-IP

People
Owner: michael [...] bizsystems.com
Requestors: codebard [...] gmail.com
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 4.043
Fixed in: (no value)



Subject: Problem with ->compactref
I encountered a problem trying to use ->compactref(\@list) where the (incorrect) results I was receiving were closer to an expansion rather than a compaction -- the results were correct when using Compact(@list) and ->compact(@list). I got consistent results with Perl 5.8.8, 5.10.1, and 5.12.3 under Linux and Darwin. When I checked the code, it appeared that ->compactref() only took into account an array ref of NetAddr::IP objects as its only argument, so Compact(@list) and ->compact(@list) worked but ->compactref(\@list) did not since the first argument would be a NetAddr::IP object and the second would be the array ref. Here is a patch that should address that. I also implemented support and POD for Compact(\@list), which made the most sense to me without having to add an export for a "Compactref". I've also included a patch to augment t/v4-compact.t Thanks. Rusty
Subject: compact-t.patch
--- t/v4-compact.t 2008-12-02 12:54:12.000000000 -0800 +++ t/v4-compact-new.t 2011-05-17 12:35:14.000000000 -0700 @@ -18,44 +18,93 @@ exit 0; } -print "1..2\n"; +print "1..9\n"; -my @ips; +my @ips1; for my $ip ('10.0.0.0', '11.0.0.0', '12.0.0.0') { - push @ips, NetAddr::IP->new($ip, 24)->split(32); + push @ips1, NetAddr::IP->new($ip, 24)->split(32); } for my $ip ('20.0.0.0', '30.0.0.0', '40.0.0.0') { - push @ips, NetAddr::IP->new($ip, 16)->split(28); + push @ips1, NetAddr::IP->new($ip, 16)->split(28); } -my @c = Compact(@ips); -my @m; +my @ips2; -for my $c (@c) { - push @m, grep { $c->addr eq $_->[0] and $c->mask eq $_->[1] } @r; +for my $num (0 .. 255) { + push @ips2, NetAddr::IP->new("192.168.$num.0", 24); } +my $ips2_compact = '192.168.0.0/16'; -if (@m == @c) { - print "ok 1\n"; -} -else { - print "not ok 1\n"; -} +# Compact(@) +# +compact_ips1_check(1, Compact(@ips1)); +compact_ips2_check(2, Compact(@ips2)); + +# ->compact(@) +# +compact_ips1_check(3, $ips1[0]->compact(@ips1[1..$#ips1])); +compact_ips2_check(4, $ips2[0]->compact(@ips2[1..$#ips2])); + +# Compact([]) +# +compact_ips1_check(5, @{Compact(\@ips1)}); +compact_ips2_check(6, @{Compact(\@ips2)}); + +# ->compactref([]) +# +compact_ips1_check(7, @{$ips1[0]->compactref([@ips1[1..$#ips1]])}); +compact_ips2_check(8, @{$ips2[0]->compactref([@ips2[1..$#ips2]])}); -@ips = (); +# duplicate IP +# +@ips1 = (); for my $ip (qw(1.1.1.1 1.1.1.1 1.1.1.1 1.1.1.1)) { - push(@ips, NetAddr::IP->new($ip)); + push(@ips1, NetAddr::IP->new($ip)); } -@c = NetAddr::IP::compact(@ips); +@c = NetAddr::IP::compact(@ips1); if (@c == 1 and $c[0]->cidr() eq '1.1.1.1/32') { - print "ok 2\n"; + print "ok 9\n"; } else { - print "not ok 2\n"; + print "not ok 9\n"; } + +###################################################################### +sub compact_ips1_check +{ + my $num = shift; + my @ips = shift; + + my @mips; + for my $ip (@ips) { + push @mips, grep { $ip->addr eq $_->[0] and $ip->mask eq $_->[1] } @r; + } + + if (@mips == @ips) { + print "ok $num\n"; + } + else { + print "not ok $num\n"; + } +} + + +###################################################################### +sub compact_ips2_check +{ + my $num = shift; + my @ips = shift; + + if (@ips == 1 and $ips[0] eq $ips2_compact) { + print "ok $num\n"; + } + else { + print "not ok $num\n"; + } +}
Subject: compact.patch
--- IP.pm 2011-04-06 11:31:14.000000000 -0700 +++ IP-new.pm 2011-05-17 12:34:21.000000000 -0700 @@ -390,7 +390,10 @@ } sub compact { - return @{compactref(\@_)}; + return compactref($_[0]) + if ref $_[0] eq 'ARRAY'; # Compact(\@list) + + return @{compactref(\@_)}; # Compact(@list) or ->compact(@list) } *Compact = \&compact; @@ -1084,7 +1087,9 @@ =item C<$me-E<gt>compactref(\@list)> -As usual, a faster version of =item C<-E<gt>compact()> that returns a +=item C<$compacted_object_list = Compact(\@list)> + +As usual, a faster version of C<-E<gt>compact()> that returns a reference to a list. Note that this method takes a reference to a list instead. @@ -1097,39 +1102,57 @@ # or return []; # return [] unless @r; - return [] unless (my @unr = @{$_[0]}); + my @r; + { + my $unr = []; + my $args = $_[0]; + + if (ref $_[0] eq __PACKAGE__ and ref $_[1] eq 'ARRAY') { + # ->compactref(\@list) + # + $unr = [$_[0], @{$_[1]}]; # keeping structures intact + } + else { + # Compact(@list) or ->compact(@list) or Compact(\@list) + # + $unr = $args; + } + + return [] unless @$unr; - foreach(0..$#unr) { - $unr[$_]->{addr} = $unr[$_]->network->{addr}; + for (@$unr) { + $_->{addr} = $_->network->{addr}; + } + + @r = sort @$unr; } - my @r = sort @unr; my $changed; do { - $changed = 0; - for(my $i=0; $i <= $#r -1;$i++) { - if ($r[$i]->contains($r[$i +1])) { - splice(@r,$i +1,1); - ++$changed; - --$i; - } - elsif ((notcontiguous($r[$i]->{mask}))[1] == (notcontiguous($r[$i +1]->{mask}))[1]) { # masks the same - if (hasbits($r[$i]->network->{addr} ^ $r[$i +1]->network->{addr})) { # if not the same netblock - my $upnet = $r[$i]->copy; - $upnet->{mask} = shiftleft($upnet->{mask},1); - if ($upnet->contains($r[$i +1])) { # adjacent nets in next net up - $r[$i] = $upnet; - splice(@r,$i +1,1); - ++$changed; - --$i; - } - } else { # identical nets - splice(@r,$i +1,1); - ++$changed; - --$i; - } - } - } + $changed = 0; + for(my $i=0; $i <= $#r -1;$i++) { + if ($r[$i]->contains($r[$i +1])) { + splice(@r,$i +1,1); + ++$changed; + --$i; + } + elsif ((notcontiguous($r[$i]->{mask}))[1] == (notcontiguous($r[$i +1]->{mask}))[1]) { # masks the same + if (hasbits($r[$i]->{addr} ^ $r[$i +1]->{addr})) { # if not the same netblock + my $upnet = $r[$i]->copy; + $upnet->{mask} = shiftleft($upnet->{mask},1); + if ($upnet->contains($r[$i +1])) { # adjacent nets in next net up + $r[$i] = $upnet; + splice(@r,$i +1,1); + ++$changed; + --$i; + } + } else { # identical nets + splice(@r,$i +1,1); + ++$changed; + --$i; + } + } + } } while $changed; return \@r; }
Same attachments
Subject: compact-t-patch.txt
--- t/v4-compact.t 2008-12-02 12:54:12.000000000 -0800 +++ t/v4-compact-new.t 2011-05-17 12:35:14.000000000 -0700 @@ -18,44 +18,93 @@ exit 0; } -print "1..2\n"; +print "1..9\n"; -my @ips; +my @ips1; for my $ip ('10.0.0.0', '11.0.0.0', '12.0.0.0') { - push @ips, NetAddr::IP->new($ip, 24)->split(32); + push @ips1, NetAddr::IP->new($ip, 24)->split(32); } for my $ip ('20.0.0.0', '30.0.0.0', '40.0.0.0') { - push @ips, NetAddr::IP->new($ip, 16)->split(28); + push @ips1, NetAddr::IP->new($ip, 16)->split(28); } -my @c = Compact(@ips); -my @m; +my @ips2; -for my $c (@c) { - push @m, grep { $c->addr eq $_->[0] and $c->mask eq $_->[1] } @r; +for my $num (0 .. 255) { + push @ips2, NetAddr::IP->new("192.168.$num.0", 24); } +my $ips2_compact = '192.168.0.0/16'; -if (@m == @c) { - print "ok 1\n"; -} -else { - print "not ok 1\n"; -} +# Compact(@) +# +compact_ips1_check(1, Compact(@ips1)); +compact_ips2_check(2, Compact(@ips2)); + +# ->compact(@) +# +compact_ips1_check(3, $ips1[0]->compact(@ips1[1..$#ips1])); +compact_ips2_check(4, $ips2[0]->compact(@ips2[1..$#ips2])); + +# Compact([]) +# +compact_ips1_check(5, @{Compact(\@ips1)}); +compact_ips2_check(6, @{Compact(\@ips2)}); + +# ->compactref([]) +# +compact_ips1_check(7, @{$ips1[0]->compactref([@ips1[1..$#ips1]])}); +compact_ips2_check(8, @{$ips2[0]->compactref([@ips2[1..$#ips2]])}); -@ips = (); +# duplicate IP +# +@ips1 = (); for my $ip (qw(1.1.1.1 1.1.1.1 1.1.1.1 1.1.1.1)) { - push(@ips, NetAddr::IP->new($ip)); + push(@ips1, NetAddr::IP->new($ip)); } -@c = NetAddr::IP::compact(@ips); +@c = NetAddr::IP::compact(@ips1); if (@c == 1 and $c[0]->cidr() eq '1.1.1.1/32') { - print "ok 2\n"; + print "ok 9\n"; } else { - print "not ok 2\n"; + print "not ok 9\n"; } + +###################################################################### +sub compact_ips1_check +{ + my $num = shift; + my @ips = shift; + + my @mips; + for my $ip (@ips) { + push @mips, grep { $ip->addr eq $_->[0] and $ip->mask eq $_->[1] } @r; + } + + if (@mips == @ips) { + print "ok $num\n"; + } + else { + print "not ok $num\n"; + } +} + + +###################################################################### +sub compact_ips2_check +{ + my $num = shift; + my @ips = shift; + + if (@ips == 1 and $ips[0] eq $ips2_compact) { + print "ok $num\n"; + } + else { + print "not ok $num\n"; + } +}
Subject: compact-patch.txt
--- IP.pm 2011-04-06 11:31:14.000000000 -0700 +++ IP-new.pm 2011-05-17 12:34:21.000000000 -0700 @@ -390,7 +390,10 @@ } sub compact { - return @{compactref(\@_)}; + return compactref($_[0]) + if ref $_[0] eq 'ARRAY'; # Compact(\@list) + + return @{compactref(\@_)}; # Compact(@list) or ->compact(@list) } *Compact = \&compact; @@ -1084,7 +1087,9 @@ =item C<$me-E<gt>compactref(\@list)> -As usual, a faster version of =item C<-E<gt>compact()> that returns a +=item C<$compacted_object_list = Compact(\@list)> + +As usual, a faster version of C<-E<gt>compact()> that returns a reference to a list. Note that this method takes a reference to a list instead. @@ -1097,39 +1102,57 @@ # or return []; # return [] unless @r; - return [] unless (my @unr = @{$_[0]}); + my @r; + { + my $unr = []; + my $args = $_[0]; + + if (ref $_[0] eq __PACKAGE__ and ref $_[1] eq 'ARRAY') { + # ->compactref(\@list) + # + $unr = [$_[0], @{$_[1]}]; # keeping structures intact + } + else { + # Compact(@list) or ->compact(@list) or Compact(\@list) + # + $unr = $args; + } + + return [] unless @$unr; - foreach(0..$#unr) { - $unr[$_]->{addr} = $unr[$_]->network->{addr}; + for (@$unr) { + $_->{addr} = $_->network->{addr}; + } + + @r = sort @$unr; } - my @r = sort @unr; my $changed; do { - $changed = 0; - for(my $i=0; $i <= $#r -1;$i++) { - if ($r[$i]->contains($r[$i +1])) { - splice(@r,$i +1,1); - ++$changed; - --$i; - } - elsif ((notcontiguous($r[$i]->{mask}))[1] == (notcontiguous($r[$i +1]->{mask}))[1]) { # masks the same - if (hasbits($r[$i]->network->{addr} ^ $r[$i +1]->network->{addr})) { # if not the same netblock - my $upnet = $r[$i]->copy; - $upnet->{mask} = shiftleft($upnet->{mask},1); - if ($upnet->contains($r[$i +1])) { # adjacent nets in next net up - $r[$i] = $upnet; - splice(@r,$i +1,1); - ++$changed; - --$i; - } - } else { # identical nets - splice(@r,$i +1,1); - ++$changed; - --$i; - } - } - } + $changed = 0; + for(my $i=0; $i <= $#r -1;$i++) { + if ($r[$i]->contains($r[$i +1])) { + splice(@r,$i +1,1); + ++$changed; + --$i; + } + elsif ((notcontiguous($r[$i]->{mask}))[1] == (notcontiguous($r[$i +1]->{mask}))[1]) { # masks the same + if (hasbits($r[$i]->{addr} ^ $r[$i +1]->{addr})) { # if not the same netblock + my $upnet = $r[$i]->copy; + $upnet->{mask} = shiftleft($upnet->{mask},1); + if ($upnet->contains($r[$i +1])) { # adjacent nets in next net up + $r[$i] = $upnet; + splice(@r,$i +1,1); + ++$changed; + --$i; + } + } else { # identical nets + splice(@r,$i +1,1); + ++$changed; + --$i; + } + } + } } while $changed; return \@r; }
Subject: Re: [rt.cpan.org #68273] Problem with ->compactref
Date: Wed, 18 May 2011 11:18:35 -0700
To: bug-NetAddr-IP [...] rt.cpan.org
From: michael [...] insulin-pumpers.org
Show quoted text
> Tue May 17 16:04:48 2011: Request 68273 was acted upon. > Transaction: Ticket created by RBOUR > Queue: NetAddr-IP > Subject: Problem with ->compactref > Broken in: 4.043 > Severity: Normal > Owner: Nobody > Requestors: codebard@gmail.com > Status: new > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=68273 > > >
Hi Rusty, In the patch: - if (hasbits($r[$i]->network->{addr} ^ $r[$i +1]->network->{addr})) { # if not the same netblock + if (hasbits($r[$i]->{addr} ^ $r[$i +1]->{addr})) { # if not the same netblock you made a change from comparing the network address to comparing IP addresses I would expect this to fail the test every time for adjacent addresses, even in the same netblock. I don't think this is appropriate, please let me know your thinking here. Best regards, Michael
Hi Michael, I might have missed something there. The objects going into the previous sort (and out to @r) are each assigned $_->{addr} = $_- Show quoted text
>network->{addr} . My thought was that if the objects are the same
coming out of the sort going into @r, then the fragments "$r[$i]- Show quoted text
>network->{addr} ^ $r[$i +1]->network->{addr}" and "$r[$i]->{addr} ^
$r[$i +1]->{addr}" would be equivalent. It didn't appear to me that $r[$i]->{addr} needed to change, and the omission of the extra call would yield a bit of a speed increase. If it is correct to squash the object->{addr} with object->network-> {addr} during compaction, then the omission seems ok to me since the the algorithm appears to splice out unneeded IP blocks and then shifting the masks. The changes that I've made pass the existing tests and the one I added. Perhaps there is an additional test that should be added? Thanks. Rusty
Subject: Re: [rt.cpan.org #68273] Problem with ->compactref
Date: Wed, 18 May 2011 14:57:30 -0700
To: bug-NetAddr-IP [...] rt.cpan.org
From: michael [...] insulin-pumpers.org
Show quoted text
> Queue: NetAddr-IP > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=68273 > > > Hi Michael, > > I might have missed something there. The objects going into the > previous sort (and out to @r) are each assigned $_->{addr} = $_-
> >network->{addr} .
Nope, I missed it. All along the code fragment you changed has been redundant. Good catch! Thanks. Show quoted text
> My thought was that if the objects are the same > coming out of the sort going into @r, then the fragments "$r[$i]-
> >network->{addr} ^ $r[$i +1]->network->{addr}" and "$r[$i]->{addr} ^
> $r[$i +1]->{addr}" would be equivalent. It didn't appear to me that > $r[$i]->{addr} needed to change, and the omission of the extra call > would yield a bit of a speed increase. > > If it is correct to squash the object->{addr} with object->network-> > {addr} during compaction, then the omission seems ok to me since the > the algorithm appears to splice out unneeded IP blocks and then > shifting the masks. > > The changes that I've made pass the existing tests and the one I > added. Perhaps there is an additional test that should be added? > > Thanks. > > Rusty
NetAddr::IP v4.044 uploaded to CPAN On Wed May 18 17:57:35 2011, michael@insulin-pumpers.org wrote: Show quoted text
> > Queue: NetAddr-IP > > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=68273 > > > > > Hi Michael, > > > > I might have missed something there. The objects going into the > > previous sort (and out to @r) are each assigned $_->{addr} = $_-
> > >network->{addr} .
> > Nope, I missed it. All along the code fragment you changed has been > redundant. Good catch! Thanks. >
> > My thought was that if the objects are the same > > coming out of the sort going into @r, then the fragments "$r[$i]-
> > >network->{addr} ^ $r[$i +1]->network->{addr}" and "$r[$i]->{addr} ^
> > $r[$i +1]->{addr}" would be equivalent. It didn't appear to me that > > $r[$i]->{addr} needed to change, and the omission of the extra call > > would yield a bit of a speed increase. > > > > If it is correct to squash the object->{addr} with object->network-> > > {addr} during compaction, then the omission seems ok to me since the > > the algorithm appears to splice out unneeded IP blocks and then > > shifting the masks. > > > > The changes that I've made pass the existing tests and the one I > > added. Perhaps there is an additional test that should be added? > > > > Thanks. > > > > Rusty
> >