3 #ifndef __LZMA_ENCODER_H
4 #define __LZMA_ENCODER_H
6 #include "../../../Common/MyCom.h"
7 #include "../../ICoder.h"
11 #include "../../../../C/Alloc.h"
12 #include "../../../../C/Compress/Lz/MatchFinder.h"
14 #include "../../../../C/Compress/Lz/MatchFinderMt.h"
18 #include "../RangeCoder/RangeCoderBitTree.h"
25 typedef NRangeCoder::CBitEncoder<kNumMoveBits> CMyBitEncoder;
32 UInt32 _repDistances[kNumRepDistances];
37 for(UInt32 i = 0 ; i < kNumRepDistances; i++)
53 UInt32 PosPrev; // posNext;
55 UInt32 Backs[kNumRepDistances];
56 void MakeAsChar() { BackPrev = UInt32(-1); Prev1IsChar = false; }
57 void MakeAsShortRep() { BackPrev = 0; ; Prev1IsChar = false; }
58 bool IsShortRep() { return (BackPrev == 0); }
62 // #define LZMA_LOG_BRANCH
65 // Must give gain in core 2. but slower ~2% on k8.
66 // #define LZMA_LOG_BSR
70 static const int kNumLogBits = 13; // don't change it !
71 extern Byte g_FastPos[];
73 inline UInt32 GetPosSlot(UInt32 pos)
79 _BitScanReverse(&index, pos);
80 return (index + index) + ((pos >> (index - 1)) & 1);
82 if (pos < (1 << kNumLogBits))
83 return g_FastPos[pos];
84 if (pos < (1 << (kNumLogBits * 2 - 1)))
85 return g_FastPos[pos >> (kNumLogBits - 1)] + (kNumLogBits - 1) * 2;
86 return g_FastPos[pos >> (kNumLogBits - 1) * 2] + (kNumLogBits - 1) * 4;
90 inline UInt32 GetPosSlot2(UInt32 pos)
94 _BitScanReverse(&index, pos);
95 return (index + index) + ((pos >> (index - 1)) & 1);
97 #ifdef LZMA_LOG_BRANCH
98 if (pos < (1 << (kNumLogBits + 6)))
99 return g_FastPos[pos >> 6] + 12;
100 if (pos < (1 << (kNumLogBits * 2 + 5)))
101 return g_FastPos[pos >> (kNumLogBits + 5)] + (kNumLogBits + 5) * 2;
102 return g_FastPos[pos >> (kNumLogBits * 2 + 4)] + (kNumLogBits * 2 + 4) * 2;
104 // it's faster with VC6-32bit.
105 UInt32 s = 6 + ((kNumLogBits - 1) & (UInt32)((Int32)(((1 << (kNumLogBits + 6)) - 1) - pos) >> 31));
106 return g_FastPos[pos >> s] + (s * 2);
111 const UInt32 kIfinityPrice = 0xFFFFFFF;
113 const UInt32 kNumOpts = 1 << 12;
116 class CLiteralEncoder2
118 CMyBitEncoder _encoders[0x300];
122 for (int i = 0; i < 0x300; i++)
125 void Encode(NRangeCoder::CEncoder *rangeEncoder, Byte symbol);
126 void EncodeMatched(NRangeCoder::CEncoder *rangeEncoder, Byte matchByte, Byte symbol);
127 UInt32 GetPrice(bool matchMode, Byte matchByte, Byte symbol) const;
130 class CLiteralEncoder
132 CLiteralEncoder2 *_coders;
137 CLiteralEncoder(): _coders(0) {}
138 ~CLiteralEncoder() { Free(); }
144 bool Create(int numPosBits, int numPrevBits)
146 if (_coders == 0 || (numPosBits + numPrevBits) != (_numPrevBits + _numPosBits))
149 UInt32 numStates = 1 << (numPosBits + numPrevBits);
150 _coders = (CLiteralEncoder2 *)MyAlloc(numStates * sizeof(CLiteralEncoder2));
152 _numPosBits = numPosBits;
153 _posMask = (1 << numPosBits) - 1;
154 _numPrevBits = numPrevBits;
155 return (_coders != 0);
159 UInt32 numStates = 1 << (_numPrevBits + _numPosBits);
160 for (UInt32 i = 0; i < numStates; i++)
163 CLiteralEncoder2 *GetSubCoder(UInt32 pos, Byte prevByte)
164 { return &_coders[((pos & _posMask) << _numPrevBits) + (prevByte >> (8 - _numPrevBits))]; }
171 CMyBitEncoder _choice;
172 CMyBitEncoder _choice2;
173 NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumLowBits> _lowCoder[kNumPosStatesEncodingMax];
174 NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumMidBits> _midCoder[kNumPosStatesEncodingMax];
175 NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumHighBits> _highCoder;
177 void Init(UInt32 numPosStates);
178 void Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 symbol, UInt32 posState);
179 void SetPrices(UInt32 posState, UInt32 numSymbols, UInt32 *prices) const;
182 const UInt32 kNumSpecSymbols = kNumLowSymbols + kNumMidSymbols;
184 class CPriceTableEncoder: public CEncoder
186 UInt32 _prices[kNumPosStatesEncodingMax][kNumSymbolsTotal];
188 UInt32 _counters[kNumPosStatesEncodingMax];
190 void SetTableSize(UInt32 tableSize) { _tableSize = tableSize; }
191 UInt32 GetPrice(UInt32 symbol, UInt32 posState) const { return _prices[posState][symbol]; }
192 void UpdateTable(UInt32 posState)
194 SetPrices(posState, _tableSize, _prices[posState]);
195 _counters[posState] = _tableSize;
197 void UpdateTables(UInt32 numPosStates)
199 for (UInt32 posState = 0; posState < numPosStates; posState++)
200 UpdateTable(posState);
202 void Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 symbol, UInt32 posState, bool updatePrice)
204 CEncoder::Encode(rangeEncoder, symbol, posState);
206 if (--_counters[posState] == 0)
207 UpdateTable(posState);
213 typedef struct _CSeqInStream
215 ISeqInStream SeqInStream;
216 CMyComPtr<ISequentialInStream> RealStream;
221 public ICompressCoder,
222 public ICompressSetOutStream,
223 public ICompressSetCoderProperties,
224 public ICompressWriteCoderProperties,
228 NRangeCoder::CEncoder _rangeEncoder;
230 IMatchFinder _matchFinder;
231 void *_matchFinderObj;
233 #ifdef COMPRESS_MF_MT
236 CMatchFinderMt _matchFinderMt;
239 CMatchFinder _matchFinderBase;
240 #ifdef COMPRESS_MF_MT
241 Byte _pad1[kMtCacheLineDummy];
244 COptimal _optimum[kNumOpts];
246 CMyBitEncoder _isMatch[kNumStates][NLength::kNumPosStatesEncodingMax];
247 CMyBitEncoder _isRep[kNumStates];
248 CMyBitEncoder _isRepG0[kNumStates];
249 CMyBitEncoder _isRepG1[kNumStates];
250 CMyBitEncoder _isRepG2[kNumStates];
251 CMyBitEncoder _isRep0Long[kNumStates][NLength::kNumPosStatesEncodingMax];
253 NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumPosSlotBits> _posSlotEncoder[kNumLenToPosStates];
255 CMyBitEncoder _posEncoders[kNumFullDistances - kEndPosModelIndex];
256 NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumAlignBits> _posAlignEncoder;
258 NLength::CPriceTableEncoder _lenEncoder;
259 NLength::CPriceTableEncoder _repMatchLenEncoder;
261 CLiteralEncoder _literalEncoder;
263 UInt32 _matchDistances[kMatchMaxLen * 2 + 2 + 1];
267 UInt32 _numFastBytes;
268 UInt32 _longestMatchLength;
269 UInt32 _numDistancePairs;
271 UInt32 _additionalOffset;
273 UInt32 _optimumEndIndex;
274 UInt32 _optimumCurrentIndex;
276 bool _longestMatchWasFound;
278 UInt32 _posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
280 UInt32 _distancesPrices[kNumLenToPosStates][kNumFullDistances];
282 UInt32 _alignPrices[kAlignTableSize];
283 UInt32 _alignPriceCount;
285 UInt32 _distTableSize;
287 UInt32 _posStateBits;
288 UInt32 _posStateMask;
289 UInt32 _numLiteralPosStateBits;
290 UInt32 _numLiteralContextBits;
292 UInt32 _dictionarySize;
294 UInt32 _matchPriceCount;
297 ISequentialInStream *_inStream;
299 CSeqInStream _seqInStream;
301 UInt32 _matchFinderCycles;
306 bool _needReleaseMFStream;
308 void ReleaseMatchFinder()
310 _matchFinder.Init = 0;
311 _seqInStream.RealStream.Release();
314 void ReleaseMFStream()
316 if (_matchFinderObj && _needReleaseMFStream)
318 #ifdef COMPRESS_MF_MT
320 MatchFinderMt_ReleaseStream(&_matchFinderMt);
322 _needReleaseMFStream = false;
324 _seqInStream.RealStream.Release();
327 UInt32 ReadMatchDistances(UInt32 &numDistancePairs);
329 void MovePos(UInt32 num);
330 UInt32 GetRepLen1Price(CState state, UInt32 posState) const
332 return _isRepG0[state.Index].GetPrice0() +
333 _isRep0Long[state.Index][posState].GetPrice0();
336 UInt32 GetPureRepPrice(UInt32 repIndex, CState state, UInt32 posState) const
341 price = _isRepG0[state.Index].GetPrice0();
342 price += _isRep0Long[state.Index][posState].GetPrice1();
346 price = _isRepG0[state.Index].GetPrice1();
348 price += _isRepG1[state.Index].GetPrice0();
351 price += _isRepG1[state.Index].GetPrice1();
352 price += _isRepG2[state.Index].GetPrice(repIndex - 2);
357 UInt32 GetRepPrice(UInt32 repIndex, UInt32 len, CState state, UInt32 posState) const
359 return _repMatchLenEncoder.GetPrice(len - kMatchMinLen, posState) +
360 GetPureRepPrice(repIndex, state, posState);
363 UInt32 GetPosLen2Price(UInt32 pos, UInt32 posState) const
365 if (pos >= kNumFullDistances)
366 return kIfinityPrice;
367 return _distancesPrices[0][pos] + _lenEncoder.GetPrice(0, posState);
369 UInt32 GetPosLen3Price(UInt32 pos, UInt32 len, UInt32 posState) const
372 UInt32 lenToPosState = GetLenToPosState(len);
373 if (pos < kNumFullDistances)
374 price = _distancesPrices[lenToPosState][pos];
376 price = _posSlotPrices[lenToPosState][GetPosSlot2(pos)] +
377 _alignPrices[pos & kAlignMask];
378 return price + _lenEncoder.GetPrice(len - kMatchMinLen, posState);
381 UInt32 GetPosLenPrice(UInt32 pos, UInt32 len, UInt32 posState) const
384 UInt32 lenToPosState = GetLenToPosState(len);
385 if (pos < kNumFullDistances)
386 price = _distancesPrices[lenToPosState][pos];
388 price = _posSlotPrices[lenToPosState][GetPosSlot2(pos)] +
389 _alignPrices[pos & kAlignMask];
390 return price + _lenEncoder.GetPrice(len - kMatchMinLen, posState);
393 UInt32 Backward(UInt32 &backRes, UInt32 cur);
394 UInt32 GetOptimum(UInt32 position, UInt32 &backRes);
395 UInt32 GetOptimumFast(UInt32 &backRes);
397 void FillDistancesPrices();
398 void FillAlignPrices();
400 void ReleaseStreams()
406 HRESULT Flush(UInt32 nowPos);
411 CCoderReleaser(CEncoder *coder): _coder(coder) {}
412 ~CCoderReleaser() { _coder->ReleaseStreams(); }
414 friend class CCoderReleaser;
416 void WriteEndMarker(UInt32 posState);
420 void SetWriteEndMarkerMode(bool writeEndMarker)
421 { _writeEndMark= writeEndMarker; }
426 ICompressSetOutStream,
427 ICompressSetCoderProperties,
428 ICompressWriteCoderProperties
433 // ICompressCoder interface
434 HRESULT SetStreams(ISequentialInStream *inStream,
435 ISequentialOutStream *outStream,
436 const UInt64 *inSize, const UInt64 *outSize);
437 HRESULT CodeOneBlock(UInt64 *inSize, UInt64 *outSize, Int32 *finished);
439 HRESULT CodeReal(ISequentialInStream *inStream,
440 ISequentialOutStream *outStream,
441 const UInt64 *inSize, const UInt64 *outSize,
442 ICompressProgressInfo *progress);
444 // ICompressCoder interface
445 STDMETHOD(Code)(ISequentialInStream *inStream,
446 ISequentialOutStream *outStream,
447 const UInt64 *inSize, const UInt64 *outSize,
448 ICompressProgressInfo *progress);
450 // ICompressSetCoderProperties2
451 STDMETHOD(SetCoderProperties)(const PROPID *propIDs,
452 const PROPVARIANT *properties, UInt32 numProperties);
454 // ICompressWriteCoderProperties
455 STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
457 STDMETHOD(SetOutStream)(ISequentialOutStream *outStream);
458 STDMETHOD(ReleaseOutStream)();