Greg Kennedy
Greg Kennedy

Reputation: 644

Empty `vec()` is not False

Consider this example:

#!/usr/bin/env perl

my $vec0;

# set the first bit of vec0 to false
vec($vec0, 0, 1) = 0;

print "vec0 is " . length($vec0) . " bytes long\n";

if ($vec0) {
  # what
  print "vec0 is True!\n";
}

A vec used in evaluation seems to (almost) always be True - this is because a vec is really a string, and so $vec0 is a string containing "\0" which is not False according to Perl: only strings "" and "0" are False.

(aside: this is False, despite being non-zero:

vec($vec0, 5, 1) = 1;
vec($vec0, 4, 1) = 1;

because 0x30 is the ASCII code for 0)

Fine: what is the "correct" way to check for an "empty" vector (i.e. all bits set to 0)? Count bits with unpack, regex test m/^\0*$/, "normalize" all vectors by chopping empty bytes off the end? This seems like it should be a solved problem... and why does Perl not treat vec magically for true/false?

Upvotes: 2

Views: 107

Answers (3)

ikegami
ikegami

Reputation: 386541

The following is probably the fastest approach without external C code:

$vec0 !~ tr/\x01-\xFF//   # True if "empty".
$vec0 =~ tr/\x01-\xFF//   # True if not "empty".

Upvotes: 2

zdim
zdim

Reputation: 66964

To check that

All bits in the vector are unset (0)

can convert it to a (bit)string with my $bits = unpack("b*", $vector) and then in numeric context that will be equal to zero ($bits == 0) if all bits are unset. So

if ( unpack("b*", $vec0) == 0 ) { say "All bits zero" }

This is a shorthand of checking that no bits are set, ( unpack("b*", $vec0) | 0 ) == 0.

I don't think that vec has any "magical" way of checking for this.

Upvotes: 3

Shawn
Shawn

Reputation: 52579

If you're using fixed-width vectors, you can create another one of the appropriate length that's all-zeros and compare it with ones you want to test.

my $zero_vec = pack "C*", (0) x $length_in_bytes;

# ...

if ($vec0 ne $zero_vec) {
  print "vec0 is True!\n";
}

I also found an old module on CPAN, String::BitCount, that counts the number of set bits in a string:

use String::BitCount;

# ...

if (BitCount($vec0)) {
  print "vec0 is True!\n";
}

or maybe a regular expression:

if ($vec0 !~ m/\A\x00+\z/) {
  print "vec0 is True!\n";
}

Upvotes: 2

Related Questions