brouter/brouter-util/src/main/java/btools/util/MixCoderDataOutputStream.java

107 lines
2.2 KiB
Java

/**
* 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 void encodeBit(boolean value) throws IOException {
if (bm == 0x100) {
writeByte((byte) b);
bm = 1;
b = 0;
}
if (value) {
b |= bm;
}
bm <<= 1;
}
public 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 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]);
}
}