Use pack() and unpack(), or else vec() and the bitwise operations.
For example, this sets $vec to have bit N set if $ints[N] was set:
$vec = ''; foreach(@ints) { vec($vec,$_,1) = 1 }Here's how, given a vector in $vec, you can get those bits into your @ints array:
sub bitvec_to_list { my $vec = shift; my @ints; # Find null-byte density then select best algorithm if ($vec =~ tr/\0// / length $vec > 0.95) { use integer; my $i; # This method is faster with mostly null-bytes while($vec =~ /[^\0]/g ) { $i = -9 + 8 * pos $vec; push @ints, $i if vec($vec, ++$i, 1); push @ints, $i if vec($vec, ++$i, 1); push @ints, $i if vec($vec, ++$i, 1); push @ints, $i if vec($vec, ++$i, 1); push @ints, $i if vec($vec, ++$i, 1); push @ints, $i if vec($vec, ++$i, 1); push @ints, $i if vec($vec, ++$i, 1); push @ints, $i if vec($vec, ++$i, 1); } } else { # This method is a fast general algorithm use integer; my $bits = unpack "b*", $vec; push @ints, 0 if $bits =~ s/^(\d)// && $1; push @ints, pos $bits while($bits =~ /1/g); } return \@ints; }This method gets faster the more sparse the bit vector is. (Courtesy of Tim Bunce and Winfried Koenig.)
You can make the while loop a lot shorter with this suggestion from Benjamin Goldberg:
while($vec =~ /[^\0]+/g ) { push @ints, grep vec($vec, $_, 1), $-[0] * 8 .. $+[0] * 8; }Or use the CPAN module Bit::Vector:
$vector = Bit::Vector->new($num_of_bits); $vector->Index_List_Store(@ints); @ints = $vector->Index_List_Read();Bit::Vector provides efficient methods for bit vector, sets of small integers and "big int" math.
Here's a more extensive illustration using vec():
# vec demo $vector = "\xff\x0f\xef\xfe"; print "Ilya's string \\xff\\x0f\\xef\\xfe represents the number ", unpack("N", $vector), "\n"; $is_set = vec($vector, 23, 1); print "Its 23rd bit is ", $is_set ? "set" : "clear", ".\n"; pvec($vector);
set_vec(1,1,1); set_vec(3,1,1); set_vec(23,1,1);
set_vec(3,1,3); set_vec(3,2,3); set_vec(3,4,3); set_vec(3,4,7); set_vec(3,8,3); set_vec(3,8,7);
set_vec(0,32,17); set_vec(1,32,17);
sub set_vec { my ($offset, $width, $value) = @_; my $vector = ''; vec($vector, $offset, $width) = $value; print "offset=$offset width=$width value=$value\n"; pvec($vector); }
sub pvec { my $vector = shift; my $bits = unpack("b*", $vector); my $i = 0; my $BASE = 8;
print "vector length in bytes: ", length($vector), "\n"; @bytes = unpack("A8" x length($vector), $bits); print "bits are: @bytes\n\n"; }