package org.yamcs.utils;
import java.nio.ByteBuffer;
/**
* Wrapper around a ByteBuffer that allows to write individual bits or group of bits
*
* All the writings/readings are performed to a temporary long which is stored into the backing ByteBuffer when it is "full"
*
* Don't forget to call flush after the last write, such that the long is written to the backing ByteBuffer
*
* @author nm
*
*/
public class BitWriter {
private int bitShift; //bit offset from the right inside the current int
final private ByteBuffer bb;
//we put all the bits in the b, when it is full we save it in the array a and increase the offset
private long b; //current element
/**
* Constructs a BitWriter around an existing ByteBuffer
*
* @param bb
*/
public BitWriter(ByteBuffer bb) {
this.bb = bb;
bitShift = 64;
b = 0;
}
/**
* write the least significant numBits of x into the BitBuffer
*
* Note that there is no check that the bits will actually fit into the ByteBuffer, they will be stored in the temporary field.
* A buffer overflow exception will happen when the temporary field is full and flushed to the buffer
*
* @param x
* @param numBits
*/
public void write(int x, int numBits) {
int k = numBits-bitShift;
if(k<0) {
doWrite(x, numBits);
} else {
doWrite(x>>k, bitShift);
if(k>0) {
bitShift = 64;
bb.putLong(b);
b = 0;
doWrite(x, k);
}
}
// System.out.println("bitShift: "+bitShift+" bb.position: "+bb.position()+" numBits: "+numBits);
}
//here we know that numBits<bitShift
private void doWrite(int x, int numBits) {
bitShift-=numBits;
long mask = (1L<<numBits) -1;
b |= ((x&mask) << bitShift);
}
/**
* flush the temporary long to the ByteBuffer
* do not call this method twice!!
*/
public void flush() {
if(bitShift!=64) {
bb.putLong(b);
}
}
}