private uint GetOptimum(uint position, out uint backRes) { OptimumReps reps = new OptimumReps(); P<uint> matches; uint numAvail; uint lenEnd; { if (mOptimumEndIndex != mOptimumCurrentIndex) { COptimal opt = mOpt[mOptimumCurrentIndex]; uint lenRes = opt.mPosPrev - mOptimumCurrentIndex; backRes = opt.mBackPrev; mOptimumCurrentIndex = opt.mPosPrev; return lenRes; } mOptimumCurrentIndex = 0; mOptimumEndIndex = 0; uint mainLen, numPairs; if (mAdditionalOffset == 0) { mainLen = ReadMatchDistances(out numPairs); } else { mainLen = mLongestMatchLength; numPairs = mNumPairs; } numAvail = mNumAvail; if (numAvail < 2) { backRes = ~0u; return 1; } if (numAvail > LZMA_MATCH_LEN_MAX) numAvail = LZMA_MATCH_LEN_MAX; P<byte> data = mMatchFinder.GetPointerToCurrentPos(mMatchFinderObj) - 1; OptimumReps repLens = new OptimumReps(); uint repMaxIndex = 0; for (uint i = 0; i < LZMA_NUM_REPS; i++) { reps[i] = mReps[i]; TR("GetOptimum:reps[i]", reps[i]); P<byte> data2 = data - (reps[i] + 1); if (data[0] != data2[0] || data[1] != data2[1]) { repLens[i] = 0; continue; } uint lenTest = 2; while (lenTest < numAvail && data[lenTest] == data2[lenTest]) lenTest++; repLens[i] = lenTest; if (lenTest > repLens[repMaxIndex]) repMaxIndex = i; } if (repLens[repMaxIndex] >= mNumFastBytes) { uint lenRes; backRes = repMaxIndex; lenRes = repLens[repMaxIndex]; MovePos(lenRes - 1); return lenRes; } matches = mMatches; if (mainLen >= mNumFastBytes) { backRes = matches[numPairs - 1] + LZMA_NUM_REPS; MovePos(mainLen - 1); return mainLen; } byte curByte = data[0]; byte matchByte = (data - (reps._0 + 1))[0]; if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2) { backRes = ~0u; return 1; } mOpt[0].mState = mState; uint posState = (position & mPbMask); { P<ushort> probs = LIT_PROBS(position, (data - 1)[0]); mOpt[1].mPrice = GET_PRICE_0(mIsMatch[mState][posState]) + (!IsCharState(mState) ? LitEnc_GetPriceMatched(probs, curByte, matchByte, mProbPrices) : LitEnc_GetPrice(probs, curByte, mProbPrices)); } mOpt[1].MakeAsChar(); uint matchPrice = GET_PRICE_1(mIsMatch[mState][posState]); uint repMatchPrice = matchPrice + GET_PRICE_1(mIsRep[mState]); if (matchByte == curByte) { uint shortRepPrice = repMatchPrice + GetRepLen1Price(mState, posState); if (shortRepPrice < mOpt[1].mPrice) { mOpt[1].mPrice = shortRepPrice; mOpt[1].MakeAsShortRep(); } } lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]); if (lenEnd < 2) { backRes = mOpt[1].mBackPrev; return 1; } mOpt[1].mPosPrev = 0; mOpt[0].mBacks = reps; uint len = lenEnd; do { mOpt[len--].mPrice = kInfinityPrice; } while (len >= 2); for (uint i = 0; i < LZMA_NUM_REPS; i++) { uint repLen = repLens[i]; if (repLen < 2) continue; uint price = repMatchPrice + GetPureRepPrice(i, mState, posState); do { uint curAndLenPrice = price + mRepLenEnc.mPrices[posState][repLen - 2]; COptimal opt = mOpt[repLen]; if (curAndLenPrice < opt.mPrice) { opt.mPrice = curAndLenPrice; opt.mPosPrev = 0; opt.mBackPrev = i; opt.mPrev1IsChar = false; } } while (--repLen >= 2); } uint normalMatchPrice = matchPrice + GET_PRICE_0(mIsRep[mState]); len = ((repLens._0 >= 2) ? repLens._0 + 1 : 2); if (len <= mainLen) { uint offs = 0; while (len > matches[offs]) offs += 2; for (; ; len++) { uint distance = matches[offs + 1]; uint curAndLenPrice = normalMatchPrice + mLenEnc.mPrices[posState][len - LZMA_MATCH_LEN_MIN]; uint lenToPosState = GetLenToPosState(len); if (distance < kNumFullDistances) { curAndLenPrice += mDistancesPrices[lenToPosState][distance]; } else { uint slot = GetPosSlot2(distance); curAndLenPrice += mAlignPrices[distance & kAlignMask] + mPosSlotPrices[lenToPosState][slot]; } COptimal opt = mOpt[len]; if (curAndLenPrice < opt.mPrice) { opt.mPrice = curAndLenPrice; opt.mPosPrev = 0; opt.mBackPrev = distance + LZMA_NUM_REPS; opt.mPrev1IsChar = false; } if (len == matches[offs]) { offs += 2; if (offs == numPairs) break; } } } } uint cur = 0; #if SHOW_STAT2 if(position >= 0) { Print("\n pos = {0:X4}", position); for(uint j = cur; j <= lenEnd; j++) Print("\nprice[{0:X4}] = {1}", position - cur + j, mOpt[j].mPrice); } #endif //TR("GetOptimum::pos", position); //if(position >= 0) //{ // TR("GetOptimum::cur", cur); // for(uint j = cur; j <= lenEnd; j++) // TR("GetOptimum::price[i]", mOpt[j].price); //} for (;;) { cur++; if (cur == lenEnd) return Backward(out backRes, cur); uint numPairs; uint newLen = ReadMatchDistances(out numPairs); if (newLen >= mNumFastBytes) { mNumPairs = numPairs; mLongestMatchLength = newLen; return Backward(out backRes, cur); } position++; uint state; COptimal curOpt = mOpt[cur]; uint posPrev = curOpt.mPosPrev; if (curOpt.mPrev1IsChar) { posPrev--; if (curOpt.mPrev2) { state = mOpt[curOpt.mPosPrev2].mState; if (curOpt.mBackPrev2 < LZMA_NUM_REPS) state = kRepNextStates[state]; else state = kMatchNextStates[state]; } else { state = mOpt[posPrev].mState; } state = kLiteralNextStates[state]; } else { state = mOpt[posPrev].mState; } if (posPrev == cur - 1) { if (curOpt.IsShortRep()) state = kShortRepNextStates[state]; else state = kLiteralNextStates[state]; } else { uint pos; if (curOpt.mPrev1IsChar && curOpt.mPrev2) { posPrev = curOpt.mPosPrev2; pos = curOpt.mBackPrev2; state = kRepNextStates[state]; } else { pos = curOpt.mBackPrev; if (pos < LZMA_NUM_REPS) state = kRepNextStates[state]; else state = kMatchNextStates[state]; } COptimal prevOpt = mOpt[posPrev]; if (pos < LZMA_NUM_REPS) { reps._0 = prevOpt.mBacks[pos]; uint i = 1; for (; i <= pos; i++) reps[i] = prevOpt.mBacks[i - 1]; for (; i < LZMA_NUM_REPS; i++) reps[i] = prevOpt.mBacks[i]; } else { reps._0 = pos - LZMA_NUM_REPS; reps._1 = prevOpt.mBacks._0; reps._2 = prevOpt.mBacks._1; reps._3 = prevOpt.mBacks._2; } } curOpt.mState = state; curOpt.mBacks = reps; uint curPrice = curOpt.mPrice; bool nextIsChar = false; P<byte> data = mMatchFinder.GetPointerToCurrentPos(mMatchFinderObj) - 1; byte curByte = data[0]; byte matchByte = (data - (reps._0 + 1))[0]; uint posState = (position & mPbMask); uint curAnd1Price = curPrice + GET_PRICE_0(mIsMatch[state][posState]); { P<ushort> probs = LIT_PROBS(position, data[-1]); if (!IsCharState(state)) curAnd1Price += LitEnc_GetPriceMatched(probs, curByte, matchByte, mProbPrices); else curAnd1Price += LitEnc_GetPrice(probs, curByte, mProbPrices); } COptimal nextOpt = mOpt[cur + 1]; if (curAnd1Price < nextOpt.mPrice) { nextOpt.mPrice = curAnd1Price; nextOpt.mPosPrev = cur; nextOpt.MakeAsChar(); nextIsChar = true; } uint matchPrice = curPrice + GET_PRICE_1(mIsMatch[state][posState]); uint repMatchPrice = matchPrice + GET_PRICE_1(mIsRep[state]); if (matchByte == curByte && !(nextOpt.mPosPrev < cur && nextOpt.mBackPrev == 0)) { uint shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState); if (shortRepPrice <= nextOpt.mPrice) { nextOpt.mPrice = shortRepPrice; nextOpt.mPosPrev = cur; nextOpt.MakeAsShortRep(); nextIsChar = true; } } uint numAvailFull = Math.Min(mNumAvail, kNumOpts - 1 - cur); if (numAvailFull < 2) continue; numAvail = (numAvailFull <= mNumFastBytes ? numAvailFull : mNumFastBytes); if (!nextIsChar && matchByte != curByte) /* speed optimization */ { /* try Literal + rep0 */ P<byte> data2 = data - (reps._0 + 1); uint limit = mNumFastBytes + 1; if (limit > numAvailFull) limit = numAvailFull; uint temp = 1; while (temp < limit && data[temp] == data2[temp]) temp++; uint lenTest2 = temp - 1; if (lenTest2 >= 2) { uint state2 = kLiteralNextStates[state]; uint posStateNext = (position + 1) & mPbMask; uint nextRepMatchPrice = curAnd1Price + GET_PRICE_1(mIsMatch[state2][posStateNext]) + GET_PRICE_1(mIsRep[state2]); /* for (; lenTest2 >= 2; lenTest2--) */ { uint offset = cur + 1 + lenTest2; while (lenEnd < offset) mOpt[++lenEnd].mPrice = kInfinityPrice; uint curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext); COptimal opt = mOpt[offset]; if (curAndLenPrice < opt.mPrice) { opt.mPrice = curAndLenPrice; opt.mPosPrev = cur + 1; opt.mBackPrev = 0; opt.mPrev1IsChar = true; opt.mPrev2 = false; } } } } uint startLen = 2; /* speed optimization */ for (uint repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++) { P<byte> data2 = data - (reps[repIndex] + 1); if (data[0] != data2[0] || data[1] != data2[1]) continue; uint lenTest = 2; while (lenTest < numAvail && data[lenTest] == data2[lenTest]) lenTest++; while (lenEnd < cur + lenTest) mOpt[++lenEnd].mPrice = kInfinityPrice; uint lenTestTemp = lenTest; uint price = repMatchPrice + GetPureRepPrice(repIndex, state, posState); do { uint curAndLenPrice = price + mRepLenEnc.mPrices[posState][lenTest - 2]; COptimal opt = mOpt[cur + lenTest]; if (curAndLenPrice < opt.mPrice) { opt.mPrice = curAndLenPrice; opt.mPosPrev = cur; opt.mBackPrev = repIndex; opt.mPrev1IsChar = false; } } while (--lenTest >= 2); lenTest = lenTestTemp; if (repIndex == 0) startLen = lenTest + 1; { uint lenTest2 = lenTest + 1; uint limit = lenTest2 + mNumFastBytes; if (limit > numAvailFull) limit = numAvailFull; while (lenTest2 < limit && data[lenTest2] == data2[lenTest2]) lenTest2++; lenTest2 -= lenTest + 1; if (lenTest2 >= 2) { uint state2 = kRepNextStates[state]; uint posStateNext = (position + lenTest) & mPbMask; uint curAndLenCharPrice = price + mRepLenEnc.mPrices[posState][lenTest - 2] + GET_PRICE_0(mIsMatch[state2][posStateNext]) + LitEnc_GetPriceMatched( LIT_PROBS(position + lenTest, data[lenTest - 1]), data[lenTest], data2[lenTest], mProbPrices); state2 = kLiteralNextStates[state2]; posStateNext = (position + lenTest + 1) & mPbMask; uint nextRepMatchPrice = curAndLenCharPrice + GET_PRICE_1(mIsMatch[state2][posStateNext]) + GET_PRICE_1(mIsRep[state2]); /* for (; lenTest2 >= 2; lenTest2--) */ { uint offset = cur + lenTest + 1 + lenTest2; while (lenEnd < offset) mOpt[++lenEnd].mPrice = kInfinityPrice; uint curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext); COptimal opt = mOpt[offset]; if (curAndLenPrice < opt.mPrice) { opt.mPrice = curAndLenPrice; opt.mPosPrev = cur + lenTest + 1; opt.mBackPrev = 0; opt.mPrev1IsChar = true; opt.mPrev2 = true; opt.mPosPrev2 = cur; opt.mBackPrev2 = repIndex; } } } } } /* for (uint lenTest = 2; lenTest <= newLen; lenTest++) */ if (newLen > numAvail) { newLen = numAvail; numPairs = 0; while (newLen > matches[numPairs]) numPairs += 2; matches[numPairs] = newLen; numPairs += 2; } if (newLen >= startLen) { uint normalMatchPrice = matchPrice + GET_PRICE_0(mIsRep[state]); while (lenEnd < cur + newLen) mOpt[++lenEnd].mPrice = kInfinityPrice; uint offs = 0; while (startLen > matches[offs]) offs += 2; uint curBack = matches[offs + 1]; uint posSlot = GetPosSlot2(curBack); for (uint lenTest = /*2*/ startLen; ; lenTest++) { uint curAndLenPrice = normalMatchPrice + mLenEnc.mPrices[posState][lenTest - LZMA_MATCH_LEN_MIN]; uint lenToPosState = GetLenToPosState(lenTest); if (curBack < kNumFullDistances) curAndLenPrice += mDistancesPrices[lenToPosState][curBack]; else curAndLenPrice += mPosSlotPrices[lenToPosState][posSlot] + mAlignPrices[curBack & kAlignMask]; COptimal opt = mOpt[cur + lenTest]; if (curAndLenPrice < opt.mPrice) { opt.mPrice = curAndLenPrice; opt.mPosPrev = cur; opt.mBackPrev = curBack + LZMA_NUM_REPS; opt.mPrev1IsChar = false; } if (lenTest == matches[offs]) { /* Try Match + Literal + Rep0 */ P<byte> data2 = data - (curBack + 1); uint lenTest2 = lenTest + 1; uint limit = lenTest2 + mNumFastBytes; uint nextRepMatchPrice; if (limit > numAvailFull) limit = numAvailFull; while (lenTest2 < limit && data[lenTest2] == data2[lenTest2]) lenTest2++; lenTest2 -= lenTest + 1; if (lenTest2 >= 2) { uint state2 = kMatchNextStates[state]; uint posStateNext = (position + lenTest) & mPbMask; uint curAndLenCharPrice = curAndLenPrice + GET_PRICE_0(mIsMatch[state2][posStateNext]) + LitEnc_GetPriceMatched( LIT_PROBS(position + lenTest, data[lenTest - 1]), data[lenTest], data2[lenTest], mProbPrices); state2 = kLiteralNextStates[state2]; posStateNext = (posStateNext + 1) & mPbMask; nextRepMatchPrice = curAndLenCharPrice + GET_PRICE_1(mIsMatch[state2][posStateNext]) + GET_PRICE_1(mIsRep[state2]); /* for (; lenTest2 >= 2; lenTest2--) */ { uint offset = cur + lenTest + 1 + lenTest2; uint curAndLenPrice4; while (lenEnd < offset) mOpt[++lenEnd].mPrice = kInfinityPrice; curAndLenPrice4 = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext); COptimal opt4 = mOpt[offset]; if (curAndLenPrice4 < opt4.mPrice) { opt4.mPrice = curAndLenPrice4; opt4.mPosPrev = cur + lenTest + 1; opt4.mBackPrev = 0; opt4.mPrev1IsChar = true; opt4.mPrev2 = true; opt4.mPosPrev2 = cur; opt4.mBackPrev2 = curBack + LZMA_NUM_REPS; } } } offs += 2; if (offs == numPairs) break; curBack = matches[offs + 1]; if (curBack >= kNumFullDistances) posSlot = GetPosSlot2(curBack); } } } } }
internal void LzmaEnc_Init() { TR("LzmaEnc_Init", 0); mState = 0; mReps = new OptimumReps(); mRC.RangeEnc_Init(); for (uint i = 0; i < kNumStates; i++) { for (uint j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) { mIsMatch[i][j] = kProbInitValue; mIsRep0Long[i][j] = kProbInitValue; } mIsRep[i] = kProbInitValue; mIsRepG0[i] = kProbInitValue; mIsRepG1[i] = kProbInitValue; mIsRepG2[i] = kProbInitValue; } uint n = 0x300u << (mLP + mLC); for (uint i = 0; i < n; i++) mLitProbs[i] = kProbInitValue; for (uint i = 0; i < kNumLenToPosStates; i++) { P<ushort> probs = mPosSlotEncoder[i]; for (uint j = 0; j < (1 << kNumPosSlotBits); j++) probs[j] = kProbInitValue; } for (uint i = 0; i < kNumFullDistances - kEndPosModelIndex; i++) mPosEncoders[i] = kProbInitValue; mLenEnc.LenEnc_Init(); mRepLenEnc.LenEnc_Init(); for (uint i = 0; i < (1 << kNumAlignBits); i++) mPosAlignEncoder[i] = kProbInitValue; mOptimumEndIndex = 0; mOptimumCurrentIndex = 0; mAdditionalOffset = 0; mPbMask = (1u << mPB) - 1; mLpMask = (1u << mLP) - 1; }
internal void LzmaEnc_RestoreState() { TR("LzmaEnc_RestoreState", 0); mLenEnc = new CLenPriceEnc(mSaveState.mLenEnc); mRepLenEnc = new CLenPriceEnc(mSaveState.mRepLenEnc); mState = mSaveState.mState; for (int i = 0; i < kNumStates; i++) { memcpy(mIsMatch[i], mSaveState.mIsMatch[i], LZMA_NUM_PB_STATES_MAX * 2); memcpy(mIsRep0Long[i], mSaveState.mIsRep0Long[i], LZMA_NUM_PB_STATES_MAX * 2); } for (int i = 0; i < kNumLenToPosStates; i++) memcpy(mPosSlotEncoder[i], mSaveState.mPosSlotEncoder[i], (1 << kNumPosSlotBits) * 2); memcpy(mIsRep, mSaveState.mIsRep, kNumStates * 2); memcpy(mIsRepG0, mSaveState.mIsRepG0, kNumStates * 2); memcpy(mIsRepG1, mSaveState.mIsRepG1, kNumStates * 2); memcpy(mIsRepG2, mSaveState.mIsRepG2, kNumStates * 2); memcpy(mPosEncoders, mSaveState.mPosEncoders, (kNumFullDistances - kEndPosModelIndex) * 2); memcpy(mPosAlignEncoder, mSaveState.mPosAlignEncoder, (1 << kNumAlignBits) * 2); mReps = mSaveState.mReps; memcpy(mLitProbs, mSaveState.mLitProbs, (0x300 << mLcLp) * 2); }