tags:

views:

62

answers:

3

I have a string of packed values which was created sequentially using something like:

while (...) {
 ...
 $packed .= pack( 'L', $val );
}

In another program, after I load $packed, I wish to find out how many values were actually packed. I know how to do that after unpacking:

my @vals = unpack( 'L*', $packed );
print scalar(@vals);

But is it really necessary? If I only care about the number of values, can I do better and skip the unpacking?

+7  A: 

Since you know the size of a packed value (L is an unsigned 32-bit int, or 4 bytes), just divide the length by the size:

my $count = length($packed) / 4;

If you don't want to hard code the size, you could also pack a sample value to calculate it. (Note that Perl's compile-time constant folding doesn't work with pack, at least not with 5.10.1, so you'd want to do that calculation only once.)

my $size = length(pack('L', 0));
...
my $count = length($packed) / $size;
cjm
+1: you really know `pack` well.
drewk
@cjm could you please explain your comment `(Note that ...)`? I didn't get it.
David B
@David: Perl interpreter would not found that `length(pack('L', 0))` is constant so this expression would be interpreted each time it found. Anyway you can use `use constant LLength => length(pack("L", 0));` and perl will interpolate it for you as constant.
Hynek -Pichi- Vychodil
@David B, when Perl compiles your script, it does [constant folding](http://en.wikipedia.org/wiki/Constant_folding). However, as of 5.10.1, it does not recognize that `pack` (with constant arguments) could be evaluated at compile time, so it can't convert `length(pack('L', 0))` into `4`; it has to create the packed string every time that line of code is executed. It's not that important, unless you're evaluating that expression a great many times.
cjm
David B
FWIW, pack and unpack aren't easily folded away mostly because of the `p` template. Right now using that with a literal string constant works just fine as the scalar representing the constant will be referenced directly by the optree, keeping it around. If one was to fold away that constant and the pack/unpack it is used in the behaviour of some code such as `unpack('p<', pack('p<', 'foo'))` would change. This would need to be either a pretty smart optimisation or violate some assumptions existing code might make regarding the life-time of literal string constants.
rafl
+1  A: 

Since L is merely groups of 32 bit values, you can simply count the number of bytes and divide by 4.

slebetman
A: 
use constant LLength => length(pack("L", 0));
...
print length($packed)/LLength;

Check if LLength is really constant:

$ perl -MO=Deparse,-d -e'use constant L => length(pack("L", 0));print L, "\n";'
sub L () { 4 }
use constant ("L", length pack("L", 0));
print 4, "\n";
-e syntax OK
Hynek -Pichi- Vychodil
`L` is explicitely defined as a 32-bit integer, so this check is not needed. This is different from `L!` which is a native long.
dolmen
@dolmen: You are dunno. This check checks if `LLength` would be placed there as constant or would be evaluated as function call. It doesn't have anything with `L`, `L!` or any other type. It is matter of performance!
Hynek -Pichi- Vychodil