brouter/brouter-util/src/main/java/btools/util/BitCoderContext.java
Phyks (Lucas Verney) 780e865870 Fix JavaDoc errors
2018-12-07 08:59:15 +01:00

264 lines
4.7 KiB
Java

package btools.util;
public class BitCoderContext
{
private byte[] ab;
private int idxMax;
private int idx = -1;
private int bm = 0x100; // byte mask (write mode)
private int bits; // bits left in buffer (read mode)
private int b;
public BitCoderContext( byte[] ab )
{
this.ab = ab;
idxMax = ab.length-1;
}
public final void reset( byte[] ab )
{
this.ab = ab;
idxMax = ab.length-1;
reset();
}
public final void reset()
{
idx = -1;
bm = 0x100;
bits = 0;
b = 0;
}
/**
* encode a distance with a variable bit length
* (poor mans huffman tree)
* {@code 1 -> 0}
* {@code 01 -> 1} + following 1-bit word ( 1..2 )
* {@code 001 -> 3} + following 2-bit word ( 3..6 )
* {@code 0001 -> 7} + following 3-bit word ( 7..14 ) etc.
*
* @see #decodeVarBits
*/
public final void encodeVarBits( int value )
{
int range = 0;
while (value > range)
{
encodeBit( false );
value -= range + 1;
range = 2 * range + 1;
}
encodeBit( true );
encodeBounded( range, value );
}
/**
* @see #encodeVarBits
*/
public final int decodeVarBits2()
{
int range = 0;
while (!decodeBit())
{
range = 2 * range + 1;
}
return range + decodeBounded( range );
}
public final int decodeVarBits()
{
int range = 1;
int cnt = 1;
fillBuffer();
if ( (b & 0xffffff ) == 0 )
{
return decodeVarBits2(); // fast version limited to 24 bit
}
while ((b & range) == 0)
{
range = (range << 1) | 1;
cnt++;
}
b >>>= cnt;
bits -= cnt;
return (range >>> 1) + ( cnt > 1 ? decodeBits( cnt-1 ) : 0 );
}
public final void encodeBit( boolean value )
{
if ( bm == 0x100 )
{
bm = 1;
ab[++idx] = 0;
}
if ( value )
ab[idx] |= bm;
bm <<= 1;
}
public final boolean decodeBit()
{
if ( bits == 0 )
{
bits = 8;
b = ab[++idx] & 0xff;
}
boolean value = ( ( b & 1 ) != 0 );
b >>>= 1;
bits--;
return value;
}
/**
* encode an integer in the range 0..max (inclusive).
* For max = 2^n-1, this just encodes n bits, but in general
* this is variable length encoding, with the shorter codes
* for the central value range
*/
public final void encodeBounded( int max, int value )
{
int im = 1; // integer mask
while (im <= max)
{
if ( bm == 0x100 )
{
bm = 1;
ab[++idx] = 0;
}
if ( ( value & im ) != 0 )
{
ab[idx] |= bm;
max -= im;
}
bm <<= 1;
im <<= 1;
}
}
/**
* decode an integer in the range 0..max (inclusive).
* @see #encodeBounded
*/
public final int decodeBounded( int max )
{
int value = 0;
int im = 1; // integer mask
while (( value | im ) <= max)
{
if ( bits == 0 )
{
bits = 8;
b = ab[++idx] & 0xff;
}
if ( ( b & 1 ) != 0 )
value |= im;
b >>>= 1;
bits--;
im <<= 1;
}
return value;
}
public final int decodeBits( int count )
{
if ( count == 0 )
{
return 0;
}
fillBuffer();
int mask = 0xffffffff >>> ( 32 - count );
int value = b & mask;
b >>>= count;
bits -= count;
return value;
}
private void fillBuffer()
{
while (bits < 24)
{
if ( idx < idxMax )
{
b |= (ab[++idx] & 0xff) << bits;
}
bits += 8;
}
}
/**
* @return the encoded length in bytes
*/
public final int getEncodedLength()
{
return idx + 1;
}
/**
* @return the encoded length in bits
*/
public final long getWritingBitPosition()
{
long bitpos = idx << 3;
int m = bm;
while (m > 1)
{
bitpos++;
m >>= 1;
}
return bitpos;
}
public final int getReadingBitPosition()
{
return (idx << 3) + 8 - bits;
}
public final void setReadingBitPosition(int pos)
{
idx = pos >>> 3;
bits = (idx << 3) + 8 - pos;
b = ab[idx] & 0xff;
b >>>= (8-bits);
}
public final void copyBitsTo( byte[] dst, int bitcount )
{
int dstIdx = 0;
for(;;)
{
if ( bitcount > 8 )
{
if ( bits < 8 )
{
b |= (ab[++idx] & 0xff) << bits;
}
else
{
bits -= 8;
}
dst[dstIdx++] = (byte)b;
b >>>= 8;
bitcount -= 8;
}
else
{
if ( bits < bitcount )
{
b |= (ab[++idx] & 0xff) << bits;
bits += 8;
}
int mask = 0xff >>> ( 8 - bitcount );
dst[dstIdx] = (byte)(b & mask);
bits -= bitcount;
b >>>= bitcount;
break;
}
}
}
}