private int makeCopyDecision(int index, int[] bestDist) { int[] dist1 = new int[1]; int[] gain1 = new int[1]; int[] costPerByte1 = new int[1]; int here = index; int len1 = findMatch(index, dist1, gain1, costPerByte1); updateModel(index++); if (gain1[0] > 0) { int[] dist2 = new int[1]; int[] gain2 = new int[1]; int[] costPerByte2 = new int[1]; int len2 = findMatch(index, dist2, gain2, costPerByte2); int symbolCost = symEncoder.writeSymbolCost(buf[here] & 0xff); if (gain2[0] >= gain1[0] && costPerByte1[0] > (costPerByte2[0] * len2 + symbolCost) / (len2 + 1)) { len1 = 0; } else if (len1 > 3) { len2 = findMatch(here + len1, dist2, gain2, costPerByte2); if (len2 >= 2) { int[] dist3 = new int[1]; int[] gain3 = new int[1]; int[] costPerByte3 = new int[1]; int len3 = findMatch(here + len1 - 1, dist3, gain3, costPerByte3); if (len3 > len2 && costPerByte3[0] < costPerByte2[0]) { int distRanges = getNumDistRanges(dist1[0] + 1); int lenBitCount = encodeLengthCost(len1 - 1, dist1[0] + 1, distRanges); int distBitCount = encodeDistance2Cost(dist1[0] + 1, distRanges); int cost1B = lenBitCount + distBitCount + costPerByte3[0] * len3; int cost1A = costPerByte1[0] * len1 + costPerByte2[0] * len2; if ((cost1A / (len1 + len2)) > (cost1B / (len1 - 1 + len3))) { len1--; dist1[0]++; } } } } if (len1 == 2) { if (here >= 2 && buf[here] == buf[here - 2]) { int dup2Cost = symEncoder.writeSymbolCost(dup2); if (costPerByte1[0] * 2 > dup2Cost + symEncoder.writeSymbolCost(buf[here + 1] & 0xff)) { len1 = 0; } } else if (here >= 1 && here + 1 < buf.length && buf[here + 1] == buf[here - 1]) { int dup2Cost = symEncoder.writeSymbolCost(dup2); if (costPerByte1[0] * 2 > symbolCost + dup2Cost) { len1 = 0; } } } } bestDist[0] = dist1[0]; return len1; }
private int encodeDistance2Cost(int value, int distRanges) { int cost = 0; value -= DIST_MIN; final int mask = (1 << DIST_WIDTH) - 1; for (int i = (distRanges - 1) * DIST_WIDTH; i >= 0; i -= DIST_WIDTH) { cost += distEncoder.writeSymbolCost((value >> i) & mask); } return cost; }
private int encodeLengthCost(int value, int dist, int numDistRanges) { if (dist >= MAX_2BYTE_DIST) { value -= LEN_MIN3; } else { value -= LEN_MIN; } int bitsUsed = HuffmanEncoder.bitsUsed(value); int i = BIT_RANGE; while (i < bitsUsed) { i += BIT_RANGE; } int mask = 1 << (i - 1); int symbol = bitsUsed > BIT_RANGE ? 2 : 0; if ((value & mask) != 0) { symbol |= 1; } mask >>= 1; symbol <<= 1; if ((value & mask) != 0) { symbol |= 1; } mask >>= 1; int cost = symEncoder.writeSymbolCost(256 + symbol + (numDistRanges - 1) * (1 << LEN_WIDTH)); for (i = bitsUsed - BIT_RANGE; i >= 1; i -= BIT_RANGE) { symbol = i > BIT_RANGE ? 2 : 0; if ((value & mask) != 0) { symbol |= 1; } mask >>= 1; symbol <<= 1; if ((value & mask) != 0) { symbol |= 1; } mask >>= 1; cost += lenEncoder.writeSymbolCost(symbol); } return cost; }
// consider refactoring signature to return PotentialMatch object with fields set... int findMatch(int index, int[] distOut, int[] gainOut, int[] costPerByteOut) { final int maxCostCacheLength = 32; int[] literalCostCache = new int[maxCostCacheLength + 1]; int maxIndexMinusIndex = buf.length - index; int bestLength = 0; int bestDist = 0; int bestGain = 0; int bestCopyCost = 0; int maxComputedLength = 0; if (maxIndexMinusIndex > 1) { int pos = ((buf[index] & 0xff) << 8) | (buf[index + 1] & 0xff); HashNode prevNode = null; int hNodeCount = 0; for (HashNode hNode = hashTable[pos]; hNode != null; prevNode = hNode, hNode = hNode.next) { int i = hNode.index; int dist = index - i; hNodeCount++; if (hNodeCount > 256 || dist > maxCopyDist) { if (hashTable[pos] == hNode) { hashTable[pos] = null; } else { prevNode.next = null; } break; } int maxLen = index - i; if (maxIndexMinusIndex < maxLen) { maxLen = maxIndexMinusIndex; } if (maxLen < LEN_MIN) { continue; } i += 2; int length = 2; for (length = 2; length < maxLen && buf[i] == buf[index + length]; length++) { i++; } if (length < LEN_MIN) { continue; } dist = dist - length + 1; if (dist > distMax || (length == 2 && dist >= MAX_2BYTE_DIST)) { continue; } if (length <= bestLength && dist > bestDist) { if (length <= bestLength - 2) { continue; } if (dist > (bestDist << DIST_WIDTH)) { if (length < bestLength || dist > (bestDist << (DIST_WIDTH + 1))) { continue; } } } int literalCost = 0; if (length > maxComputedLength) { int limit = length; if (limit > maxCostCacheLength) limit = maxCostCacheLength; for (i = maxComputedLength; i < limit; i++) { byte c = buf[index + i]; literalCostCache[i + 1] = literalCostCache[i] + symEncoder.writeSymbolCost(c & 0xff); } maxComputedLength = limit; if (length > maxCostCacheLength) { literalCost = literalCostCache[maxCostCacheLength]; literalCost += literalCost / maxCostCacheLength * (length - maxCostCacheLength); } else { literalCost = literalCostCache[length]; } } else { literalCost = literalCostCache[length]; } if (literalCost > bestGain) { int distRanges = getNumDistRanges(dist); int copyCost = encodeLengthCost(length, dist, distRanges); if (literalCost - copyCost - (distRanges << 16) > bestGain) { copyCost += encodeDistance2Cost(dist, distRanges); int gain = literalCost - copyCost; if (gain > bestGain) { bestGain = gain; bestLength = length; bestDist = dist; bestCopyCost = copyCost; } } } } } costPerByteOut[0] = bestLength > 0 ? bestCopyCost / bestLength : 0; distOut[0] = bestDist; gainOut[0] = bestGain; return bestLength; }