/** * DataOutputStream for fast-compact encoding of number sequences * * @author ab */ package btools.util; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; public final class MixCoderDataOutputStream extends DataOutputStream { private int lastValue; private int lastLastValue; private int repCount; private int diffshift; private int bm = 1; // byte mask (write mode) private int b = 0; public static int[] diffs = new int[100]; public static int[] counts = new int[100]; public MixCoderDataOutputStream( OutputStream os ) { super( os ); } public void writeMixed( int v ) throws IOException { if ( v != lastValue && repCount > 0 ) { int d = lastValue - lastLastValue; lastLastValue = lastValue; encodeBit( d < 0 ); if ( d < 0 ) { d = -d; } encodeVarBits( d-diffshift ); encodeVarBits( repCount-1 ); if ( d < 100 ) diffs[d]++; if ( repCount < 100 ) counts[repCount]++; diffshift = 1; repCount = 0; } lastValue = v; repCount++; } @Override public void flush() throws IOException { int v = lastValue; writeMixed( v+1 ); lastValue = v; repCount = 0; if ( bm > 1 ) { writeByte( (byte)b ); // flush bit-coding } } public final void encodeBit( boolean value ) throws IOException { if ( bm == 0x100 ) { writeByte( (byte)b ); bm = 1; b = 0; } if ( value ) { b |= bm; } bm <<= 1; } public final void encodeVarBits( int value ) throws IOException { int range = 0; while (value > range) { encodeBit( false ); value -= range + 1; range = 2 * range + 1; } encodeBit( true ); encodeBounded( range, value ); } public final void encodeBounded( int max, int value ) throws IOException { int im = 1; // integer mask while (im <= max) { if ( bm == 0x100 ) { writeByte( (byte)b ); bm = 1; b = 0; } if ( ( value & im ) != 0 ) { b |= bm; max -= im; } bm <<= 1; im <<= 1; } } public static void stats() { for(int i=1; i<100;i++) System.out.println( "diff[" + i + "] = " + diffs[i] ); for(int i=1; i<100;i++) System.out.println( "counts[" + i + "] = " + counts[i] ); } }