/** * 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]); } }