package fi.iki.yak.ts.compression.gorilla;

import java.nio.ByteBuffer;

/**
 * An implementation of BitInput that parses the data from byte array or existing ByteBuffer.
 *
 * @author Michael Burman
 */
public class ByteBufferBitInput implements BitInput {
    private ByteBuffer bb;
    private byte b;
    private int bitsLeft = 0;

    /**
     * Uses an existing ByteBuffer to read the stream. Starts at the ByteBuffer's current position.
     *
     * @param buf
     */
    public ByteBufferBitInput(ByteBuffer buf) {
        bb = buf;
        flipByte();
    }

    public ByteBufferBitInput(byte[] input) {
        this(ByteBuffer.wrap(input));
    }

    /**
     * Reads the next bit and returns a boolean representing it.
     *
     * @return true if the next bit is 1, otherwise 0.
     */
    public boolean readBit() {
        boolean bit = ((b >> (bitsLeft - 1)) & 1) == 1;
        bitsLeft--;
        flipByte();
        return bit;
    }

    /**
     * Reads a long from the next X bits that represent the least significant bits in the long value.
     *
     * @param bits How many next bits are read from the stream
     * @return
     */
    public long getLong(int bits) {
        long value = 0;
        while(bits > 0) {
            if(bits > bitsLeft || bits == Byte.SIZE) {
                // Take only the bitsLeft "least significant" bits
                byte d = (byte) (b & ((1<<bitsLeft) - 1));
                value = (value << bitsLeft) + (d & 0xFF);
                bits -= bitsLeft;
                bitsLeft = 0;
            } else {
                // TODO This isn't optimal - we need a range of bits
                for(; bits > 0; bits--) {
                    byte bit = (byte) ((b >> (bitsLeft - 1)) & 1);
                    bitsLeft--;
                    value = (value << 1) + (bit & 0xFF);
                }
            }
            flipByte();
        }
        return value;
    }

    private void flipByte() {
        if (bitsLeft == 0) {
            b = bb.get();
            bitsLeft = Byte.SIZE;
        }
    }

    /**
     * Returns the underlying ByteBuffer
     *
     * @return
     */
    public ByteBuffer getByteBuffer() {
        return this.bb;
    }
}

@@ -1587,104 +1587,71 @@
  // 
-TODO This isn't optimal - we need a range of bits%0A                for(; bits %3E 0; bits--) %7B%0A    
+Shift to correct position and take only least significant bits%0A
     
@@ -1667,19 +1667,17 @@
    byte 
-bit
+d
  = (byte
@@ -1680,24 +1680,25 @@
 byte) ((b %3E%3E
+%3E
  (bitsLeft -
@@ -1698,23 +1698,40 @@
 sLeft - 
-1
+bits
 )) & 
-1
+((1%3C%3Cbits) - 1)
 );%0A     
@@ -1745,79 +1745,78 @@
     
-    bitsLeft--;%0A                    value = (value %3C%3C 1) + (bit & 0xFF)
+value = (value %3C%3C bits) + (d & 0xFF);%0A                bitsLeft -= bits
 ;%0A  
@@ -1821,33 +1821,41 @@
                 
-%7D
+bits = 0;
 %0A            %7D%0A 

Improve getLong( performance