@@ -369,31 +369,70 @@ typedef struct
369
369
static void
370
370
bitstream_pack (bitstream_write_cursor_t * bwcp , uint32_t val )
371
371
{
372
- // Fetch the quadword where our data goes.
373
- uint64_t qw = * (uint64_t * ) bwcp -> bwc_curp ;
372
+ size_t bits_left_in_first_byte = 8 - bwcp -> bwc_used ;
373
+ size_t bits_to_write_after_first_byte = bwcp -> bwc_nbits - bits_left_in_first_byte ;
374
+ size_t full_bytes_to_write = bits_to_write_after_first_byte / 8 ;
375
+ size_t remainder_bits_after_full_bytes = bits_to_write_after_first_byte % 8 ;
374
376
375
- // Swap the bytes.
376
- qw = bswap_64 (qw );
377
+ // write is small enough that it fits in current byte's remaining space with
378
+ // room to spare, so pad the bottom of the byte by left-shifting
379
+ if (bwcp -> bwc_nbits < bits_left_in_first_byte )
380
+ {
381
+ * bwcp -> bwc_curp = (* bwcp -> bwc_curp ) | ((uint8_t )(val << (bits_left_in_first_byte - bwcp -> bwc_nbits )));
382
+
383
+ // consume part of the byte and exit
384
+ bwcp -> bwc_used += bwcp -> bwc_nbits ;
385
+ return ;
386
+ }
377
387
378
- // Shift our bits into place and combine.
379
- qw |= ((uint64_t ) val << (64 - bwcp -> bwc_nbits - bwcp -> bwc_used ));
388
+ // write fits exactly in current byte's remaining space, so just OR it in to
389
+ // the bottom bits of the byte
390
+ if (bwcp -> bwc_nbits == bits_left_in_first_byte )
391
+ {
392
+ * bwcp -> bwc_curp = (* bwcp -> bwc_curp ) | (uint8_t )(val );
380
393
381
- // Swap the bytes back again.
382
- qw = bswap_64 (qw );
394
+ // consume remainder of byte and exit
395
+ bwcp -> bwc_used = 0 ;
396
+ bwcp -> bwc_curp += 1 ;
397
+ return ;
398
+ }
383
399
384
- // Write the word back out.
385
- * (uint64_t * ) bwcp -> bwc_curp = qw ;
400
+ // write DOES NOT fit into current byte, so shift off all but the topmost
401
+ // bits from the value and OR those into the bottom bits of the byte
402
+ /* bwcp->bwc_nbits > bits_left_in_first_byte */
403
+ * bwcp -> bwc_curp = (* bwcp -> bwc_curp ) | ((uint8_t )(val >> (bwcp -> bwc_nbits - bits_left_in_first_byte )));
386
404
387
- // We've used some more bits now.
388
- bwcp -> bwc_used += bwcp -> bwc_nbits ;
405
+ // consume remainder of byte
406
+ bwcp -> bwc_used = 0 ;
407
+ bwcp -> bwc_curp += 1 ;
389
408
390
- // Normalize the cursor.
391
- while (bwcp -> bwc_used >= 8 )
409
+ // if there are 8 or more bits of the value left to write, write them in one
410
+ // byte chunks, higher chunks first
411
+ if (full_bytes_to_write > 0 )
392
412
{
393
- bwcp -> bwc_used -= 8 ;
394
- bwcp -> bwc_curp += 1 ;
413
+ for (size_t i = 0 ; i < full_bytes_to_write ; ++ i )
414
+ {
415
+ size_t bits_to_keep = bits_left_in_first_byte + (8 * (i + 1 ));
416
+ size_t right_shift = (bwcp -> bwc_nbits - bits_to_keep );
417
+
418
+ // no OR here because byte is guaranteed to be completely unused
419
+ // see above, before conditional
420
+ * bwcp -> bwc_curp = (uint8_t )(val >> right_shift );
421
+
422
+ // consume entire byte
423
+ bwcp -> bwc_used = 0 ;
424
+ bwcp -> bwc_curp += 1 ;
425
+ }
395
426
}
427
+ if (remainder_bits_after_full_bytes > 0 )
428
+ {
429
+ uint8_t mask = (1 << remainder_bits_after_full_bytes ) - 1 ;
430
+ // no OR here because byte is guaranteed to be completely unused
431
+ * bwcp -> bwc_curp = ((uint8_t )val & mask ) << (8 - remainder_bits_after_full_bytes );
396
432
433
+ // consume part of the byte
434
+ bwcp -> bwc_used = remainder_bits_after_full_bytes ;
435
+ }
397
436
}
398
437
399
438
static void
0 commit comments