blob: e9bce3535a081fedf21ab3ff06b4e18c221d2e30 [file] [log] [blame]
Zane Shelleyabc51c22020-11-09 21:35:35 -06001package BitRange;
2
3use warnings;
4use strict;
5
6use Data::Dumper;
7
8#-------------------------------------------------------------------------------
9
10# Takes a string of integers separated by ',' (concat) and ':' (range). Will
11# return a sorted list of the expanded strings.
12sub expand($)
13{
14 my ( $str ) = @_;
15
16 my @list;
17 for my $e ( split(/,/, $str) )
18 {
19 if ( $e =~ /([0-9]+):([0-9]+)/ )
20 {
21 push @list, $_ foreach ( int($1)..int($2) );
22 }
23 else
24 {
25 push @list, int($e);
26 }
27 }
28
29 return @list;
30}
31
32#-------------------------------------------------------------------------------
33
34sub __combineConsecutiveRanges($$;$$); # because it is called recursively
35
36sub __combineConsecutiveRanges($$;$$)
37{
38 my ( $in, $out, $first, $last ) = @_;
39
40 # Check if there are any elements in the input list.
41 if ( 0 < scalar @{$in} )
42 {
43 # Check if we have found any previous range elements.
44 if ( defined $first )
45 {
46 if ( defined $last )
47 {
48 # We have at least two in a range. Check if the next one is in
49 # the consecutive range.
50 if ( $last + 1 == $in->[0] )
51 {
52 $last = shift @{$in};
53 }
54 # This range is done. Add to the list and start the next range.
55 else
56 {
57 push @{$out}, "$first:$last";
58 $first = shift @{$in};
59 $last = undef;
60 }
61 }
62 else
63 {
64 # Only the first element in the range so far. Check if the next
65 # one is in the consecutive range.
66 if ( $first + 1 == $in->[0] )
67 {
68 $last = shift @{$in};
69 }
70 # This range is done. Add to the list and start the next range.
71 else
72 {
73 push @{$out}, "$first";
74 $first = shift @{$in};
75 $last = undef;
76 }
77 }
78 }
79 # No previous range elements. Get the first one.
80 else
81 {
82 $first = shift @{$in};
83 $last = undef; # Just in case.
84 }
85
86 # Iterate again.
87 __combineConsecutiveRanges($in, $out, $first, $last);
88 }
89 # Nothing else in the input list. Add any trailing range elements.
90 elsif ( defined $first )
91 {
92 push @{$out}, "$first" . ((defined $last) ? ":$last" : "");
93 }
94}
95
96# Takes a reference to a list of integers. Any set of consecutive integers will
97# be combined using the ':' character to represent a range
98# (i.e. 0,1,2,3 => 0:3). The remaining non-consecutive integers will be combined
99# with ',' character (i.e. 0,2,3,5 => 0,2:3,5).
100sub compress($)
101{
102 my ( $in ) = @_;
103
104 # Next, combine all of the consecutive ranges.
105 my $out = [];
106 __combineConsecutiveRanges( $in, $out );
107
108 # Now, combine the non-consecutive elements and return the string.
109 return join( ',', @{$out} );
110}
111
112#-------------------------------------------------------------------------------
113
1141;