LZMAEncoder.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. // LZMA/Encoder.h
  2. #ifndef __LZMA_ENCODER_H
  3. #define __LZMA_ENCODER_H
  4. #include "../../../Common/MyCom.h"
  5. #include "../../ICoder.h"
  6. extern "C"
  7. {
  8. #include "../../../../C/Alloc.h"
  9. #include "../../../../C/Compress/Lz/MatchFinder.h"
  10. #ifdef COMPRESS_MF_MT
  11. #include "../../../../C/Compress/Lz/MatchFinderMt.h"
  12. #endif
  13. }
  14. #include "../RangeCoder/RangeCoderBitTree.h"
  15. #include "LZMA.h"
  16. namespace NCompress {
  17. namespace NLZMA {
  18. typedef NRangeCoder::CBitEncoder<kNumMoveBits> CMyBitEncoder;
  19. class CBaseState
  20. {
  21. protected:
  22. CState _state;
  23. Byte _previousByte;
  24. UInt32 _repDistances[kNumRepDistances];
  25. void Init()
  26. {
  27. _state.Init();
  28. _previousByte = 0;
  29. for(UInt32 i = 0 ; i < kNumRepDistances; i++)
  30. _repDistances[i] = 0;
  31. }
  32. };
  33. struct COptimal
  34. {
  35. CState State;
  36. bool Prev1IsChar;
  37. bool Prev2;
  38. UInt32 PosPrev2;
  39. UInt32 BackPrev2;
  40. UInt32 Price;
  41. UInt32 PosPrev; // posNext;
  42. UInt32 BackPrev;
  43. UInt32 Backs[kNumRepDistances];
  44. void MakeAsChar() { BackPrev = UInt32(-1); Prev1IsChar = false; }
  45. void MakeAsShortRep() { BackPrev = 0; ; Prev1IsChar = false; }
  46. bool IsShortRep() { return (BackPrev == 0); }
  47. };
  48. // #define LZMA_LOG_BRANCH
  49. #if _MSC_VER >= 1400
  50. // Must give gain in core 2. but slower ~2% on k8.
  51. // #define LZMA_LOG_BSR
  52. #endif
  53. #ifndef LZMA_LOG_BSR
  54. static const int kNumLogBits = 13; // don't change it !
  55. extern Byte g_FastPos[];
  56. #endif
  57. inline UInt32 GetPosSlot(UInt32 pos)
  58. {
  59. #ifdef LZMA_LOG_BSR
  60. if (pos < 2)
  61. return pos;
  62. unsigned long index;
  63. _BitScanReverse(&index, pos);
  64. return (index + index) + ((pos >> (index - 1)) & 1);
  65. #else
  66. if (pos < (1 << kNumLogBits))
  67. return g_FastPos[pos];
  68. if (pos < (1 << (kNumLogBits * 2 - 1)))
  69. return g_FastPos[pos >> (kNumLogBits - 1)] + (kNumLogBits - 1) * 2;
  70. return g_FastPos[pos >> (kNumLogBits - 1) * 2] + (kNumLogBits - 1) * 4;
  71. #endif
  72. }
  73. inline UInt32 GetPosSlot2(UInt32 pos)
  74. {
  75. #ifdef LZMA_LOG_BSR
  76. unsigned long index;
  77. _BitScanReverse(&index, pos);
  78. return (index + index) + ((pos >> (index - 1)) & 1);
  79. #else
  80. #ifdef LZMA_LOG_BRANCH
  81. if (pos < (1 << (kNumLogBits + 6)))
  82. return g_FastPos[pos >> 6] + 12;
  83. if (pos < (1 << (kNumLogBits * 2 + 5)))
  84. return g_FastPos[pos >> (kNumLogBits + 5)] + (kNumLogBits + 5) * 2;
  85. return g_FastPos[pos >> (kNumLogBits * 2 + 4)] + (kNumLogBits * 2 + 4) * 2;
  86. #else
  87. // it's faster with VC6-32bit.
  88. UInt32 s = 6 + ((kNumLogBits - 1) & (UInt32)((Int32)(((1 << (kNumLogBits + 6)) - 1) - pos) >> 31));
  89. return g_FastPos[pos >> s] + (s * 2);
  90. #endif
  91. #endif
  92. }
  93. const UInt32 kIfinityPrice = 0xFFFFFFF;
  94. const UInt32 kNumOpts = 1 << 12;
  95. class CLiteralEncoder2
  96. {
  97. CMyBitEncoder _encoders[0x300];
  98. public:
  99. void Init()
  100. {
  101. for (int i = 0; i < 0x300; i++)
  102. _encoders[i].Init();
  103. }
  104. void Encode(NRangeCoder::CEncoder *rangeEncoder, Byte symbol);
  105. void EncodeMatched(NRangeCoder::CEncoder *rangeEncoder, Byte matchByte, Byte symbol);
  106. UInt32 GetPrice(bool matchMode, Byte matchByte, Byte symbol) const;
  107. };
  108. class CLiteralEncoder
  109. {
  110. CLiteralEncoder2 *_coders;
  111. int _numPrevBits;
  112. int _numPosBits;
  113. UInt32 _posMask;
  114. public:
  115. CLiteralEncoder(): _coders(0) {}
  116. ~CLiteralEncoder() { Free(); }
  117. void Free()
  118. {
  119. MyFree(_coders);
  120. _coders = 0;
  121. }
  122. bool Create(int numPosBits, int numPrevBits)
  123. {
  124. if (_coders == 0 || (numPosBits + numPrevBits) != (_numPrevBits + _numPosBits))
  125. {
  126. Free();
  127. UInt32 numStates = 1 << (numPosBits + numPrevBits);
  128. _coders = (CLiteralEncoder2 *)MyAlloc(numStates * sizeof(CLiteralEncoder2));
  129. }
  130. _numPosBits = numPosBits;
  131. _posMask = (1 << numPosBits) - 1;
  132. _numPrevBits = numPrevBits;
  133. return (_coders != 0);
  134. }
  135. void Init()
  136. {
  137. UInt32 numStates = 1 << (_numPrevBits + _numPosBits);
  138. for (UInt32 i = 0; i < numStates; i++)
  139. _coders[i].Init();
  140. }
  141. CLiteralEncoder2 *GetSubCoder(UInt32 pos, Byte prevByte)
  142. { return &_coders[((pos & _posMask) << _numPrevBits) + (prevByte >> (8 - _numPrevBits))]; }
  143. };
  144. namespace NLength {
  145. class CEncoder
  146. {
  147. CMyBitEncoder _choice;
  148. CMyBitEncoder _choice2;
  149. NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumLowBits> _lowCoder[kNumPosStatesEncodingMax];
  150. NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumMidBits> _midCoder[kNumPosStatesEncodingMax];
  151. NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumHighBits> _highCoder;
  152. public:
  153. void Init(UInt32 numPosStates);
  154. void Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 symbol, UInt32 posState);
  155. void SetPrices(UInt32 posState, UInt32 numSymbols, UInt32 *prices) const;
  156. };
  157. const UInt32 kNumSpecSymbols = kNumLowSymbols + kNumMidSymbols;
  158. class CPriceTableEncoder: public CEncoder
  159. {
  160. UInt32 _prices[kNumPosStatesEncodingMax][kNumSymbolsTotal];
  161. UInt32 _tableSize;
  162. UInt32 _counters[kNumPosStatesEncodingMax];
  163. public:
  164. void SetTableSize(UInt32 tableSize) { _tableSize = tableSize; }
  165. UInt32 GetPrice(UInt32 symbol, UInt32 posState) const { return _prices[posState][symbol]; }
  166. void UpdateTable(UInt32 posState)
  167. {
  168. SetPrices(posState, _tableSize, _prices[posState]);
  169. _counters[posState] = _tableSize;
  170. }
  171. void UpdateTables(UInt32 numPosStates)
  172. {
  173. for (UInt32 posState = 0; posState < numPosStates; posState++)
  174. UpdateTable(posState);
  175. }
  176. void Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 symbol, UInt32 posState, bool updatePrice)
  177. {
  178. CEncoder::Encode(rangeEncoder, symbol, posState);
  179. if (updatePrice)
  180. if (--_counters[posState] == 0)
  181. UpdateTable(posState);
  182. }
  183. };
  184. }
  185. typedef struct _CSeqInStream
  186. {
  187. ISeqInStream SeqInStream;
  188. CMyComPtr<ISequentialInStream> RealStream;
  189. } CSeqInStream;
  190. class CEncoder :
  191. public ICompressCoder,
  192. public ICompressSetOutStream,
  193. public ICompressSetCoderProperties,
  194. public ICompressWriteCoderProperties,
  195. public CBaseState,
  196. public CMyUnknownImp
  197. {
  198. NRangeCoder::CEncoder _rangeEncoder;
  199. IMatchFinder _matchFinder;
  200. void *_matchFinderObj;
  201. #ifdef COMPRESS_MF_MT
  202. Bool _multiThread;
  203. Bool _mtMode;
  204. CMatchFinderMt _matchFinderMt;
  205. #endif
  206. CMatchFinder _matchFinderBase;
  207. #ifdef COMPRESS_MF_MT
  208. Byte _pad1[kMtCacheLineDummy];
  209. #endif
  210. COptimal _optimum[kNumOpts];
  211. CMyBitEncoder _isMatch[kNumStates][NLength::kNumPosStatesEncodingMax];
  212. CMyBitEncoder _isRep[kNumStates];
  213. CMyBitEncoder _isRepG0[kNumStates];
  214. CMyBitEncoder _isRepG1[kNumStates];
  215. CMyBitEncoder _isRepG2[kNumStates];
  216. CMyBitEncoder _isRep0Long[kNumStates][NLength::kNumPosStatesEncodingMax];
  217. NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumPosSlotBits> _posSlotEncoder[kNumLenToPosStates];
  218. CMyBitEncoder _posEncoders[kNumFullDistances - kEndPosModelIndex];
  219. NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumAlignBits> _posAlignEncoder;
  220. NLength::CPriceTableEncoder _lenEncoder;
  221. NLength::CPriceTableEncoder _repMatchLenEncoder;
  222. CLiteralEncoder _literalEncoder;
  223. UInt32 _matchDistances[kMatchMaxLen * 2 + 2 + 1];
  224. bool _fastMode;
  225. // bool _maxMode;
  226. UInt32 _numFastBytes;
  227. UInt32 _longestMatchLength;
  228. UInt32 _numDistancePairs;
  229. UInt32 _additionalOffset;
  230. UInt32 _optimumEndIndex;
  231. UInt32 _optimumCurrentIndex;
  232. bool _longestMatchWasFound;
  233. UInt32 _posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
  234. UInt32 _distancesPrices[kNumLenToPosStates][kNumFullDistances];
  235. UInt32 _alignPrices[kAlignTableSize];
  236. UInt32 _alignPriceCount;
  237. UInt32 _distTableSize;
  238. UInt32 _posStateBits;
  239. UInt32 _posStateMask;
  240. UInt32 _numLiteralPosStateBits;
  241. UInt32 _numLiteralContextBits;
  242. UInt32 _dictionarySize;
  243. UInt32 _matchPriceCount;
  244. UInt64 nowPos64;
  245. bool _finished;
  246. ISequentialInStream *_inStream;
  247. CSeqInStream _seqInStream;
  248. UInt32 _matchFinderCycles;
  249. // int _numSkip
  250. bool _writeEndMark;
  251. bool _needReleaseMFStream;
  252. void ReleaseMatchFinder()
  253. {
  254. _matchFinder.Init = 0;
  255. _seqInStream.RealStream.Release();
  256. }
  257. void ReleaseMFStream()
  258. {
  259. if (_matchFinderObj && _needReleaseMFStream)
  260. {
  261. #ifdef COMPRESS_MF_MT
  262. if (_mtMode)
  263. MatchFinderMt_ReleaseStream(&_matchFinderMt);
  264. #endif
  265. _needReleaseMFStream = false;
  266. }
  267. _seqInStream.RealStream.Release();
  268. }
  269. UInt32 ReadMatchDistances(UInt32 &numDistancePairs);
  270. void MovePos(UInt32 num);
  271. UInt32 GetRepLen1Price(CState state, UInt32 posState) const
  272. {
  273. return _isRepG0[state.Index].GetPrice0() +
  274. _isRep0Long[state.Index][posState].GetPrice0();
  275. }
  276. UInt32 GetPureRepPrice(UInt32 repIndex, CState state, UInt32 posState) const
  277. {
  278. UInt32 price;
  279. if(repIndex == 0)
  280. {
  281. price = _isRepG0[state.Index].GetPrice0();
  282. price += _isRep0Long[state.Index][posState].GetPrice1();
  283. }
  284. else
  285. {
  286. price = _isRepG0[state.Index].GetPrice1();
  287. if (repIndex == 1)
  288. price += _isRepG1[state.Index].GetPrice0();
  289. else
  290. {
  291. price += _isRepG1[state.Index].GetPrice1();
  292. price += _isRepG2[state.Index].GetPrice(repIndex - 2);
  293. }
  294. }
  295. return price;
  296. }
  297. UInt32 GetRepPrice(UInt32 repIndex, UInt32 len, CState state, UInt32 posState) const
  298. {
  299. return _repMatchLenEncoder.GetPrice(len - kMatchMinLen, posState) +
  300. GetPureRepPrice(repIndex, state, posState);
  301. }
  302. /*
  303. UInt32 GetPosLen2Price(UInt32 pos, UInt32 posState) const
  304. {
  305. if (pos >= kNumFullDistances)
  306. return kIfinityPrice;
  307. return _distancesPrices[0][pos] + _lenEncoder.GetPrice(0, posState);
  308. }
  309. UInt32 GetPosLen3Price(UInt32 pos, UInt32 len, UInt32 posState) const
  310. {
  311. UInt32 price;
  312. UInt32 lenToPosState = GetLenToPosState(len);
  313. if (pos < kNumFullDistances)
  314. price = _distancesPrices[lenToPosState][pos];
  315. else
  316. price = _posSlotPrices[lenToPosState][GetPosSlot2(pos)] +
  317. _alignPrices[pos & kAlignMask];
  318. return price + _lenEncoder.GetPrice(len - kMatchMinLen, posState);
  319. }
  320. */
  321. UInt32 GetPosLenPrice(UInt32 pos, UInt32 len, UInt32 posState) const
  322. {
  323. UInt32 price;
  324. UInt32 lenToPosState = GetLenToPosState(len);
  325. if (pos < kNumFullDistances)
  326. price = _distancesPrices[lenToPosState][pos];
  327. else
  328. price = _posSlotPrices[lenToPosState][GetPosSlot2(pos)] +
  329. _alignPrices[pos & kAlignMask];
  330. return price + _lenEncoder.GetPrice(len - kMatchMinLen, posState);
  331. }
  332. UInt32 Backward(UInt32 &backRes, UInt32 cur);
  333. UInt32 GetOptimum(UInt32 position, UInt32 &backRes);
  334. UInt32 GetOptimumFast(UInt32 &backRes);
  335. void FillDistancesPrices();
  336. void FillAlignPrices();
  337. void ReleaseStreams()
  338. {
  339. ReleaseMFStream();
  340. ReleaseOutStream();
  341. }
  342. HRESULT Flush(UInt32 nowPos);
  343. class CCoderReleaser
  344. {
  345. CEncoder *_coder;
  346. public:
  347. CCoderReleaser(CEncoder *coder): _coder(coder) {}
  348. ~CCoderReleaser() { _coder->ReleaseStreams(); }
  349. };
  350. friend class CCoderReleaser;
  351. void WriteEndMarker(UInt32 posState);
  352. public:
  353. CEncoder();
  354. void SetWriteEndMarkerMode(bool writeEndMarker)
  355. { _writeEndMark= writeEndMarker; }
  356. HRESULT Create();
  357. MY_UNKNOWN_IMP3(
  358. ICompressSetOutStream,
  359. ICompressSetCoderProperties,
  360. ICompressWriteCoderProperties
  361. )
  362. HRESULT Init();
  363. // ICompressCoder interface
  364. HRESULT SetStreams(ISequentialInStream *inStream,
  365. ISequentialOutStream *outStream,
  366. const UInt64 *inSize, const UInt64 *outSize);
  367. HRESULT CodeOneBlock(UInt64 *inSize, UInt64 *outSize, Int32 *finished);
  368. HRESULT CodeReal(ISequentialInStream *inStream,
  369. ISequentialOutStream *outStream,
  370. const UInt64 *inSize, const UInt64 *outSize,
  371. ICompressProgressInfo *progress);
  372. // ICompressCoder interface
  373. STDMETHOD(Code)(ISequentialInStream *inStream,
  374. ISequentialOutStream *outStream,
  375. const UInt64 *inSize, const UInt64 *outSize,
  376. ICompressProgressInfo *progress);
  377. // ICompressSetCoderProperties2
  378. STDMETHOD(SetCoderProperties)(const PROPID *propIDs,
  379. const PROPVARIANT *properties, UInt32 numProperties);
  380. // ICompressWriteCoderProperties
  381. STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
  382. STDMETHOD(SetOutStream)(ISequentialOutStream *outStream);
  383. STDMETHOD(ReleaseOutStream)();
  384. virtual ~CEncoder();
  385. };
  386. }}
  387. #endif