in src/main/java/org/apache/commons/compress/harmony/pack200/BandSet.java [516:667]
private void encodeWithPopulationCodec(final int[] band, final BHSDCodec defaultCodec, final BandData bandData, final BandAnalysisResults results)
throws Pack200Exception {
results.numCodecsTried += 3; // quite a bit more effort to try this codec
final Map<Integer, Integer> distinctValues = bandData.distinctValues;
final List<Integer> favored = new ArrayList<>();
distinctValues.forEach((k, v) -> {
if (v.intValue() > 2 || distinctValues.size() < 256) { // TODO: tweak
favored.add(k);
}
});
// Sort the favored list with the most commonly occurring first
if (distinctValues.size() > 255) {
favored.sort((arg0, arg1) -> distinctValues.get(arg1).compareTo(distinctValues.get(arg0)));
}
final Map<Integer, Integer> favoredToIndex = new HashMap<>();
for (int i = 0; i < favored.size(); i++) {
favoredToIndex.put(favored.get(i), Integer.valueOf(i));
}
final IntList unfavoured = new IntList();
final int[] tokens = new int[band.length];
for (int i = 0; i < band.length; i++) {
final Integer favouredIndex = favoredToIndex.get(Integer.valueOf(band[i]));
if (favouredIndex == null) {
tokens[i] = 0;
unfavoured.add(band[i]);
} else {
tokens[i] = favouredIndex.intValue() + 1;
}
}
favored.add(favored.get(favored.size() - 1)); // repeat last value
final int[] favouredBand = integerListToArray(favored);
final int[] unfavouredBand = unfavoured.toArray();
// Analyse the three bands to get the best codec
final BandAnalysisResults favouredResults = analyseBand("POPULATION", favouredBand, defaultCodec);
final BandAnalysisResults unfavouredResults = analyseBand("POPULATION", unfavouredBand, defaultCodec);
int tdefL = 0;
int l = 0;
Codec tokenCodec = null;
final byte[] tokensEncoded;
final int k = favored.size() - 1;
if (k < 256) {
tdefL = 1;
tokensEncoded = Codec.BYTE1.encode(tokens);
} else {
final BandAnalysisResults tokenResults = analyseBand("POPULATION", tokens, defaultCodec);
tokenCodec = tokenResults.betterCodec;
tokensEncoded = tokenResults.encodedBand;
if (tokenCodec == null) {
tokenCodec = defaultCodec;
}
l = ((BHSDCodec) tokenCodec).getL();
final int h = ((BHSDCodec) tokenCodec).getH();
final int s = ((BHSDCodec) tokenCodec).getS();
final int b = ((BHSDCodec) tokenCodec).getB();
final int d = ((BHSDCodec) tokenCodec).isDelta() ? 1 : 0;
if (s == 0 && d == 0) {
boolean canUseTDefL = true;
if (b > 1) {
final BHSDCodec oneLowerB = new BHSDCodec(b - 1, h);
if (oneLowerB.largest() >= k) {
canUseTDefL = false;
}
}
if (canUseTDefL) {
switch (l) {
case 4:
tdefL = 1;
break;
case 8:
tdefL = 2;
break;
case 16:
tdefL = 3;
break;
case 32:
tdefL = 4;
break;
case 64:
tdefL = 5;
break;
case 128:
tdefL = 6;
break;
case 192:
tdefL = 7;
break;
case 224:
tdefL = 8;
break;
case 240:
tdefL = 9;
break;
case 248:
tdefL = 10;
break;
case 252:
tdefL = 11;
break;
}
}
}
}
final byte[] favouredEncoded = favouredResults.encodedBand;
final byte[] unfavouredEncoded = unfavouredResults.encodedBand;
final Codec favouredCodec = favouredResults.betterCodec;
final Codec unfavouredCodec = unfavouredResults.betterCodec;
int specifier = 141 + (favouredCodec == null ? 1 : 0) + 4 * tdefL + (unfavouredCodec == null ? 2 : 0);
final IntList extraBandMetadata = new IntList(3);
if (favouredCodec != null) {
IntStream.of(CodecEncoding.getSpecifier(favouredCodec, null)).forEach(extraBandMetadata::add);
}
if (tdefL == 0) {
IntStream.of(CodecEncoding.getSpecifier(tokenCodec, null)).forEach(extraBandMetadata::add);
}
if (unfavouredCodec != null) {
IntStream.of(CodecEncoding.getSpecifier(unfavouredCodec, null)).forEach(extraBandMetadata::add);
}
final int[] extraMetadata = extraBandMetadata.toArray();
final byte[] extraMetadataEncoded = Codec.UNSIGNED5.encode(extraMetadata);
if (defaultCodec.isSigned()) {
specifier = -1 - specifier;
} else {
specifier += defaultCodec.getL();
}
final byte[] firstValueEncoded = defaultCodec.encode(new int[] { specifier });
final int totalBandLength = firstValueEncoded.length + favouredEncoded.length + tokensEncoded.length + unfavouredEncoded.length;
if (totalBandLength + extraMetadataEncoded.length < results.encodedBand.length) {
results.saved += results.encodedBand.length - (totalBandLength + extraMetadataEncoded.length);
final byte[] encodedBand = new byte[totalBandLength];
System.arraycopy(firstValueEncoded, 0, encodedBand, 0, firstValueEncoded.length);
System.arraycopy(favouredEncoded, 0, encodedBand, firstValueEncoded.length, favouredEncoded.length);
System.arraycopy(tokensEncoded, 0, encodedBand, firstValueEncoded.length + favouredEncoded.length, tokensEncoded.length);
System.arraycopy(unfavouredEncoded, 0, encodedBand, firstValueEncoded.length + favouredEncoded.length + tokensEncoded.length,
unfavouredEncoded.length);
results.encodedBand = encodedBand;
results.extraMetadata = extraMetadata;
if (l != 0) {
results.betterCodec = new PopulationCodec(favouredCodec, l, unfavouredCodec);
} else {
results.betterCodec = new PopulationCodec(favouredCodec, tokenCodec, unfavouredCodec);
}
}
}