@@ -246,38 +246,37 @@ sub read_f8le {
246
246
sub align_to_byte {
247
247
my ($self ) = @_ ;
248
248
249
- $self -> {bits } = 0;
250
249
$self -> {bits_left } = 0;
250
+ $self -> {bits } = 0;
251
251
}
252
252
253
253
sub read_bits_int_be {
254
254
my ($self , $n ) = @_ ;
255
+ my $res = 0;
255
256
256
257
my $bits_needed = $n - $self -> {bits_left };
258
+ $self -> {bits_left } = -$bits_needed & 7; # `-$bits_needed mod 8`
259
+
257
260
if ($bits_needed > 0) {
258
261
# 1 bit => 1 byte
259
262
# 8 bits => 1 byte
260
263
# 9 bits => 2 bytes
261
- my $bytes_needed = int (($bits_needed - 1) / 8) + 1;
264
+ my $bytes_needed = (($bits_needed - 1) >> 3) + 1; # `ceil($bits_needed / 8)` (NB: `x >> 3` is `floor(x / 8)`,
265
+ # but ONLY for `x >= 0`, because `>>` is unsigned in Perl
266
+ # unless it is inside a `use integer` block)
262
267
my $buf = $self -> read_bytes($bytes_needed );
263
- for my $byte (split (" " , $buf )) {
264
- $byte = unpack (" C" , $byte );
265
- $self -> {bits } <<= 8;
266
- $self -> {bits } |= $byte ;
267
- $self -> {bits_left } += 8;
268
+ for my $byte (unpack (' C*' , $buf )) {
269
+ $res = $res << 8 | $byte ;
268
270
}
269
- }
270
-
271
- # Raw mask with required number of 1s, starting from lowest bit
272
- my $mask = (1 << $n ) - 1;
273
271
274
- # Shift $self->{bits} to align the highest bits with the mask & derive reading result
275
- my $shift_bits = $self -> {bits_left } - $n ;
276
- my $res = ($self -> {bits } >> $shift_bits ) & $mask ;
272
+ my $new_bits = $res ;
273
+ $res = $res >> $self -> {bits_left } | $self -> {bits } << $bits_needed ;
274
+ $self -> {bits } = $new_bits ; # will be masked at the end of the function
275
+ } else {
276
+ $res = $self -> {bits } >> -$bits_needed ; # shift unneeded bits out
277
+ }
277
278
278
- # Clear top bits that we've just read => AND with 1s
279
- $self -> {bits_left } -= $n ;
280
- $mask = (1 << $self -> {bits_left }) - 1;
279
+ my $mask = (1 << $self -> {bits_left }) - 1; # `bits_left` is in range 0..7
281
280
$self -> {bits } &= $mask ;
282
281
283
282
return $res ;
@@ -294,28 +293,34 @@ sub read_bits_int {
294
293
sub read_bits_int_le {
295
294
my ($self , $n ) = @_ ;
296
295
296
+ my $res = 0;
297
297
my $bits_needed = $n - $self -> {bits_left };
298
+
298
299
if ($bits_needed > 0) {
299
300
# 1 bit => 1 byte
300
301
# 8 bits => 1 byte
301
302
# 9 bits => 2 bytes
302
- my $bytes_needed = int (($bits_needed - 1) / 8) + 1;
303
+ my $bytes_needed = (($bits_needed - 1) >> 3) + 1; # `ceil($bits_needed / 8)` (NB: `x >> 3` is `floor(x / 8)`,
304
+ # but ONLY for `x >= 0` - see `read_bits_int_be` method)
303
305
my $buf = $self -> read_bytes($bytes_needed );
304
- for my $byte ( split ( " " , $buf )) {
305
- $byte = unpack (" C " , $byte );
306
- $self -> { bits } |= ( $byte << $self -> { bits_left } );
307
- $self -> { bits_left } += 8 ;
306
+ my $i = 0;
307
+ for my $byte ( unpack (' C* ' , $buf )) {
308
+ $res |= $byte << ( $i * 8 );
309
+ $i ++ ;
308
310
}
311
+
312
+ my $new_bits = $res >> $bits_needed ;
313
+ $res = $res << $self -> {bits_left } | $self -> {bits };
314
+ $self -> {bits } = $new_bits ;
315
+ } else {
316
+ $res = $self -> {bits };
317
+ $self -> {bits } >>= $n ;
309
318
}
310
319
311
- # Raw mask with required number of 1s, starting from lowest bit
312
- my $mask = (1 << $n ) - 1;
313
- # Derive reading result
314
- my $res = $self -> {bits } & $mask ;
315
- # Remove bottom bits that we've just read by shifting
316
- $self -> {bits } >>= $n ;
317
- $self -> {bits_left } -= $n ;
320
+ $self -> {bits_left } = -$bits_needed & 7; # `-$bits_needed mod 8`
318
321
322
+ my $mask = (1 << $n ) - 1; # unlike some other languages, no problem with this in Perl
323
+ $res &= $mask ;
319
324
return $res ;
320
325
}
321
326
0 commit comments