Created
September 9, 2015 19:00
-
-
Save ztellman/b1dfb60e73d5b210716b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package compression; | |
import java.lang.Exception; | |
import java.nio.ByteBuffer; | |
import java.nio.DoubleBuffer; | |
public class FPC { | |
// adapted from http://users.ices.utexas.edu/~burtscher/papers/tr08.pdf | |
private static final int PREDICT_TABLE_SIZE = 32768; | |
public static void compress(DoubleBuffer in, ByteBuffer out) { | |
int hash = 0, dhash = 0; | |
long val, prev = 0, pred1 = 0, pred2 = 0; | |
boolean even = true; | |
long[] fcm = new long[PREDICT_TABLE_SIZE]; | |
long[] dfcm = new long[PREDICT_TABLE_SIZE]; | |
int headerLength = (int) Math.ceil(in.remaining() / 2.0f); | |
out.position(headerLength); | |
int index = 0; | |
while (in.hasRemaining()) { | |
val = Double.doubleToRawLongBits(in.get()); | |
// direct predictor table | |
long xor1 = pred1 ^ val; | |
fcm[hash] = val; | |
hash = ((hash << 6) ^ (int)(val >>> 48)) & (PREDICT_TABLE_SIZE - 1); | |
pred1 = fcm[hash]; | |
// offset predictor table | |
long stride = val - prev; | |
long xor2 = (prev + pred2) ^ val; | |
dfcm[dhash] = stride; | |
dhash = ((dhash << 2) ^ (int)(stride >>> 40)) & (PREDICT_TABLE_SIZE - 1); | |
pred2 = dfcm[dhash]; | |
byte code = 0; | |
if (xor1 < 0 || xor1 > xor2) { | |
xor1 = xor2; | |
code = 0x8; | |
} | |
long xor = xor1; | |
byte bcode = 8; | |
for (int i = 0; i < 8; i++) { | |
if ((0xFF00000000000000L & xor) == 0) { | |
xor <<= 8; | |
bcode--; | |
} else { | |
break; | |
} | |
} | |
if (bcode > 4) bcode--; | |
if (even) { | |
code |= bcode; | |
out.put(index >> 1, code); | |
} else { | |
code = (byte)((code | bcode) << 4); | |
out.put(index >> 1, (byte)(code | out.get(index >> 1))); | |
} | |
int limit = bcode > 3 ? bcode + 1 : bcode; | |
for (int i = limit-1; i >= 0; i--) { | |
int offset = (i << 3); | |
long mask = 0xFFL << offset; | |
out.put((byte)((xor1 & mask) >> offset)); | |
} | |
prev = val; | |
index++; | |
even = !even; | |
} | |
} | |
public static void decompress(int length, ByteBuffer in, DoubleBuffer out) { | |
int hash = 0, dhash = 0; | |
long prev = 0, pred1 = 0, pred2 = 0; | |
long[] fcm = new long[PREDICT_TABLE_SIZE]; | |
long[] dfcm = new long[PREDICT_TABLE_SIZE]; | |
int headerLength = (int) Math.ceil(length / 2.0f); | |
in.position(headerLength); | |
boolean even = true; | |
for (int i = 0; i < length; i++) { | |
byte code = in.get(i >> 1); | |
if (!even) code >>= 4; | |
code &= 0xF; | |
boolean fcmPredictor = (code & 0x8) != 0x8; | |
byte bcode = (byte)(code & 0x7); | |
bcode = bcode > 3 ? (byte)(bcode + 1) : bcode; | |
long val = 0; | |
for (int j = 0; j < bcode; j++) { | |
val <<= 8; | |
val |= in.get() & 0xFF; | |
} | |
if (!fcmPredictor) { | |
pred1 = pred2; | |
} | |
val ^= pred1; | |
out.put(Double.longBitsToDouble(val)); | |
// standard predictor table | |
fcm[hash] = val; | |
hash = ((hash << 6) ^ (int)(val >>> 48)) & (PREDICT_TABLE_SIZE - 1); | |
pred1 = fcm[hash]; | |
// offset predictor table | |
long stride = val - prev; | |
dfcm[dhash] = stride; | |
dhash = ((dhash << 2) ^ (int)(stride >>> 40)) & (PREDICT_TABLE_SIZE - 1); | |
pred2 = val + dfcm[dhash]; | |
prev = val; | |
even = !even; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment