]> git.sesse.net Git - fjl/blobdiff - bitsource.h
Add an x86 optimized version of extend().
[fjl] / bitsource.h
index 6cabbf004245139d6f3f5a8f5f5fac5cfdb646e6..f2f164db43821652acaf281c76f2b050f4041c7a 100644 (file)
@@ -2,6 +2,7 @@
 #define _BITSOURCE_H 1
 
 #include <assert.h>
+#include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <sys/types.h>
 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(__i386__) || defined(__x86_64__))
+       bitreservoir_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);
@@ -34,14 +42,22 @@ struct bit_source {
        // When this is empty, it needs to be refilled from the input
        // stream.
        uint8_t* bytes;
+       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);
@@ -62,8 +78,8 @@ 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->bytes);
-               source->bytes += sizeof(bitreservoir_fill_t);
+               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);
                source->bits_available += BITRESERVOIR_FILL_SIZE;