-// A data source for efficient reading of bit-level data.
-struct bit_source {
- // Short-term bit reservoir; holds up to 64 bits. When it's empty,
- // it needs to get refilled from the medium-term bit reservoir.
- bitreservoir_t bits;
- unsigned bits_available;
-
- // Medium-term bit reservoir; holds a few kilobytes of spare data.
- // When this is empty, it needs to be refilled from the input
- // stream.
- uint8_t* bytes;
- unsigned bytes_available;
-
- // Data source.
- input_func_t* input_func;
- void* userdata;
-};
-
-void init_bit_source(struct bit_source* source, input_func_t* input_func, void* userdata);
-
-// Internal function. Do not use.
-void possibly_refill_slow_path(struct bit_source* source, unsigned num_bits);
-
-// Make sure there's at least NUM_BITS available in the short-term bit reservoir.
-// You usually want to call this before read_bits(). The reason it's separate
-// is that if you want two reads and you know the size of both, it's faster to
-// refill A+B, read A, read B than refill A, read A, refill B, read B.
-static inline void possibly_refill(struct bit_source* source, unsigned num_bits)
-{
- assert(num_bits <= BITRESERVOIR_FILL_SIZE + 1);
-
- if (source->bits_available >= num_bits) {
- // Fast path (~90% of invocations?)
- return;
- }
-
- // Slower path (~99% of remaining invocations?)
- assert(source->bits_available + BITRESERVOIR_FILL_SIZE < BITRESERVOIR_SIZE);
- if (source->bytes_available >= sizeof(bitreservoir_fill_t)) {
- bitreservoir_fill_t fill = read_bitreservoir_fill(source->bytes);
- source->bytes += sizeof(bitreservoir_fill_t);
- source->bytes_available -= sizeof(bitreservoir_fill_t);
- source->bits |= (bitreservoir_t)fill << (BITRESERVOIR_SIZE - BITRESERVOIR_FILL_SIZE - source->bits_available);
- source->bits_available += BITRESERVOIR_FILL_SIZE;
- return;
- }