X-Git-Url: https://git.sesse.net/?p=fjl;a=blobdiff_plain;f=bitsource.h;h=4126a618d34dedbfa90940696f0489602712cceb;hp=bb3a6d246e62016665e5560ac048397b15f7f8e9;hb=b86c08340ece81f07ede8740c4cf62abd40ba641;hpb=ddc3c24c837f081787825d128675eca628d0e91c diff --git a/bitsource.h b/bitsource.h index bb3a6d2..4126a61 100644 --- a/bitsource.h +++ b/bitsource.h @@ -2,6 +2,7 @@ #define _BITSOURCE_H 1 #include +#include #include #include #include @@ -14,9 +15,20 @@ typedef uint64_t bitreservoir_t; typedef uint32_t bitreservoir_fill_t; -static inline bitreservoir_fill_t read_bitreservoir_fill(uint8_t* source) +// Note: We return bitreservoir_t here, so we can get implicit zero extension on amd64. +static inline bitreservoir_t read_bitreservoir_fill(uint8_t* source) { +#if defined(__GNUC__) && defined(__x86_64__) + bitreservoir_t ret; + asm("bswapl %1" : "=r" (ret) : "0" (*(bitreservoir_fill_t*)(source))); + return ret; +#elif defined(__GNUC__) && defined(__i386__) + bitreservoir_fill_t ret; + asm("bswapl %1" : "=r" (ret) : "0" (*(bitreservoir_fill_t*)(source))); + return ret; +#else return ntohl(*(bitreservoir_fill_t*)(source)); +#endif } static const unsigned BITRESERVOIR_SIZE = 8 * sizeof(bitreservoir_t); @@ -37,12 +49,19 @@ struct bit_source { uint8_t* byte_read_ptr; unsigned bytes_available; + // Some clients will purposedly read a bit ahead of the stream, causing + // problems at EOF. Thus, the client is allowed to request that we pad + // the end stream with a few bytes after the source reports EOF. + int padding_bytes_available; + // Data source. input_func_t* input_func; void* userdata; + bool source_eof; }; -void init_bit_source(struct bit_source* source, input_func_t* input_func, void* userdata); +void init_bit_source(struct bit_source* source, input_func_t* input_func, + unsigned padding_bytes, void* userdata); // Internal function. Do not use. void possibly_refill_slow_path(struct bit_source* source, unsigned num_bits); @@ -63,7 +82,7 @@ static inline void possibly_refill(struct bit_source* source, unsigned num_bits) // 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->byte_read_ptr); + bitreservoir_t fill = read_bitreservoir_fill(source->byte_read_ptr); source->byte_read_ptr += sizeof(bitreservoir_fill_t); source->bytes_available -= sizeof(bitreservoir_fill_t); source->bits |= (bitreservoir_t)fill << (BITRESERVOIR_SIZE - BITRESERVOIR_FILL_SIZE - source->bits_available);