blob: e9bce3535a081fedf21ab3ff06b4e18c221d2e30 [file] [log] [blame]
package BitRange;
use warnings;
use strict;
use Data::Dumper;
#-------------------------------------------------------------------------------
# Takes a string of integers separated by ',' (concat) and ':' (range). Will
# return a sorted list of the expanded strings.
sub expand($)
{
my ( $str ) = @_;
my @list;
for my $e ( split(/,/, $str) )
{
if ( $e =~ /([0-9]+):([0-9]+)/ )
{
push @list, $_ foreach ( int($1)..int($2) );
}
else
{
push @list, int($e);
}
}
return @list;
}
#-------------------------------------------------------------------------------
sub __combineConsecutiveRanges($$;$$); # because it is called recursively
sub __combineConsecutiveRanges($$;$$)
{
my ( $in, $out, $first, $last ) = @_;
# Check if there are any elements in the input list.
if ( 0 < scalar @{$in} )
{
# Check if we have found any previous range elements.
if ( defined $first )
{
if ( defined $last )
{
# We have at least two in a range. Check if the next one is in
# the consecutive range.
if ( $last + 1 == $in->[0] )
{
$last = shift @{$in};
}
# This range is done. Add to the list and start the next range.
else
{
push @{$out}, "$first:$last";
$first = shift @{$in};
$last = undef;
}
}
else
{
# Only the first element in the range so far. Check if the next
# one is in the consecutive range.
if ( $first + 1 == $in->[0] )
{
$last = shift @{$in};
}
# This range is done. Add to the list and start the next range.
else
{
push @{$out}, "$first";
$first = shift @{$in};
$last = undef;
}
}
}
# No previous range elements. Get the first one.
else
{
$first = shift @{$in};
$last = undef; # Just in case.
}
# Iterate again.
__combineConsecutiveRanges($in, $out, $first, $last);
}
# Nothing else in the input list. Add any trailing range elements.
elsif ( defined $first )
{
push @{$out}, "$first" . ((defined $last) ? ":$last" : "");
}
}
# Takes a reference to a list of integers. Any set of consecutive integers will
# be combined using the ':' character to represent a range
# (i.e. 0,1,2,3 => 0:3). The remaining non-consecutive integers will be combined
# with ',' character (i.e. 0,2,3,5 => 0,2:3,5).
sub compress($)
{
my ( $in ) = @_;
# Next, combine all of the consecutive ranges.
my $out = [];
__combineConsecutiveRanges( $in, $out );
# Now, combine the non-consecutive elements and return the string.
return join( ',', @{$out} );
}
#-------------------------------------------------------------------------------
1;