1 /* converted by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
4 * This program is free software. It comes without any warranty, to
5 * the extent permitted by applicable law. You can redistribute it
6 * and/or modify it under the terms of the Do What The Fuck You Want
7 * To Public License, Version 2, as published by Sam Hocevar. See
8 * http://www.wtfpl.net/txt/copying/ for more details.
13 /* use slightly smaller (around 300 bytes) code with branching in compressor? */
14 //version = LZMA_ENC_USE_BRANCH;
16 //version = LZMA_SANITY_MAGIC;
18 private import iv
.dlzma
;
21 // ////////////////////////////////////////////////////////////////////////// //
22 // ////////////////////////////////////////////////////////////////////////// //
23 // ////////////////////////////////////////////////////////////////////////// //
24 // ////////////////////////////////////////////////////////////////////////// //
27 private void SetUi32 (const(void)* p
, in uint v
) nothrow @trusted @nogc { pragma(inline
, true); *(cast(uint*)p
) = v
; }
28 private ushort GetUi16 (const(void)* v
) nothrow @trusted @nogc { pragma(inline
, true); return *(cast(const(ushort)*)v
); }
36 uint streamPos
; /* wrap over Zero is allowed (streamPos < pos). Use (uint32_t)(streamPos - pos) */
40 uint cyclicBufferSize
; /* it must be = (historySize + 1) */
42 ubyte streamEndWasReached
;
69 ulong expectedDataSize
;
72 //#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((const ubyte *)(p)->buffer)
74 //#define Inline_MatchFinder_GetNumAvailableBytes(p) ((uint)((p)->streamPos - (p)->pos))
75 enum Inline_MatchFinder_GetNumAvailableBytes(string p
) = `(cast(uint)((`~p
~`).streamPos - (`~p
~`).pos))`;
78 #define Inline_MatchFinder_IsFinishedOK(p) \
79 ((p)->streamEndWasReached \
80 && (p)->streamPos == (p)->pos \
81 && (!(p)->directInput || (p)->directInputRem == 0))
85 int MatchFinder_NeedMove(CMatchFinder *p);
86 /* uint8_t *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); */
87 void MatchFinder_MoveBlock(CMatchFinder *p);
88 void MatchFinder_ReadIfRequired(CMatchFinder *p);
90 void MatchFinder_Construct(CMatchFinder *p);
94 keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
96 int MatchFinder_Create(CMatchFinder *p, uint historySize,
97 uint keepAddBufferBefore, uint matchMaxLen, uint keepAddBufferAfter,
99 void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc);
100 void MatchFinder_Normalize3(uint subValue, CLzRef *items, usize numItems);
101 // void MatchFinder_ReduceOffsets(CMatchFinder *p, uint32_t subValue);
105 #define Inline_MatchFinder_InitPos(p, val) \
107 (p)->streamPos = (val);
111 #define Inline_MatchFinder_ReduceOffsets(p, subValue) \
112 (p)->pos -= (subValue); \
113 (p)->streamPos -= (subValue);
117 uint* GetMatchesSpec1(uint lenLimit, uint curMatch, uint pos, const ubyte *buffer, CLzRef *son,
118 usize _cyclicBufferPos, uint _cyclicBufferSize, uint _cutValue,
119 uint *distances, uint maxLen);
124 Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
125 Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
128 alias Mf_Init_Func
= void function (void *object
);
129 alias Mf_GetNumAvailableBytes_Func
= uint function (void *object
);
130 alias Mf_GetPointerToCurrentPos_Func
= const(ubyte)* function (void *object
);
131 alias Mf_GetMatches_Func
= uint* function (void *object
, uint *distances
);
132 alias Mf_Skip_Func
= void function (void *object
, uint);
134 struct /*_IMatchFinder*/ IMatchFinder2
{
136 Mf_GetNumAvailableBytes_Func GetNumAvailableBytes
;
137 Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos
;
138 Mf_GetMatches_Func GetMatches
;
143 void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder2 *vTable);
145 void MatchFinder_Init_LowHash(CMatchFinder *p);
146 void MatchFinder_Init_HighHash(CMatchFinder *p);
147 void MatchFinder_Init_4(CMatchFinder *p);
148 void MatchFinder_Init(CMatchFinder *p);
150 uint* Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, uint *distances);
151 uint* Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, uint *distances);
153 void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, uint num);
154 void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, uint num);
156 void LzFindPrepare(void);
160 /* LzHash.h -- HASH functions for LZ algorithms
161 2019-10-30 : Igor Pavlov : Public domain */
164 (kHash2Size >= (1 << 8)) : Required
165 (kHash3Size >= (1 << 16)) : Required
168 enum kHash2Size
= (1 << 10);
169 enum kHash3Size
= (1 << 16);
170 // #define kHash4Size (1 << 20)
172 enum kFix3HashSize
= (kHash2Size
);
173 enum kFix4HashSize
= (kHash2Size
+ kHash3Size
);
174 // #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
177 We use up to 3 crc values for hash:
181 (Shift_1 = 5) and (Shift_2 = 10) is good tradeoff.
182 Small values for Shift are not good for collision rate.
183 Big value for Shift_2 increases the minimum size
184 of hash table, that will be slow for small files.
187 enum kLzHash_CrcShift_1
= 5;
188 enum kLzHash_CrcShift_2
= 10;
192 enum kBlockMoveAlign
= (1 << 7); // alignment for memmove()
193 enum kBlockSizeAlign
= (1 << 16); // alignment for block allocation
194 enum kBlockSizeReserveMin
= (1 << 24); // it's 1/256 from 4 GB dictinary
196 enum kEmptyHashValue
= 0;
198 enum kMaxValForNormalize
= cast(uint)0;
199 // #define kMaxValForNormalize ((uint)(1 << 20) + 0xFFF) // for debug
201 // #define kNormalizeAlign (1 << 7) // alignment for speculated accesses
204 // #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
205 enum kFix5HashSize
= kFix4HashSize
;
207 // (crc[0 ... 255] & 0xFF) provides one-to-one correspondence to [0 ... 255]
211 if (cur[0]) and (h2) match, then cur[1] also match
212 if (cur[0]) and (hv) match, then cur[1] and cur[2] also match
215 uint temp
= p
.crc
[cur
[0]] ^ cur
[1];
216 h2
= temp
& (kHash2Size
- 1);
217 hv
= (temp ^
(cast(uint)cur
[2] << 8)) & p
.hashMask
;
221 uint temp
= p
.crc
[cur
[0]] ^ cur
[1];
222 h2
= temp
& (kHash2Size
- 1);
223 temp ^
= (cast(uint)cur
[2] << 8);
224 h3
= temp
& (kHash3Size
- 1);
225 hv
= (temp ^
(p
.crc
[cur
[3]] << kLzHash_CrcShift_1
)) & p
.hashMask
;
229 uint temp
= p
.crc
[cur
[0]] ^ cur
[1];
230 h2
= temp
& (kHash2Size
- 1);
231 temp ^
= (cast(uint)cur
[2] << 8);
232 h3
= temp
& (kHash3Size
- 1);
233 temp ^
= (p
.crc
[cur
[3]] << kLzHash_CrcShift_1
);
234 /* h4 = temp & p->hash4Mask; */ /* (kHash4Size - 1); */
235 hv
= (temp ^
(p
.crc
[cur
[4]] << kLzHash_CrcShift_2
)) & p
.hashMask
;
238 enum HASH_ZIP_CALC
= `hv = ((cur[2] | (cast(uint)cur[0] << 8)) ^ p.crc[cur[1]]) & 0xFFFF;`;
241 private void LzInWindow_Free(CMatchFinder
*p
, ISzAllocPtr alloc
)
245 ISzAlloc_Free(alloc
, p
.bufferBase
);
251 private int LzInWindow_Create2(CMatchFinder
*p
, uint blockSize
, ISzAllocPtr alloc
)
255 if (!p
.bufferBase || p
.blockSize
!= blockSize
)
258 LzInWindow_Free(p
, alloc
);
259 p
.blockSize
= blockSize
;
260 // blockSizeT = blockSize;
262 // printf("\nblockSize = 0x%x\n", blockSize);
265 // we can allocate 4GiB, but still use uint for (p->blockSize)
266 // we use uint type for (p->blockSize), because
267 // we don't want to wrap over 4 GiB,
268 // when we use (p->streamPos - p->pos) that is uint.
269 if (blockSize >= (uint)0 - (uint)kBlockSizeAlign)
271 blockSizeT = ((usize)1 << 32);
272 printf("\nchanged to blockSizeT = 4GiB\n");
277 p
.bufferBase
= cast(ubyte *)ISzAlloc_Alloc(alloc
, blockSize
);
278 // printf("\nbufferBase = %p\n", p->bufferBase);
279 // return 0; // for debug
281 return (p
.bufferBase
!= null);
284 private const(ubyte)* MatchFinder_GetPointerToCurrentPos(CMatchFinder
*p
) { pragma(inline
, true); return p
.buffer
; }
286 private uint MatchFinder_GetNumAvailableBytes(CMatchFinder
*p
) { pragma(inline
, true); return mixin(Inline_MatchFinder_GetNumAvailableBytes
!"p"); }
290 private void MatchFinder_ReadBlock(CMatchFinder
*p
)
292 if (p
.streamEndWasReached || p
.result
!= SZ_OK
)
295 /* We use (p->streamPos - p->pos) value.
296 (p->streamPos < p->pos) is allowed. */
300 uint curSize
= 0xFFFFFFFF - mixin(Inline_MatchFinder_GetNumAvailableBytes
!"p");
301 if (curSize
> p
.directInputRem
)
302 curSize
= cast(uint)p
.directInputRem
;
303 p
.directInputRem
-= curSize
;
304 p
.streamPos
+= curSize
;
305 if (p
.directInputRem
== 0)
306 p
.streamEndWasReached
= 1;
312 ubyte *dest
= p
.buffer
+ mixin(Inline_MatchFinder_GetNumAvailableBytes
!"p");
313 usize size
= cast(usize
)(p
.bufferBase
+ p
.blockSize
- dest
);
316 /* we call ReadBlock() after NeedMove() and MoveBlock().
317 NeedMove() and MoveBlock() povide more than (keepSizeAfter)
318 to the end of (blockSize).
319 So we don't execute this branch in normal code flow.
320 We can go here, if we will call ReadBlock() before NeedMove(), MoveBlock().
322 // p->result = SZ_ERROR_FAIL; // we can show error here
327 // if (size > kRead) size = kRead; // for debug
329 //p.result = ISeqInStream_Read(p.stream, dest, &size);
330 p
.result
= p
.stream
.Read(p
.stream
, dest
, &size
);
331 if (p
.result
!= SZ_OK
)
335 p
.streamEndWasReached
= 1;
338 p
.streamPos
+= cast(uint)size
;
339 if (mixin(Inline_MatchFinder_GetNumAvailableBytes
!"p") > p
.keepSizeAfter
)
341 /* here and in another (p->keepSizeAfter) checks we keep on 1 byte more than was requested by Create() function
342 (Inline_MatchFinder_GetNumAvailableBytes(p) >= p->keepSizeAfter) - minimal required size */
345 // on exit: (p->result != SZ_OK || p->streamEndWasReached || Inline_MatchFinder_GetNumAvailableBytes(p) > p->keepSizeAfter)
351 private void MatchFinder_MoveBlock (CMatchFinder
*p
) @nogc {
352 import core
.stdc
.string
: memmove
;
353 const usize offset
= cast(usize
)(p
.buffer
- p
.bufferBase
) - p
.keepSizeBefore
;
354 const usize keepBefore
= (offset
& (kBlockMoveAlign
- 1)) + p
.keepSizeBefore
;
355 p
.buffer
= p
.bufferBase
+ keepBefore
;
356 memmove(p
.bufferBase
,
357 p
.bufferBase
+ (offset
& ~(cast(usize
)kBlockMoveAlign
- 1)),
358 keepBefore
+ cast(usize
)mixin(Inline_MatchFinder_GetNumAvailableBytes
!"p"));
361 /* We call MoveBlock() before ReadBlock().
362 So MoveBlock() can be wasteful operation, if the whole input data
363 can fit in current block even without calling MoveBlock().
364 in important case where (dataSize <= historySize)
365 condition (p->blockSize > dataSize + p->keepSizeAfter) is met
366 So there is no MoveBlock() in that case case.
369 private int MatchFinder_NeedMove (CMatchFinder
*p
) @nogc {
372 if (p
.streamEndWasReached || p
.result
!= SZ_OK
)
374 return (cast(usize
)(p
.bufferBase
+ p
.blockSize
- p
.buffer
) <= p
.keepSizeAfter
);
377 private void MatchFinder_ReadIfRequired (CMatchFinder
*p
) {
378 if (p
.keepSizeAfter
>= mixin(Inline_MatchFinder_GetNumAvailableBytes
!"p"))
379 MatchFinder_ReadBlock(p
);
383 private void MatchFinder_SetDefaultSettings (CMatchFinder
* p
) @nogc {
390 enum kCrcPoly
= 0xEDB88320;
392 private void MatchFinder_Construct (CMatchFinder
* p
) @nogc {
397 p
.expectedDataSize
= cast(ulong)cast(long)-1;
398 MatchFinder_SetDefaultSettings(p
);
400 for (i
= 0; i
< 256; i
++)
402 uint r
= cast(uint)i
;
404 for (j
= 0; j
< 8; j
++)
405 r
= (r
>> 1) ^
(kCrcPoly
& (cast(uint)0 - (r
& 1)));
410 private void MatchFinder_FreeThisClassMemory(CMatchFinder
*p
, ISzAllocPtr alloc
)
412 ISzAlloc_Free(alloc
, p
.hash
);
416 private void MatchFinder_Free(CMatchFinder
*p
, ISzAllocPtr alloc
)
418 MatchFinder_FreeThisClassMemory(p
, alloc
);
419 LzInWindow_Free(p
, alloc
);
422 private CLzRef
* AllocRefs(usize num
, ISzAllocPtr alloc
)
424 usize sizeInBytes
= cast(usize
)num
* CLzRef
.sizeof
;
425 if (sizeInBytes
/ CLzRef
.sizeof
!= num
)
427 return cast(CLzRef
*)ISzAlloc_Alloc(alloc
, sizeInBytes
);
430 static assert(kBlockSizeReserveMin
>= kBlockSizeAlign
* 2, "Stop_Compiling_Bad_Reserve");
434 private uint GetBlockSize (CMatchFinder
* p
, uint historySize
) @nogc {
435 uint blockSize
= (p
.keepSizeBefore
+ p
.keepSizeAfter
);
437 if (historySize > kMaxHistorySize)
440 // printf("\nhistorySize == 0x%x\n", historySize);
442 if (p
.keepSizeBefore
< historySize || blockSize
< p
.keepSizeBefore
) // if 32-bit overflow
446 const uint kBlockSizeMax
= cast(uint)0 - cast(uint)kBlockSizeAlign
;
447 const uint rem
= kBlockSizeMax
- blockSize
;
448 const uint reserve
= (blockSize
>> (blockSize
< (cast(uint)1 << 30) ?
1 : 2))
449 + (1 << 12) + kBlockMoveAlign
+ kBlockSizeAlign
; // do not overflow 32-bit here
450 if (blockSize
>= kBlockSizeMax
451 || rem
< kBlockSizeReserveMin
) // we reject settings that will be slow
454 blockSize
= kBlockSizeMax
;
457 blockSize
+= reserve
;
458 blockSize
&= ~cast(uint)(kBlockSizeAlign
- 1);
461 // printf("\n LzFind_blockSize = %x\n", blockSize);
462 // printf("\n LzFind_blockSize = %d\n", blockSize >> 20);
467 private int MatchFinder_Create(CMatchFinder
*p
, uint historySize
,
468 uint keepAddBufferBefore
, uint matchMaxLen
, uint keepAddBufferAfter
,
471 /* we need one additional byte in (p->keepSizeBefore),
472 since we use MoveBlock() after (p->pos++) and before dictionary using */
473 // keepAddBufferBefore = (uint)0xFFFFFFFF - (1 << 22); // for debug
474 p
.keepSizeBefore
= historySize
+ keepAddBufferBefore
+ 1;
476 keepAddBufferAfter
+= matchMaxLen
;
477 /* we need (p->keepSizeAfter >= p->numHashBytes) */
478 if (keepAddBufferAfter
< p
.numHashBytes
)
479 keepAddBufferAfter
= p
.numHashBytes
;
480 // keepAddBufferAfter -= 2; // for debug
481 p
.keepSizeAfter
= keepAddBufferAfter
;
485 if (p
.directInput ||
LzInWindow_Create2(p
, GetBlockSize(p
, historySize
), alloc
))
487 const uint newCyclicBufferSize
= historySize
+ 1; // do not change it
489 p
.matchMaxLen
= matchMaxLen
;
494 if (p
.numHashBytes
!= 2)
497 if (hs
> p
.expectedDataSize
)
498 hs
= cast(uint)p
.expectedDataSize
;
505 // we propagated 16 bits in (hs). Low 16 bits must be set later
509 if (p
.numHashBytes
== 3)
513 /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */
516 // hs = ((uint)1 << 25) - 1; // for test
518 // (hash_size >= (1 << 16)) : Required for (numHashBytes > 2)
519 hs |
= (1 << 16) - 1; /* don't change it! */
521 // bt5: we adjust the size with recommended minimum size
522 if (p
.numHashBytes
>= 5)
523 hs |
= (256 << kLzHash_CrcShift_2
) - 1;
532 // hs4 = (1 << 16); // for test
533 p->hash4Mask = hs4 - 1;
536 if (p
.numHashBytes
> 2) p
.fixedHashSize
+= kHash2Size
;
537 if (p
.numHashBytes
> 3) p
.fixedHashSize
+= kHash3Size
;
538 // if (p->numHashBytes > 4) p->fixedHashSize += hs4; // kHash4Size;
539 hs
+= p
.fixedHashSize
;
545 p
.historySize
= historySize
;
547 p
.cyclicBufferSize
= newCyclicBufferSize
; // it must be = (historySize + 1)
549 numSons
= newCyclicBufferSize
;
552 newSize
= hs
+ numSons
;
554 // aligned size is not required here, but it can be better for some loops
555 enum NUM_REFS_ALIGN_MASK
= 0xF;
556 newSize
= (newSize
+ NUM_REFS_ALIGN_MASK
) & ~cast(usize
)NUM_REFS_ALIGN_MASK
;
558 if (p
.hash
&& p
.numRefs
== newSize
)
561 MatchFinder_FreeThisClassMemory(p
, alloc
);
563 p
.hash
= AllocRefs(newSize
, alloc
);
567 p
.son
= p
.hash
+ p
.hashSizeSum
;
573 MatchFinder_Free(p
, alloc
);
578 private void MatchFinder_SetLimits (CMatchFinder
* p
) @nogc {
580 uint n
= kMaxValForNormalize
- p
.pos
;
582 n
= cast(uint)cast(int)-1; // we allow (pos == 0) at start even with (kMaxValForNormalize == 0)
584 k
= p
.cyclicBufferSize
- p
.cyclicBufferPos
;
588 k
= mixin(Inline_MatchFinder_GetNumAvailableBytes
!"p");
590 const uint ksa
= p
.keepSizeAfter
;
591 uint mm
= p
.matchMaxLen
;
593 k
-= ksa
; // we must limit exactly to keepSizeAfter for ReadBlock
596 // the limitation for (p->lenLimit) update
597 k
-= mm
; // optimization : to reduce the number of checks
599 // k = 1; // non-optimized version : for debug
612 p
.posLimit
= p
.pos
+ n
;
616 private void MatchFinder_Init_LowHash (CMatchFinder
* p
) @nogc {
618 CLzRef
*items
= p
.hash
;
619 const usize numItems
= p
.fixedHashSize
;
620 for (i
= 0; i
< numItems
; i
++)
621 items
[i
] = kEmptyHashValue
;
625 private void MatchFinder_Init_HighHash (CMatchFinder
* p
) @nogc {
627 CLzRef
*items
= p
.hash
+ p
.fixedHashSize
;
628 const usize numItems
= cast(usize
)p
.hashMask
+ 1;
629 for (i
= 0; i
< numItems
; i
++)
630 items
[i
] = kEmptyHashValue
;
634 private void MatchFinder_Init_4 (CMatchFinder
* p
) @nogc {
635 p
.buffer
= p
.bufferBase
;
637 /* kEmptyHashValue = 0 (Zero) is used in hash tables as NO-VALUE marker.
638 the code in CMatchFinderMt expects (pos = 1) */
641 1; // it's smallest optimal value. do not change it
645 p
.streamEndWasReached
= 0;
649 // (CYC_TO_POS_OFFSET == 0) is expected by some optimized code
650 enum CYC_TO_POS_OFFSET
= 0;
651 // #define CYC_TO_POS_OFFSET 1 // for debug
653 private void MatchFinder_Init (CMatchFinder
* p
) {
654 MatchFinder_Init_HighHash(p
);
655 MatchFinder_Init_LowHash(p
);
656 MatchFinder_Init_4(p
);
658 MatchFinder_ReadBlock(p
);
660 /* if we init (cyclicBufferPos = pos), then we can use one variable
661 instead of both (cyclicBufferPos) and (pos) : only before (cyclicBufferPos) wrapping */
662 p
.cyclicBufferPos
= (p
.pos
- CYC_TO_POS_OFFSET
); // init with relation to (pos)
663 // p->cyclicBufferPos = 0; // smallest value
664 // p->son[0] = p->son[1] = 0; // unused: we can init skipped record for speculated accesses.
665 MatchFinder_SetLimits(p
);
670 // kEmptyHashValue must be zero
671 // #define SASUB_32(i) v = items[i]; m = v - subValue; if (v < subValue) m = kEmptyHashValue; items[i] = m;
672 //#define SASUB_32(i) v = items[i]; if (v < subValue) v = subValue; items[i] = v - subValue;
673 enum SASUB_32(string i
) = `v = items[`~i
~`]; if (v < subValue) v = subValue; items[`~i
~`] = v - subValue;`;
676 private void LzFind_SaturSub_32 (uint subValue
, CLzRef
* items
, const(CLzRef
)* lim
) @nogc {
690 while (items
!= lim
);
695 private void MatchFinder_Normalize3 (uint subValue
, CLzRef
* items
, usize numItems
) @nogc {
696 enum K_NORM_ALIGN_BLOCK_SIZE
= (1 << 6);
700 for (; numItems
!= 0 && (cast(uint)cast(ptrdiff_t
)items
& (K_NORM_ALIGN_BLOCK_SIZE
- 1)) != 0; numItems
--)
708 enum K_NORM_ALIGN_MASK
= (K_NORM_ALIGN_BLOCK_SIZE
/ 4 - 1);
709 lim
= items
+ (numItems
& ~cast(usize
)K_NORM_ALIGN_MASK
);
710 numItems
&= K_NORM_ALIGN_MASK
;
713 LzFind_SaturSub_32(subValue
, items
, lim
);
719 for (; numItems
!= 0; numItems
--)
729 // call MatchFinder_CheckLimits() only after (p->pos++) update
732 private void MatchFinder_CheckLimits (CMatchFinder
* p
) {
733 if (// !p->streamEndWasReached && p->result == SZ_OK &&
734 p
.keepSizeAfter
== mixin(Inline_MatchFinder_GetNumAvailableBytes
!"p"))
736 // we try to read only in exact state (p->keepSizeAfter == Inline_MatchFinder_GetNumAvailableBytes(p))
737 if (MatchFinder_NeedMove(p
))
738 MatchFinder_MoveBlock(p
);
739 MatchFinder_ReadBlock(p
);
742 if (p
.pos
== kMaxValForNormalize
)
743 if (mixin(Inline_MatchFinder_GetNumAvailableBytes
!"p") >= p
.numHashBytes
) // optional optimization for last bytes of data.
745 if we disable normalization for last bytes of data, and
746 if (data_size == 4 GiB), we don't call wastfull normalization,
747 but (pos) will be wrapped over Zero (0) in that case.
748 And we cannot resume later to normal operation
751 // MatchFinder_Normalize(p);
752 /* after normalization we need (p->pos >= p->historySize + 1); */
753 /* we can reduce subValue to aligned value, if want to keep alignment
754 of (p->pos) and (p->buffer) for speculated accesses. */
755 const uint subValue
= (p
.pos
- p
.historySize
- 1) /* & ~(uint)(kNormalizeAlign - 1) */;
756 // const uint subValue = (1 << 15); // for debug
757 // printf("\nMatchFinder_Normalize() subValue == 0x%x\n", subValue);
758 usize numSonRefs
= p
.cyclicBufferSize
;
762 //Inline_MatchFinder_ReduceOffsets(p, subValue);
764 p
.streamPos
-= subValue
;
766 MatchFinder_Normalize3(subValue
, p
.hash
, cast(usize
)p
.hashSizeSum
+ numSonRefs
);
769 if (p
.cyclicBufferPos
== p
.cyclicBufferSize
)
770 p
.cyclicBufferPos
= 0;
772 MatchFinder_SetLimits(p
);
780 private uint * Hc_GetMatchesSpec (usize lenLimit
, uint curMatch
, uint pos
, const(ubyte)* cur
, CLzRef
*son
,
781 usize _cyclicBufferPos
, uint _cyclicBufferSize
, uint cutValue
,
782 uint *d
, uint maxLen
) @nogc
785 son[_cyclicBufferPos] = curMatch;
788 uint delta = pos - curMatch;
789 if (cutValue-- == 0 || delta >= _cyclicBufferSize)
792 const ubyte *pb = cur - delta;
793 curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
794 if (pb[maxLen] == cur[maxLen] && *pb == *cur)
797 while (++len != lenLimit)
798 if (pb[len] != cur[len])
813 const(ubyte)* lim
= cur
+ lenLimit
;
814 son
[_cyclicBufferPos
] = curMatch
;
822 // if (curMatch2 >= curMatch) return null;
823 delta
= pos
- curMatch
;
824 if (delta
>= _cyclicBufferSize
)
828 curMatch
= son
[_cyclicBufferPos
- delta
+ ((delta
> _cyclicBufferPos
) ? _cyclicBufferSize
: 0)];
829 diff
= cast(ptrdiff_t
)0 - cast(ptrdiff_t
)delta
;
830 if (cur
[maxLen
] == cur
[cast(ptrdiff_t
)maxLen
+ diff
])
832 const(ubyte)* c
= cur
;
833 while (*c
== c
[diff
])
837 d
[0] = cast(uint)(lim
- cur
);
843 const uint len
= cast(uint)(c
- cur
);
847 d
[0] = cast(uint)len
;
862 private uint* GetMatchesSpec1 (uint lenLimit
, uint curMatch
, uint pos
, const(ubyte)* cur
, CLzRef
*son
,
863 usize _cyclicBufferPos
, uint _cyclicBufferSize
, uint cutValue
,
864 uint *d
, uint maxLen
) @nogc
866 CLzRef
*ptr0
= son
+ (cast(usize
)_cyclicBufferPos
<< 1) + 1;
867 CLzRef
*ptr1
= son
+ (cast(usize
)_cyclicBufferPos
<< 1);
868 uint len0
= 0, len1
= 0;
872 // if (curMatch >= pos) { *ptr0 = *ptr1 = kEmptyHashValue; return null; }
874 cmCheck
= cast(uint)(pos
- _cyclicBufferSize
);
875 if (cast(uint)pos
<= _cyclicBufferSize
)
878 if (cmCheck
< curMatch
)
881 const uint delta
= pos
- curMatch
;
883 CLzRef
*pair
= son
+ (cast(usize
)(_cyclicBufferPos
- delta
+ ((delta
> _cyclicBufferPos
) ? _cyclicBufferSize
: 0)) << 1);
884 const ubyte *pb
= cur
- delta
;
885 uint len
= (len0
< len1 ? len0
: len1
);
886 const uint pair0
= pair
[0];
887 if (pb
[len
] == cur
[len
])
889 if (++len
!= lenLimit
&& pb
[len
] == cur
[len
])
890 while (++len
!= lenLimit
)
891 if (pb
[len
] != cur
[len
])
895 maxLen
= cast(uint)len
;
896 *d
++ = cast(uint)len
;
906 if (pb
[len
] < cur
[len
])
909 // const uint curMatch2 = pair[1];
910 // if (curMatch2 >= curMatch) { *ptr0 = *ptr1 = kEmptyHashValue; return null; }
911 // curMatch = curMatch2;
925 while(--cutValue
&& cmCheck
< curMatch
);
927 *ptr0
= *ptr1
= kEmptyHashValue
;
932 private void SkipMatchesSpec (uint lenLimit
, uint curMatch
, uint pos
, const(ubyte)* cur
, CLzRef
*son
,
933 usize _cyclicBufferPos
, uint _cyclicBufferSize
, uint cutValue
) @nogc
935 CLzRef
*ptr0
= son
+ (cast(usize
)_cyclicBufferPos
<< 1) + 1;
936 CLzRef
*ptr1
= son
+ (cast(usize
)_cyclicBufferPos
<< 1);
937 uint len0
= 0, len1
= 0;
941 cmCheck
= cast(uint)(pos
- _cyclicBufferSize
);
942 if (cast(uint)pos
<= _cyclicBufferSize
)
945 if (// curMatch >= pos || // failure
949 const uint delta
= pos
- curMatch
;
951 CLzRef
*pair
= son
+ (cast(usize
)(_cyclicBufferPos
- delta
+ ((delta
> _cyclicBufferPos
) ? _cyclicBufferSize
: 0)) << 1);
952 const ubyte *pb
= cur
- delta
;
953 uint len
= (len0
< len1 ? len0
: len1
);
954 if (pb
[len
] == cur
[len
])
956 while (++len
!= lenLimit
)
957 if (pb
[len
] != cur
[len
])
968 if (pb
[len
] < cur
[len
])
984 while(--cutValue
&& cmCheck
< curMatch
);
986 *ptr0
= *ptr1
= kEmptyHashValue
;
994 { const uint pos1
= p
.pos
+ 1; p
.pos
= pos1
; if (pos1
== p
.posLimit
) MatchFinder_CheckLimits(p
); }
997 enum MOVE_POS_RET
= MOVE_POS
~`return distances;`;
1000 private void MatchFinder_MovePos (CMatchFinder
*p
) {
1001 pragma(inline
, true);
1002 /* we go here at the end of stream data, when (avail < num_hash_bytes)
1003 We don't update sons[cyclicBufferPos << btMode].
1004 So (sons) record will contain junk. And we cannot resume match searching
1005 to normal operation, even if we will provide more input data in buffer.
1006 p->sons[p->cyclicBufferPos << p->btMode] = 0; // kEmptyHashValue
1008 p->sons[(p->cyclicBufferPos << p->btMode) + 1] = 0; // kEmptyHashValue
1013 enum GET_MATCHES_HEADER2(string minLen
, string ret_op
) = `
1014 uint lenLimit; uint hv; ubyte *cur; uint curMatch;
1015 lenLimit = cast(uint)p.lenLimit; { if (lenLimit < `~minLen
~`) { MatchFinder_MovePos(p); `~ret_op
~`; } }
1019 enum GET_MATCHES_HEADER(string minLen
) = GET_MATCHES_HEADER2
!(minLen
, "return distances");
1020 //enum SKIP_HEADER(string minLen) = `do { `~GET_MATCHES_HEADER2!(minLen, "continue");
1021 enum SKIP_HEADER(string minLen
) = GET_MATCHES_HEADER2
!(minLen
, "continue");
1023 enum MF_PARAMS(string p
) = `lenLimit, curMatch, `~p
~`.pos, `~p
~`.buffer, `~p
~`.son, `~p
~`.cyclicBufferPos, `~p
~`.cyclicBufferSize, `~p
~`.cutValue`;
1025 //#define SKIP_FOOTER SkipMatchesSpec(MF_PARAMS(p)); mixin(MOVE_POS); } while (--num);
1026 enum SKIP_FOOTER
= `SkipMatchesSpec(`~MF_PARAMS
!"p"~`);`~MOVE_POS
;
1029 enum GET_MATCHES_FOOTER_BASE(string _maxLen_
, string func
) = `
1030 distances = `~func
~`(`~MF_PARAMS
!"p"~`, distances, cast(uint)`~_maxLen_
~`);`~MOVE_POS_RET
;
1032 enum GET_MATCHES_FOOTER_BT(string _maxLen_
) = GET_MATCHES_FOOTER_BASE
!(_maxLen_
, "GetMatchesSpec1");
1034 enum GET_MATCHES_FOOTER_HC(string _maxLen_
) = GET_MATCHES_FOOTER_BASE
!(_maxLen_
, "Hc_GetMatchesSpec");
1038 enum UPDATE_maxLen
= q
{
1039 const ptrdiff_t diff
= cast(ptrdiff_t
)0 - cast(ptrdiff_t
)d2
;
1040 const(ubyte)* c
= cur
+ maxLen
;
1041 const(ubyte)* lim
= cur
+ lenLimit
;
1042 for (; c
!= lim
; c
++) if (*(c
+ diff
) != *c
) break;
1043 maxLen
= cast(uint)(c
- cur
);
1047 private uint* Bt2_MatchFinder_GetMatches (CMatchFinder
* p
, uint* distances
) {
1048 mixin(GET_MATCHES_HEADER
!"2");
1050 curMatch
= p
.hash
[hv
];
1052 mixin(GET_MATCHES_FOOTER_BT
!"1");
1055 private uint* Bt3Zip_MatchFinder_GetMatches (CMatchFinder
* p
, uint* distances
) {
1056 mixin(GET_MATCHES_HEADER
!"3");
1057 mixin(HASH_ZIP_CALC
);
1058 curMatch
= p
.hash
[hv
];
1060 mixin(GET_MATCHES_FOOTER_BT
!"2");
1065 mmm
= p
.cyclicBufferSize
;
1066 if (pos
< mmm
) mmm
= pos
;
1070 private uint* Bt3_MatchFinder_GetMatches (CMatchFinder
* p
, uint* distances
) {
1075 mixin(GET_MATCHES_HEADER
!"3");
1082 d2
= pos
- hash
[h2
];
1084 curMatch
= (hash
+ kFix3HashSize
)[hv
];
1087 (hash
+ kFix3HashSize
)[hv
] = pos
;
1093 if (d2
< mmm
&& *(cur
- d2
) == *cur
)
1095 mixin(UPDATE_maxLen
);
1096 distances
[0] = cast(uint)maxLen
;
1097 distances
[1] = d2
- 1;
1099 if (maxLen
== lenLimit
)
1101 mixin(`SkipMatchesSpec(`~MF_PARAMS
!"p"~`);`);
1102 mixin(MOVE_POS_RET
);
1106 mixin(GET_MATCHES_FOOTER_BT
!"maxLen");
1110 private uint* Bt4_MatchFinder_GetMatches (CMatchFinder
* p
, uint* distances
) {
1112 uint h2
, h3
, d2
, d3
, pos
;
1115 mixin(GET_MATCHES_HEADER
!"4");
1122 d2
= pos
- hash
[h2
];
1123 d3
= pos
- (hash
+ kFix3HashSize
)[h3
];
1124 curMatch
= (hash
+ kFix4HashSize
)[hv
];
1127 (hash
+ kFix3HashSize
)[h3
] = pos
;
1128 (hash
+ kFix4HashSize
)[hv
] = pos
;
1136 if (d2
< mmm
&& *(cur
- d2
) == *cur
)
1139 distances
[1] = d2
- 1;
1141 if (*(cur
- d2
+ 2) == cur
[2])
1143 // distances[-2] = 3;
1145 else if (d3
< mmm
&& *(cur
- d3
) == *cur
)
1148 distances
[1] = d3
- 1;
1154 else if (d3
< mmm
&& *(cur
- d3
) == *cur
)
1157 distances
[1] = d3
- 1;
1163 mixin(UPDATE_maxLen
);
1164 distances
[-2] = cast(uint)maxLen
;
1165 if (maxLen
== lenLimit
)
1167 mixin(`SkipMatchesSpec(`~MF_PARAMS
!"p"~`);`);
1168 mixin(MOVE_POS_RET
);
1173 mixin(GET_MATCHES_FOOTER_BT
!"maxLen");
1177 private uint* Bt5_MatchFinder_GetMatches (CMatchFinder
* p
, uint* distances
) {
1179 uint h2
, h3
, d2
, d3
, maxLen
, pos
;
1181 mixin(GET_MATCHES_HEADER
!"5");
1188 d2
= pos
- hash
[h2
];
1189 d3
= pos
- (hash
+ kFix3HashSize
)[h3
];
1190 // d4 = pos - (hash + kFix4HashSize)[h4];
1192 curMatch
= (hash
+ kFix5HashSize
)[hv
];
1195 (hash
+ kFix3HashSize
)[h3
] = pos
;
1196 // (hash + kFix4HashSize)[h4] = pos;
1197 (hash
+ kFix5HashSize
)[hv
] = pos
;
1205 if (d2
< mmm
&& *(cur
- d2
) == *cur
)
1208 distances
[1] = d2
- 1;
1210 if (*(cur
- d2
+ 2) == cur
[2])
1213 else if (d3
< mmm
&& *(cur
- d3
) == *cur
)
1215 distances
[1] = d3
- 1;
1222 else if (d3
< mmm
&& *(cur
- d3
) == *cur
)
1224 distances
[1] = d3
- 1;
1232 if (*(cur
- d2
+ 3) != cur
[3])
1234 mixin(UPDATE_maxLen
);
1235 distances
[-2] = cast(uint)maxLen
;
1236 if (maxLen
== lenLimit
)
1238 mixin(`SkipMatchesSpec(`~MF_PARAMS
!"p"~`);`);
1239 mixin(MOVE_POS_RET
);
1244 mixin(GET_MATCHES_FOOTER_BT
!"maxLen");
1248 private uint* Hc4_MatchFinder_GetMatches (CMatchFinder
* p
, uint* distances
) {
1250 uint h2
, h3
, d2
, d3
, pos
;
1253 mixin(GET_MATCHES_HEADER
!"4");
1260 d2
= pos
- hash
[h2
];
1261 d3
= pos
- (hash
+ kFix3HashSize
)[h3
];
1262 curMatch
= (hash
+ kFix4HashSize
)[hv
];
1265 (hash
+ kFix3HashSize
)[h3
] = pos
;
1266 (hash
+ kFix4HashSize
)[hv
] = pos
;
1274 if (d2
< mmm
&& *(cur
- d2
) == *cur
)
1277 distances
[1] = d2
- 1;
1279 if (*(cur
- d2
+ 2) == cur
[2])
1281 // distances[-2] = 3;
1283 else if (d3
< mmm
&& *(cur
- d3
) == *cur
)
1286 distances
[1] = d3
- 1;
1292 else if (d3
< mmm
&& *(cur
- d3
) == *cur
)
1295 distances
[1] = d3
- 1;
1301 mixin(UPDATE_maxLen
);
1302 distances
[-2] = cast(uint)maxLen
;
1303 if (maxLen
== lenLimit
)
1305 p
.son
[p
.cyclicBufferPos
] = curMatch
;
1306 mixin(MOVE_POS_RET
);
1311 mixin(GET_MATCHES_FOOTER_HC
!"maxLen");
1315 private uint *Hc5_MatchFinder_GetMatches (CMatchFinder
* p
, uint* distances
) {
1317 uint h2
, h3
, d2
, d3
, maxLen
, pos
;
1319 mixin(GET_MATCHES_HEADER
!"5");
1326 d2
= pos
- hash
[h2
];
1327 d3
= pos
- (hash
+ kFix3HashSize
)[h3
];
1328 // d4 = pos - (hash + kFix4HashSize)[h4];
1330 curMatch
= (hash
+ kFix5HashSize
)[hv
];
1333 (hash
+ kFix3HashSize
)[h3
] = pos
;
1334 // (hash + kFix4HashSize)[h4] = pos;
1335 (hash
+ kFix5HashSize
)[hv
] = pos
;
1343 if (d2
< mmm
&& *(cur
- d2
) == *cur
)
1346 distances
[1] = d2
- 1;
1348 if (*(cur
- d2
+ 2) == cur
[2])
1351 else if (d3
< mmm
&& *(cur
- d3
) == *cur
)
1353 distances
[1] = d3
- 1;
1360 else if (d3
< mmm
&& *(cur
- d3
) == *cur
)
1362 distances
[1] = d3
- 1;
1370 if (*(cur
- d2
+ 3) != cur
[3])
1372 mixin(UPDATE_maxLen
);
1373 distances
[-2] = maxLen
;
1374 if (maxLen
== lenLimit
)
1376 p
.son
[p
.cyclicBufferPos
] = curMatch
;
1377 mixin(MOVE_POS_RET
);
1382 mixin(GET_MATCHES_FOOTER_HC
!"maxLen");
1386 private uint* Hc3Zip_MatchFinder_GetMatches (CMatchFinder
* p
, uint* distances
) {
1387 mixin(GET_MATCHES_HEADER
!"3");
1388 mixin(HASH_ZIP_CALC
);
1389 curMatch
= p
.hash
[hv
];
1391 mixin(GET_MATCHES_FOOTER_HC
!"2");
1395 private void Bt2_MatchFinder_Skip (CMatchFinder
* p
, uint num
) {
1396 do { mixin(SKIP_HEADER
!"2");
1399 curMatch
= p
.hash
[hv
];
1402 mixin(SKIP_FOOTER
); } while (--num
);
1405 private void Bt3Zip_MatchFinder_Skip (CMatchFinder
* p
, uint num
) {
1406 do { mixin(SKIP_HEADER
!"3");
1408 mixin(HASH_ZIP_CALC
);
1409 curMatch
= p
.hash
[hv
];
1412 mixin(SKIP_FOOTER
); } while (--num
);
1415 private void Bt3_MatchFinder_Skip (CMatchFinder
* p
, uint num
) {
1416 do { mixin(SKIP_HEADER
!"3");
1422 curMatch
= (hash
+ kFix3HashSize
)[hv
];
1424 (hash
+ kFix3HashSize
)[hv
] = p
.pos
;
1426 mixin(SKIP_FOOTER
); } while (--num
);
1429 private void Bt4_MatchFinder_Skip (CMatchFinder
* p
, uint num
) {
1430 do { mixin(SKIP_HEADER
!"4");
1436 curMatch
= (hash
+ kFix4HashSize
)[hv
];
1438 (hash
+ kFix3HashSize
)[h3
] =
1439 (hash
+ kFix4HashSize
)[hv
] = p
.pos
;
1441 mixin(SKIP_FOOTER
); } while (--num
);
1444 private void Bt5_MatchFinder_Skip (CMatchFinder
* p
, uint num
) {
1445 do { mixin(SKIP_HEADER
!"5");
1451 curMatch
= (hash
+ kFix5HashSize
)[hv
];
1453 (hash
+ kFix3HashSize
)[h3
] =
1454 // (hash + kFix4HashSize)[h4] =
1455 (hash
+ kFix5HashSize
)[hv
] = p
.pos
;
1457 mixin(SKIP_FOOTER
); } while (--num
);
1461 private void Hc4_MatchFinder_Skip (CMatchFinder
* p
, uint num
) {
1463 do { if (p
.lenLimit
< minLenSKH
) { MatchFinder_MovePos(p
); num
--; continue; } {
1469 /* (p->pos == p->posLimit) is not allowed here !!! */
1470 { const uint rem
= p
.posLimit
- pos
; if (num2
> rem
) num2
= rem
; }
1472 { const uint cycPos
= p
.cyclicBufferPos
;
1473 son
= p
.son
+ cycPos
;
1474 p
.cyclicBufferPos
= cycPos
+ num2
; }
1483 curMatch
= (hash
+ kFix4HashSize
)[hv
];
1485 (hash
+ kFix3HashSize
)[h3
] =
1486 (hash
+ kFix4HashSize
)[hv
] = pos
;
1489 cur
++; pos
++; *son
++ = curMatch
;
1493 if (pos
== p
.posLimit
) MatchFinder_CheckLimits(p
);
1498 private void Hc5_MatchFinder_Skip (CMatchFinder
* p
, uint num
) {
1500 do { if (p
.lenLimit
< minLenSKH
) { MatchFinder_MovePos(p
); num
--; continue; } {
1506 /* (p->pos == p->posLimit) is not allowed here !!! */
1507 { const uint rem
= p
.posLimit
- pos
; if (num2
> rem
) num2
= rem
; }
1509 { const uint cycPos
= p
.cyclicBufferPos
;
1510 son
= p
.son
+ cycPos
;
1511 p
.cyclicBufferPos
= cycPos
+ num2
; }
1520 curMatch
= (hash
+ kFix5HashSize
)[hv
];
1522 (hash
+ kFix3HashSize
)[h3
] =
1523 // (hash + kFix4HashSize)[h4] =
1524 (hash
+ kFix5HashSize
)[hv
] = pos
;
1527 cur
++; pos
++; *son
++ = curMatch
;
1531 if (pos
== p
.posLimit
) MatchFinder_CheckLimits(p
);
1536 private void Hc3Zip_MatchFinder_Skip (CMatchFinder
* p
, uint num
) {
1538 do { if (p
.lenLimit
< minLenSKH
) { MatchFinder_MovePos(p
); num
--; continue; } {
1544 /* (p->pos == p->posLimit) is not allowed here !!! */
1545 { const uint rem
= p
.posLimit
- pos
; if (num2
> rem
) num2
= rem
; }
1547 { const uint cycPos
= p
.cyclicBufferPos
;
1548 son
= p
.son
+ cycPos
;
1549 p
.cyclicBufferPos
= cycPos
+ num2
; }
1556 mixin(HASH_ZIP_CALC
);
1557 curMatch
= hash
[hv
];
1561 cur
++; pos
++; *son
++ = curMatch
;
1565 if (pos
== p
.posLimit
) MatchFinder_CheckLimits(p
);
1570 private void MatchFinder_CreateVTable (CMatchFinder
* p
, IMatchFinder2
* vTable
) @nogc {
1571 vTable
.Init
= cast(Mf_Init_Func
)&MatchFinder_Init
;
1572 vTable
.GetNumAvailableBytes
= cast(Mf_GetNumAvailableBytes_Func
)&MatchFinder_GetNumAvailableBytes
;
1573 vTable
.GetPointerToCurrentPos
= cast(Mf_GetPointerToCurrentPos_Func
)&MatchFinder_GetPointerToCurrentPos
;
1576 if (p
.numHashBytes
<= 4)
1578 vTable
.GetMatches
= cast(Mf_GetMatches_Func
)&Hc4_MatchFinder_GetMatches
;
1579 vTable
.Skip
= cast(Mf_Skip_Func
)&Hc4_MatchFinder_Skip
;
1583 vTable
.GetMatches
= cast(Mf_GetMatches_Func
)&Hc5_MatchFinder_GetMatches
;
1584 vTable
.Skip
= cast(Mf_Skip_Func
)&Hc5_MatchFinder_Skip
;
1587 else if (p
.numHashBytes
== 2)
1589 vTable
.GetMatches
= cast(Mf_GetMatches_Func
)&Bt2_MatchFinder_GetMatches
;
1590 vTable
.Skip
= cast(Mf_Skip_Func
)&Bt2_MatchFinder_Skip
;
1592 else if (p
.numHashBytes
== 3)
1594 vTable
.GetMatches
= cast(Mf_GetMatches_Func
)&Bt3_MatchFinder_GetMatches
;
1595 vTable
.Skip
= cast(Mf_Skip_Func
)&Bt3_MatchFinder_Skip
;
1597 else if (p
.numHashBytes
== 4)
1599 vTable
.GetMatches
= cast(Mf_GetMatches_Func
)&Bt4_MatchFinder_GetMatches
;
1600 vTable
.Skip
= cast(Mf_Skip_Func
)&Bt4_MatchFinder_Skip
;
1604 vTable
.GetMatches
= cast(Mf_GetMatches_Func
)&Bt5_MatchFinder_GetMatches
;
1605 vTable
.Skip
= cast(Mf_Skip_Func
)&Bt5_MatchFinder_Skip
;
1610 private void LzFindPrepare () @nogc {
1614 // ////////////////////////////////////////////////////////////////////////// //
1615 // ////////////////////////////////////////////////////////////////////////// //
1616 // ////////////////////////////////////////////////////////////////////////// //
1617 // ////////////////////////////////////////////////////////////////////////// //
1618 /* for good normalization speed we still reserve 256 MB before 4 GB range */
1619 enum kLzmaMaxHistorySize
= (cast(uint)15 << 28);
1621 enum kNumTopBits
= 24;
1622 enum kTopValue
= (cast(uint)1 << kNumTopBits
);
1624 enum kNumBitModelTotalBits
= 11;
1625 enum kBitModelTotal
= (1 << kNumBitModelTotalBits
);
1626 enum kNumMoveBits
= 5;
1627 enum kProbInitValue
= (kBitModelTotal
>> 1);
1629 enum kNumMoveReducingBits
= 4;
1630 enum kNumBitPriceShiftBits
= 4;
1631 // #define kBitPrice (1 << kNumBitPriceShiftBits)
1633 enum REP_LEN_COUNT
= 64;
1636 //==========================================================================
1638 // LzmaEncProps_Init
1640 //==========================================================================
1641 public void LzmaEncProps_Init (CLzmaEncProps
* p
) @nogc {
1643 p
.dictSize
= p
.mc
= 0;
1644 p
.reduceSize
= cast(ulong)cast(long)-1;
1645 p
.lc
= p
.lp
= p
.pb
= p
.algo
= p
.fb
= p
.btMode
= p
.numHashBytes
= -1;
1650 //==========================================================================
1652 // LzmaEncProps_Normalize
1654 //==========================================================================
1655 public void LzmaEncProps_Normalize (CLzmaEncProps
* p
) @nogc {
1656 int level
= p
.level
;
1657 if (level
< 0) level
= 5;
1660 if (p
.dictSize
== 0)
1662 ( level
<= 3 ?
(cast(uint)1 << (level
* 2 + 16)) :
1663 ( level
<= 6 ?
(cast(uint)1 << (level
+ 19)) :
1664 ( level
<= 7 ?
(cast(uint)1 << 25) : (cast(uint)1 << 26)
1667 if (p
.dictSize
> p
.reduceSize
)
1669 uint v
= cast(uint)p
.reduceSize
;
1670 const uint kReduceMin
= (cast(uint)1 << 12);
1677 if (p
.lc
< 0) p
.lc
= 3;
1678 if (p
.lp
< 0) p
.lp
= 0;
1679 if (p
.pb
< 0) p
.pb
= 2;
1681 if (p
.algo
< 0) p
.algo
= (level
< 5 ?
0 : 1);
1682 if (p
.fb
< 0) p
.fb
= (level
< 7 ?
32 : 64);
1683 if (p
.btMode
< 0) p
.btMode
= (p
.algo
== 0 ?
0 : 1);
1684 if (p
.numHashBytes
< 0) p
.numHashBytes
= (p
.btMode ?
4 : 5);
1685 if (p
.mc
== 0) p
.mc
= (16 + (cast(uint)p
.fb
>> 1)) >> (p
.btMode ?
0 : 1);
1689 //==========================================================================
1691 // LzmaEncProps_GetDictSize
1693 //==========================================================================
1694 public uint LzmaEncProps_GetDictSize (const(CLzmaEncProps
)* props2
) @nogc {
1695 CLzmaEncProps props
= *props2
;
1696 LzmaEncProps_Normalize(&props
);
1697 return props
.dictSize
;
1705 IF (SRC == 0) ZF = 1, DEST is undefined;
1706 AMD : DEST is unchanged;
1707 IF (SRC != 0) ZF = 0; DEST is index of top non-zero bit
1708 BSR is slow in some processors
1711 IF (SRC == 0) CF = 1, DEST is size_in_bits_of_register(src) (32 or 64)
1712 IF (SRC != 0) CF = 0, DEST = num_lead_zero_bits
1713 IF (DEST == 0) ZF = 1;
1715 LZCNT works only in new processors starting from Haswell.
1716 if LZCNT is not supported by processor, then it's executed as BSR.
1717 LZCNT can be faster than BSR, if supported.
1721 //k8: define this for ARM (for some reason)
1722 // #define LZMA_LOG_BSR
1727 C code: : (30 - __builtin_clz(x))
1728 gcc9/gcc10 for x64 /x86 : 30 - (bsr(x) xor 31)
1729 clang10 for x64 : 31 + (bsr(x) xor -32)
1732 #define MY_clz(x) ((uint)__builtin_clz(x))
1734 // __builtin_ia32_lzcnt_u32
1739 #define BSR2_RET(pos, res) { uint zz = 30 - MY_clz(pos); \
1740 res = (zz + zz) + (pos >> zz); }
1745 uint GetPosSlot1(uint pos);
1746 uint GetPosSlot1(uint pos)
1752 #define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
1753 #define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
1756 #else // ! LZMA_LOG_BSR
1759 enum kNumLogBits
= (11 + usize
.sizeof
/ 8 * 3);
1761 enum kDicLogSizeMaxCompress
= ((kNumLogBits
- 1) * 2 + 7);
1763 private void LzmaEnc_FastPosInit (ubyte* g_FastPos
) @nogc {
1769 for (slot
= 2; slot
< kNumLogBits
* 2; slot
++)
1771 usize k
= (cast(usize
)1 << ((slot
>> 1) - 1));
1773 for (j
= 0; j
< k
; j
++)
1774 g_FastPos
[j
] = cast(ubyte)slot
;
1779 /* we can use ((limit - pos) >> 31) only if (pos < ((uint)1 << 31)) */
1781 #define BSR2_RET(pos, res) { uint zz = 6 + ((kNumLogBits - 1) & \
1782 (0 - (((((uint)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
1783 res = p->g_FastPos[pos >> zz] + (zz * 2); }
1787 #define BSR2_RET(pos, res) { uint zz = 6 + ((kNumLogBits - 1) & \
1788 (0 - (((((uint)1 << (kNumLogBits)) - 1) - (pos >> 6)) >> 31))); \
1789 res = p->g_FastPos[pos >> zz] + (zz * 2); }
1792 enum BSR2_RET(string pos
, string res
) = `
1793 { uint zz = (`~pos
~` < (1 << (kNumLogBits + 6))) ? 6 : 6 + kNumLogBits - 1;
1794 `~res
~` = p.g_FastPos[`~pos
~` >> zz] + (zz * 2); }
1798 #define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
1799 p->g_FastPos[pos >> 6] + 12 : \
1800 p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
1803 enum GetPosSlot1(string pos
) = `p.g_FastPos[`~pos
~`]`;
1805 enum GetPosSlot2(string pos
, string res
) = BSR2_RET
!(pos
, res
);
1807 enum GetPosSlot(string pos
, string res
) = `{
1808 if (`~pos
~` < kNumFullDistances) `~res
~` = p.g_FastPos[`~pos
~` & (kNumFullDistances - 1)];
1809 else {`~BSR2_RET
!(pos
, res
)~`}
1812 //#endif // LZMA_LOG_BSR
1815 enum LZMA_NUM_REPS
= 4;
1817 alias CState
= ushort;
1818 alias CExtra
= ushort;
1826 // > 1 : MATCH (extra-1) : LIT : REP0 (len)
1829 uint[LZMA_NUM_REPS
] reps
;
1834 enum kNumOpts
= (1 << 11);
1835 enum kPackReserve
= (kNumOpts
* 8);
1836 // #define kNumOpts (1 << 12)
1837 // #define kPackReserve (1 + kNumOpts * 2)
1839 enum kNumLenToPosStates
= 4;
1840 enum kNumPosSlotBits
= 6;
1841 // #define kDicLogSizeMin 0
1842 enum kDicLogSizeMax
= 32;
1843 enum kDistTableSizeMax
= (kDicLogSizeMax
* 2);
1845 enum kNumAlignBits
= 4;
1846 enum kAlignTableSize
= (1 << kNumAlignBits
);
1847 enum kAlignMask
= (kAlignTableSize
- 1);
1849 enum kStartPosModelIndex
= 4;
1850 enum kEndPosModelIndex
= 14;
1851 enum kNumFullDistances
= (1 << (kEndPosModelIndex
>> 1));
1853 enum LZMA_PB_MAX
= 4;
1854 enum LZMA_LC_MAX
= 8;
1855 enum LZMA_LP_MAX
= 4;
1857 enum LZMA_NUM_PB_STATES_MAX
= (1 << LZMA_PB_MAX
);
1859 enum kLenNumLowBits
= 3;
1860 enum kLenNumLowSymbols
= (1 << kLenNumLowBits
);
1861 enum kLenNumHighBits
= 8;
1862 enum kLenNumHighSymbols
= (1 << kLenNumHighBits
);
1863 enum kLenNumSymbolsTotal
= (kLenNumLowSymbols
* 2 + kLenNumHighSymbols
);
1865 enum LZMA_MATCH_LEN_MIN
= 2;
1866 enum LZMA_MATCH_LEN_MAX
= (LZMA_MATCH_LEN_MIN
+ kLenNumSymbolsTotal
- 1);
1868 enum kNumStates
= 12;
1872 CLzmaProb
[LZMA_NUM_PB_STATES_MAX
<< (kLenNumLowBits
+ 1)] low
;
1873 CLzmaProb
[kLenNumHighSymbols
] high
;
1877 struct CLenPriceEnc
{
1879 uint[kLenNumSymbolsTotal
][LZMA_NUM_PB_STATES_MAX
] prices
;
1880 // uint prices1[LZMA_NUM_PB_STATES_MAX][kLenNumLowSymbols * 2];
1881 // uint prices2[kLenNumSymbolsTotal];
1884 enum GET_PRICE_LEN(string p
, string posState
, string len
) =
1885 `((`~p
~`).prices[`~posState
~`][cast(usize)(`~len
~`) - LZMA_MATCH_LEN_MIN])`;
1888 #define GET_PRICE_LEN(p, posState, len) \
1889 ((p)->prices2[(usize)(len) - 2] + ((p)->prices1[posState][((len) - 2) & (kLenNumLowSymbols * 2 - 1)] & (((len) - 2 - kLenNumLowSymbols * 2) >> 9)))
1900 ISeqOutStream
*outStream
;
1907 CLzmaProb
*litProbs
;
1910 uint[LZMA_NUM_REPS
] reps
;
1912 CLzmaProb
[1 << kNumAlignBits
] posAlignEncoder
;
1913 CLzmaProb
[kNumStates
] isRep
;
1914 CLzmaProb
[kNumStates
] isRepG0
;
1915 CLzmaProb
[kNumStates
] isRepG1
;
1916 CLzmaProb
[kNumStates
] isRepG2
;
1917 CLzmaProb
[LZMA_NUM_PB_STATES_MAX
][kNumStates
] isMatch
;
1918 CLzmaProb
[LZMA_NUM_PB_STATES_MAX
][kNumStates
] isRep0Long
;
1920 CLzmaProb
[1 << kNumPosSlotBits
][kNumLenToPosStates
] posSlotEncoder
;
1921 CLzmaProb
[kNumFullDistances
] posEncoders
;
1924 CLenEnc repLenProbs
;
1928 alias CProbPrice
= uint;
1929 alias BoolInt
= int;
1933 void *matchFinderObj
;
1934 IMatchFinder2 matchFinder
;
1939 uint longestMatchLen
;
1945 uint additionalOffset
;
1946 uint[LZMA_NUM_REPS
] reps
;
1947 uint lpMask
, pbMask
;
1948 CLzmaProb
*litProbs
;
1957 BoolInt writeEndMark
;
1959 BoolInt multiThread
;
1961 // BoolInt _maxMode;
1965 uint matchPriceCount
;
1966 // uint alignPriceCount;
1967 int repLenEncCounter
;
1974 CMatchFinder matchFinderBase
;
1977 // we suppose that we have 8-bytes alignment after CMatchFinder
1980 CProbPrice
[kBitModelTotal
>> kNumMoveReducingBits
] ProbPrices
;
1982 // we want {len , dist} pairs to be 8-bytes aligned in matches array
1983 uint[LZMA_MATCH_LEN_MAX
* 2 + 2] matches
;
1985 // we want 8-bytes alignment here
1986 uint[kAlignTableSize
] alignPrices
;
1987 uint[kDistTableSizeMax
][kNumLenToPosStates
] posSlotPrices
;
1988 uint[kNumFullDistances
][kNumLenToPosStates
] distancesPrices
;
1990 CLzmaProb
[1 << kNumAlignBits
] posAlignEncoder
;
1991 CLzmaProb
[kNumStates
] isRep
;
1992 CLzmaProb
[kNumStates
] isRepG0
;
1993 CLzmaProb
[kNumStates
] isRepG1
;
1994 CLzmaProb
[kNumStates
] isRepG2
;
1995 CLzmaProb
[LZMA_NUM_PB_STATES_MAX
][kNumStates
] isMatch
;
1996 CLzmaProb
[LZMA_NUM_PB_STATES_MAX
][kNumStates
] isRep0Long
;
1997 CLzmaProb
[1 << kNumPosSlotBits
][kNumLenToPosStates
] posSlotEncoder
;
1998 CLzmaProb
[kNumFullDistances
] posEncoders
;
2001 CLenEnc repLenProbs
;
2003 //#ifndef LZMA_LOG_BSR
2004 ubyte[1 << kNumLogBits
] g_FastPos
;
2007 CLenPriceEnc lenEnc
;
2008 CLenPriceEnc repLenEnc
;
2010 COptimal
[kNumOpts
] opt
;
2012 CSaveState saveState
;
2014 // BoolInt mf_Failure;
2018 //#define MFB (p.matchFinderBase)
2021 //==========================================================================
2025 //==========================================================================
2026 public SRes
LzmaEnc_SetProps (CLzmaEncHandle pp
, const(CLzmaEncProps
)* props2
) @nogc {
2027 CLzmaEnc
*p
= cast(CLzmaEnc
*)pp
;
2028 CLzmaEncProps props
= *props2
;
2029 LzmaEncProps_Normalize(&props
);
2031 if (props
.lc
> LZMA_LC_MAX
2032 || props
.lp
> LZMA_LP_MAX
2033 || props
.pb
> LZMA_PB_MAX
)
2034 return SZ_ERROR_PARAM
;
2037 if (props
.dictSize
> kLzmaMaxHistorySize
)
2038 props
.dictSize
= kLzmaMaxHistorySize
;
2040 //#ifndef LZMA_LOG_BSR
2042 const ulong dict64
= props
.dictSize
;
2043 if (dict64
> (cast(ulong)1 << kDicLogSizeMaxCompress
))
2044 return SZ_ERROR_PARAM
;
2048 p
.dictSize
= props
.dictSize
;
2050 uint fb
= cast(uint)props
.fb
;
2053 if (fb
> LZMA_MATCH_LEN_MAX
)
2054 fb
= LZMA_MATCH_LEN_MAX
;
2055 p
.numFastBytes
= fb
;
2057 p
.lc
= cast(uint)props
.lc
;
2058 p
.lp
= cast(uint)props
.lp
;
2059 p
.pb
= cast(uint)props
.pb
;
2060 p
.fastMode
= (props
.algo
== 0);
2061 // p->_maxMode = True;
2062 (p
.matchFinderBase
).btMode
= cast(ubyte)(props
.btMode ?
1 : 0);
2064 uint numHashBytes
= 4;
2067 if (props
.numHashBytes
< 2) numHashBytes
= 2;
2068 else if (props
.numHashBytes
< 4) numHashBytes
= cast(uint)props
.numHashBytes
;
2070 if (props
.numHashBytes
>= 5) numHashBytes
= 5;
2072 (p
.matchFinderBase
).numHashBytes
= numHashBytes
;
2075 (p
.matchFinderBase
).cutValue
= props
.mc
;
2077 p
.writeEndMark
= cast(BoolInt
)props
.writeEndMark
;
2083 //==========================================================================
2085 // LzmaEnc_SetDataSize
2087 //==========================================================================
2088 public void LzmaEnc_SetDataSize (CLzmaEncHandle pp
, ulong expectedDataSiize
) @nogc {
2089 CLzmaEnc
*p
= cast(CLzmaEnc
*)pp
;
2090 (p
.matchFinderBase
).expectedDataSize
= expectedDataSiize
;
2094 enum kState_Start
= 0;
2095 enum kState_LitAfterMatch
= 4;
2096 enum kState_LitAfterRep
= 5;
2097 enum kState_MatchAfterLit
= 7;
2098 enum kState_RepAfterLit
= 8;
2100 immutable ubyte[kNumStates
] kLiteralNextStates
= [0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5];
2101 immutable ubyte[kNumStates
] kMatchNextStates
= [7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10];
2102 immutable ubyte[kNumStates
] kRepNextStates
= [8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11];
2103 immutable ubyte[kNumStates
] kShortRepNextStates
= [9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11];
2105 enum IsLitState(string s
) = `((`~s
~`) < 7)`;
2106 enum GetLenToPosState2(string len
) = `(((`~len
~`) < kNumLenToPosStates - 1) ? (`~len
~`) : kNumLenToPosStates - 1)`;
2107 enum GetLenToPosState(string len
) = `(((`~len
~`) < kNumLenToPosStates + 1) ? (`~len
~`) - 2 : kNumLenToPosStates - 1)`;
2109 enum kInfinityPrice
= (1 << 30);
2111 private void RangeEnc_Construct (CRangeEnc
* p
) @nogc {
2116 enum RangeEnc_GetProcessed(string p
) = `((`~p
~`).processed + cast(usize)((`~p
~`).buf - (`~p
~`).bufBase) + (`~p
~`).cacheSize)`;
2117 enum RangeEnc_GetProcessed_sizet(string p
) = `(cast(usize)(`~p
~`).processed + cast(usize)((`~p
~`).buf - (`~p
~`).bufBase) + cast(usize)(`~p
~`).cacheSize)`;
2119 enum RC_BUF_SIZE
= (1 << 16);
2121 private int RangeEnc_Alloc (CRangeEnc
*p
, ISzAllocPtr alloc
) {
2124 p
.bufBase
= cast(ubyte *)ISzAlloc_Alloc(alloc
, RC_BUF_SIZE
);
2127 p
.bufLim
= p
.bufBase
+ RC_BUF_SIZE
;
2132 private void RangeEnc_Free (CRangeEnc
*p
, ISzAllocPtr alloc
) {
2133 ISzAlloc_Free(alloc
, p
.bufBase
);
2138 private void RangeEnc_Init (CRangeEnc
* p
) @nogc {
2139 /* Stream.Init(); */
2140 p
.range
= 0xFFFFFFFF;
2152 private void RangeEnc_FlushStream (CRangeEnc
* p
) {
2154 if (p
.res
!= SZ_OK
) {
2155 //k8: the following code line was absent, and it looks like
2156 //k8: the encoder could perform OOB writes on some incompressible data.
2157 //k8: most of the time it is harmless, but it's still a bug.
2161 num
= cast(usize
)(p
.buf
- p
.bufBase
);
2164 if (num != ISeqOutStream_Write(p.outStream, p.bufBase, num))
2165 p.res = SZ_ERROR_WRITE;
2167 if (num
&& p
.outStream
.Write(p
.outStream
, p
.bufBase
, num
) != num
) p
.res
= SZ_ERROR_WRITE
;
2174 private void RangeEnc_ShiftLow(CRangeEnc
*p
)
2176 uint low
= cast(uint)p
.low
;
2177 uint high
= cast(uint)(p
.low
>> 32);
2178 p
.low
= cast(uint)(low
<< 8);
2179 if (low
< cast(uint)0xFF000000 || high
!= 0)
2183 *buf
++ = cast(ubyte)(p
.cache
+ high
);
2184 p
.cache
= cast(uint)(low
>> 24);
2186 if (buf
== p
.bufLim
)
2187 RangeEnc_FlushStream(p
);
2188 if (p
.cacheSize
== 0)
2195 *buf
++ = cast(ubyte)(high
);
2197 if (buf
== p
.bufLim
)
2198 RangeEnc_FlushStream(p
);
2199 if (--p
.cacheSize
== 0)
2206 private void RangeEnc_FlushData(CRangeEnc
*p
)
2209 for (i
= 0; i
< 5; i
++)
2210 RangeEnc_ShiftLow(p
);
2213 enum RC_NORM(string p
) = `if (range < kTopValue) { range <<= 8; RangeEnc_ShiftLow(`~p
~`); }`;
2215 enum RC_BIT_PRE(string p
, string prob
) = `
2217 newBound = (range >> kNumBitModelTotalBits) * ttt;
2220 // #define LZMA_ENC_USE_BRANCH
2222 version(LZMA_ENC_USE_BRANCH
) {
2224 enum RC_BIT(string p
, string prob
, string bit
) = `{
2225 `~RC_BIT_PRE
!(p
, prob
)~`
2226 if (`~bit
~` == 0) { range = newBound; ttt += (kBitModelTotal - ttt) >> kNumMoveBits; }
2227 else { (`~p
~`).low += newBound; range -= newBound; ttt -= ttt >> kNumMoveBits; }
2228 *(`~prob
~`) = cast(CLzmaProb)ttt;
2235 enum RC_BIT(string p
, string prob
, string bit
) = `{
2237 `~RC_BIT_PRE
!(p
, prob
)~`
2238 mask = 0 - cast(uint)`~bit
~`;
2242 (`~p
~`).low += mask;
2243 mask = cast(uint)`~bit
~` - 1;
2244 range += newBound & mask;
2245 mask &= (kBitModelTotal - ((1 << kNumMoveBits) - 1));
2246 mask += ((1 << kNumMoveBits) - 1);
2247 ttt += cast(uint)(cast(int)(mask - ttt) >> kNumMoveBits);
2248 *(`~prob
~`) = cast(CLzmaProb)ttt;
2256 enum RC_BIT_0_BASE(string p
, string prob
) =
2257 `range = newBound; *(`~prob
~`) = cast(CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));`;
2259 enum RC_BIT_1_BASE(string p
, string prob
) =
2260 `range -= newBound; (`~p
~`).low += newBound; *(`~prob
~`) = cast(CLzmaProb)(ttt - (ttt >> kNumMoveBits));`;
2262 enum RC_BIT_0(string p
, string prob
) =
2263 RC_BIT_0_BASE
!(p
, prob
)~
2266 enum RC_BIT_1(string p
, string prob
) =
2267 RC_BIT_1_BASE
!(p
, prob
)~
2270 private void RangeEnc_EncodeBit_0(CRangeEnc
*p
, CLzmaProb
*prob
)
2272 uint range
, ttt
, newBound
;
2274 mixin(RC_BIT_PRE
!("p", "prob"));
2275 mixin(RC_BIT_0
!("p", "prob"));
2279 private void LitEnc_Encode(CRangeEnc
*p
, CLzmaProb
*probs
, uint sym
)
2281 uint range
= p
.range
;
2286 // RangeEnc_EncodeBit(p, probs + (sym >> 8), (sym >> 7) & 1);
2287 CLzmaProb
*prob
= probs
+ (sym
>> 8);
2288 uint bit
= (sym
>> 7) & 1;
2290 mixin(RC_BIT
!("p", "prob", "bit"));
2292 while (sym
< 0x10000);
2296 private void LitEnc_EncodeMatched(CRangeEnc
*p
, CLzmaProb
*probs
, uint sym
, uint matchByte
)
2298 uint range
= p
.range
;
2307 // RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (sym >> 8)), (sym >> 7) & 1);
2308 prob
= probs
+ (offs
+ (matchByte
& offs
) + (sym
>> 8));
2309 bit
= (sym
>> 7) & 1;
2311 offs
&= ~(matchByte ^ sym
);
2312 mixin(RC_BIT
!("p", "prob", "bit"));
2314 while (sym
< 0x10000);
2320 private void LzmaEnc_InitPriceTables(CProbPrice
*ProbPrices
)
2323 for (i
= 0; i
< (kBitModelTotal
>> kNumMoveReducingBits
); i
++)
2325 const uint kCyclesBits
= kNumBitPriceShiftBits
;
2326 uint w
= (i
<< kNumMoveReducingBits
) + (1 << (kNumMoveReducingBits
- 1));
2329 for (j
= 0; j
< kCyclesBits
; j
++)
2333 while (w
>= (cast(uint)1 << 16))
2339 ProbPrices
[i
] = cast(CProbPrice
)((cast(uint)kNumBitModelTotalBits
<< kCyclesBits
) - 15 - bitCount
);
2340 // printf("\n%3d: %5d", i, ProbPrices[i]);
2345 enum GET_PRICE(string prob
, string bit
) =
2346 `p.ProbPrices[((`~prob
~`) ^ cast(uint)(((-cast(int)(`~bit
~`))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]`;
2348 enum GET_PRICEa(string prob
, string bit
) =
2349 `ProbPrices[((`~prob
~`) ^ cast(uint)((-(cast(int)(`~bit
~`))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]`;
2351 enum GET_PRICE_0(string prob
) = `p.ProbPrices[(`~prob
~`) >> kNumMoveReducingBits]`;
2352 enum GET_PRICE_1(string prob
) = `p.ProbPrices[((`~prob
~`) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]`;
2354 enum GET_PRICEa_0(string prob
) = `ProbPrices[(`~prob
~`) >> kNumMoveReducingBits]`;
2355 enum GET_PRICEa_1(string prob
) = `ProbPrices[((`~prob
~`) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]`;
2358 private uint LitEnc_GetPrice(const CLzmaProb
*probs
, uint sym
, const CProbPrice
*ProbPrices
)
2366 price
+= mixin(GET_PRICEa
!("probs[sym]", "bit"));
2373 private uint LitEnc_Matched_GetPrice(const CLzmaProb
*probs
, uint sym
, uint matchByte
, const CProbPrice
*ProbPrices
)
2381 price
+= mixin(GET_PRICEa
!("probs[offs + (matchByte & offs) + (sym >> 8)]", "(sym >> 7) & 1"));
2383 offs
&= ~(matchByte ^ sym
);
2385 while (sym
< 0x10000);
2390 private void RcTree_ReverseEncode(CRangeEnc
*rc
, CLzmaProb
*probs
, uint numBits
, uint sym
)
2392 uint range
= rc
.range
;
2398 // RangeEnc_EncodeBit(rc, probs + m, bit);
2400 mixin(RC_BIT
!("rc", "probs + m", "bit"));
2409 private void LenEnc_Init (CLenEnc
* p
) @nogc {
2411 for (i
= 0; i
< (LZMA_NUM_PB_STATES_MAX
<< (kLenNumLowBits
+ 1)); i
++)
2412 p
.low
[i
] = kProbInitValue
;
2413 for (i
= 0; i
< kLenNumHighSymbols
; i
++)
2414 p
.high
[i
] = kProbInitValue
;
2417 private void LenEnc_Encode(CLenEnc
*p
, CRangeEnc
*rc
, uint sym
, uint posState
)
2419 uint range
, ttt
, newBound
;
2420 CLzmaProb
*probs
= p
.low
.ptr
;
2422 mixin(RC_BIT_PRE
!("rc", "probs"));
2423 if (sym
>= kLenNumLowSymbols
)
2425 mixin(RC_BIT_1
!("rc", "probs"));
2426 probs
+= kLenNumLowSymbols
;
2427 mixin(RC_BIT_PRE
!("rc", "probs"));
2428 if (sym
>= kLenNumLowSymbols
* 2)
2430 mixin(RC_BIT_1
!("rc", "probs"));
2432 // RcTree_Encode(rc, p->high, kLenNumHighBits, sym - kLenNumLowSymbols * 2);
2433 LitEnc_Encode(rc
, p
.high
.ptr
, sym
- kLenNumLowSymbols
* 2);
2436 sym
-= kLenNumLowSymbols
;
2439 // RcTree_Encode(rc, probs + (posState << kLenNumLowBits), kLenNumLowBits, sym);
2443 mixin(RC_BIT_0
!("rc", "probs"));
2444 probs
+= (posState
<< (1 + kLenNumLowBits
));
2445 bit
= (sym
>> 2) ; mixin(RC_BIT
!("rc", "probs + 1", "bit")); m
= (1 << 1) + bit
;
2446 bit
= (sym
>> 1) & 1; mixin(RC_BIT
!("rc", "probs + m", "bit")); m
= (m
<< 1) + bit
;
2447 bit
= sym
& 1; mixin(RC_BIT
!("rc", "probs + m", "bit"));
2452 private void SetPrices_3 (const(CLzmaProb
)* probs
, uint startPrice
, uint* prices
, const(CProbPrice
)* ProbPrices
) @nogc {
2454 for (i
= 0; i
< 8; i
+= 2)
2456 uint price
= startPrice
;
2458 price
+= mixin(GET_PRICEa
!("probs[1 ]", "(i >> 2)"));
2459 price
+= mixin(GET_PRICEa
!("probs[2 + (i >> 2)]", "(i >> 1) & 1"));
2460 prob
= probs
[4 + (i
>> 1)];
2461 prices
[i
] = price
+ mixin(GET_PRICEa_0
!"prob");
2462 prices
[i
+ 1] = price
+ mixin(GET_PRICEa_1
!"prob");
2468 private void LenPriceEnc_UpdateTables(
2471 const(CLenEnc
)* enc
,
2472 const(CProbPrice
)* ProbPrices
)
2477 uint prob
= enc
.low
[0];
2480 b
= mixin(GET_PRICEa_1
!"prob");
2481 a
= mixin(GET_PRICEa_0
!"prob");
2482 c
= b
+ mixin(GET_PRICEa_0
!"enc.low[kLenNumLowSymbols]");
2483 for (posState
= 0; posState
< numPosStates
; posState
++)
2485 uint *prices
= p
.prices
[posState
].ptr
;
2486 const(CLzmaProb
)* probs
= enc
.low
.ptr
+ (posState
<< (1 + kLenNumLowBits
));
2487 SetPrices_3(probs
, a
, prices
, ProbPrices
);
2488 SetPrices_3(probs
+ kLenNumLowSymbols
, c
, prices
+ kLenNumLowSymbols
, ProbPrices
);
2496 a = GET_PRICEa_0(enc->low[0]);
2497 for (i = 0; i < kLenNumLowSymbols; i++)
2499 a = GET_PRICEa_1(enc->low[0]);
2500 b = a + GET_PRICEa_0(enc->low[kLenNumLowSymbols]);
2501 for (i = kLenNumLowSymbols; i < kLenNumLowSymbols * 2; i++)
2503 a += GET_PRICEa_1(enc->low[kLenNumLowSymbols]);
2507 // p->counter = numSymbols;
2511 uint i
= p
.tableSize
;
2513 if (i
> kLenNumLowSymbols
* 2)
2515 const(CLzmaProb
)* probs
= enc
.high
.ptr
;
2516 uint *prices
= p
.prices
[0].ptr
+ kLenNumLowSymbols
* 2;
2517 i
-= kLenNumLowSymbols
* 2 - 1;
2519 b
+= mixin(GET_PRICEa_1
!"enc.low[kLenNumLowSymbols]");
2524 // RcTree_GetPrice(enc->high, kLenNumHighBits, i - kLenNumLowSymbols * 2, ProbPrices);
2525 LitEnc_GetPrice(probs, i - kLenNumLowSymbols * 2, ProbPrices);
2527 // uint price = a + RcTree_GetPrice(probs, kLenNumHighBits - 1, sym, ProbPrices);
2528 uint sym
= --i
+ (1 << (kLenNumHighBits
- 1));
2534 price
+= mixin(GET_PRICEa
!("probs[sym]", "bit"));
2539 uint prob
= probs
[cast(usize
)i
+ (1 << (kLenNumHighBits
- 1))];
2540 prices
[cast(usize
)i
* 2 ] = price
+ mixin(GET_PRICEa_0
!"prob");
2541 prices
[cast(usize
)i
* 2 + 1] = price
+ mixin(GET_PRICEa_1
!"prob");
2547 import core
.stdc
.string
: memcpy
;
2549 usize num
= (p
.tableSize
- kLenNumLowSymbols
* 2) * (p
.prices
[0][0]).sizeof
;
2550 for (posState
= 1; posState
< numPosStates
; posState
++)
2551 memcpy(p
.prices
[posState
].ptr
+ kLenNumLowSymbols
* 2, p
.prices
[0].ptr
+ kLenNumLowSymbols
* 2, num
);
2559 g_STAT_OFFSET += num;
2560 printf("\n MovePos %u", num);
2564 enum MOVE_POS1(string p
, string num
) = `{
2565 `~p
~`.additionalOffset += (`~num
~`);
2566 `~p
~`.matchFinder.Skip(`~p
~`.matchFinderObj, cast(uint)(`~num
~`)); }
2570 private uint ReadMatchDistances(CLzmaEnc
*p
, uint *numPairsRes
)
2574 p
.additionalOffset
++;
2575 p
.numAvail
= p
.matchFinder
.GetNumAvailableBytes(p
.matchFinderObj
);
2577 const uint *d
= p
.matchFinder
.GetMatches(p
.matchFinderObj
, p
.matches
.ptr
);
2578 // if (!d) { p->mf_Failure = True; *numPairsRes = 0; return 0; }
2579 numPairs
= cast(uint)(d
- p
.matches
.ptr
);
2581 *numPairsRes
= numPairs
;
2585 printf("\n i = %u numPairs = %u ", g_STAT_OFFSET, numPairs / 2);
2589 for (i = 0; i < numPairs; i += 2)
2590 printf("%2u %6u | ", p.matches[i], p.matches[i + 1]);
2598 const uint len
= p
.matches
[cast(usize
)numPairs
- 2];
2599 if (len
!= p
.numFastBytes
)
2602 uint numAvail
= p
.numAvail
;
2603 if (numAvail
> LZMA_MATCH_LEN_MAX
)
2604 numAvail
= LZMA_MATCH_LEN_MAX
;
2606 const(ubyte)* p1
= p
.matchFinder
.GetPointerToCurrentPos(p
.matchFinderObj
) - 1;
2607 const(ubyte)* p2
= p1
+ len
;
2608 const ptrdiff_t dif
= cast(ptrdiff_t
)-1 - cast(ptrdiff_t
)p
.matches
[cast(usize
)numPairs
- 1];
2609 const(ubyte)* lim
= p1
+ numAvail
;
2610 for (; p2
!= lim
&& *p2
== p2
[dif
]; p2
++)
2612 return cast(uint)(p2
- p1
);
2618 enum MARK_LIT
= (cast(uint)cast(int)-1);
2620 enum MakeAs_Lit(string p
) = `{ (`~p
~`).dist = MARK_LIT; (`~p
~`).extra = 0; }`;
2621 enum MakeAs_ShortRep(string p
) = `{ (`~p
~`).dist = 0; (`~p
~`).extra = 0; }`;
2622 enum IsShortRep(string p
) = `((`~p
~`).dist == 0)`;
2625 enum GetPrice_ShortRep(string p
, string state
, string posState
) =
2626 `( `~GET_PRICE_0
!(p
~`.isRepG0[`~state
~`]`)~` + `~GET_PRICE_0
!(p
~`.isRep0Long[`~state
~`][`~posState
~`]`)~`)`;
2628 enum GetPrice_Rep_0(string p
, string state
, string posState
) = `(
2629 `~GET_PRICE_1
!(p
~`.isMatch[`~state
~`][`~posState
~`]`)~`
2630 + `~GET_PRICE_1
!(p
~`.isRep0Long[`~state
~`][`~posState
~`]`)~`)
2631 + `~GET_PRICE_1
!(p
~`.isRep[`~state
~`]`)~`
2632 + `~GET_PRICE_0
!(p
~`.isRepG0[`~state
~`]`);
2635 private uint GetPrice_PureRep(const(CLzmaEnc
)* p
, uint repIndex
, usize state
, usize posState
)
2638 uint prob
= p
.isRepG0
[state
];
2641 price
= mixin(GET_PRICE_0
!"prob");
2642 price
+= mixin(GET_PRICE_1
!"p.isRep0Long[state][posState]");
2646 price
= mixin(GET_PRICE_1
!"prob");
2647 prob
= p
.isRepG1
[state
];
2649 price
+= mixin(GET_PRICE_0
!"prob");
2652 price
+= mixin(GET_PRICE_1
!"prob");
2653 price
+= mixin(GET_PRICE
!("p.isRepG2[state]", "repIndex - 2"));
2660 private uint Backward(CLzmaEnc
*p
, uint cur
)
2667 uint dist
= p
.opt
[cur
].dist
;
2668 uint len
= cast(uint)p
.opt
[cur
].len
;
2669 uint extra
= cast(uint)p
.opt
[cur
].extra
;
2675 p
.opt
[wr
].len
= cast(uint)len
;
2680 p
.opt
[wr
].dist
= dist
;
2688 p
.opt
[wr
].dist
= MARK_LIT
;
2701 p
.opt
[wr
].dist
= dist
;
2702 p
.opt
[wr
].len
= cast(uint)len
;
2708 enum LIT_PROBS(string pos
, string prevByte
) =
2709 `(p.litProbs + cast(uint)3 * (((((`~pos
~`) << 8) + (`~prevByte
~`)) & p.lpMask) << p.lc))`;
2712 private uint GetOptimum(CLzmaEnc
*p
, uint position
)
2715 uint[LZMA_NUM_REPS
] reps
;
2716 uint[LZMA_NUM_REPS
] repLens
;
2721 uint numPairs
, mainLen
, repMaxIndex
, i
, posState
;
2722 uint matchPrice
, repMatchPrice
;
2724 ubyte curByte
, matchByte
;
2726 p
.optCur
= p
.optEnd
= 0;
2728 if (p
.additionalOffset
== 0)
2729 mainLen
= ReadMatchDistances(p
, &numPairs
);
2732 mainLen
= p
.longestMatchLen
;
2733 numPairs
= p
.numPairs
;
2736 numAvail
= p
.numAvail
;
2739 p
.backRes
= MARK_LIT
;
2742 if (numAvail
> LZMA_MATCH_LEN_MAX
)
2743 numAvail
= LZMA_MATCH_LEN_MAX
;
2745 data
= p
.matchFinder
.GetPointerToCurrentPos(p
.matchFinderObj
) - 1;
2748 for (i
= 0; i
< LZMA_NUM_REPS
; i
++)
2751 const(ubyte)* data2
;
2752 reps
[i
] = p
.reps
[i
];
2753 data2
= data
- reps
[i
];
2754 if (data
[0] != data2
[0] || data
[1] != data2
[1])
2759 for (len
= 2; len
< numAvail
&& data
[len
] == data2
[len
]; len
++)
2762 if (len
> repLens
[repMaxIndex
])
2764 if (len
== LZMA_MATCH_LEN_MAX
) // 21.03 : optimization
2768 if (repLens
[repMaxIndex
] >= p
.numFastBytes
)
2771 p
.backRes
= cast(uint)repMaxIndex
;
2772 len
= repLens
[repMaxIndex
];
2773 mixin(MOVE_POS1
!("p", "len - 1"));
2777 matches
= p
.matches
.ptr
;
2778 //!#define MATCHES matches
2779 // #define MATCHES p->matches
2781 if (mainLen
>= p
.numFastBytes
)
2783 p
.backRes
= p
.matches
[cast(usize
)numPairs
- 1] + LZMA_NUM_REPS
;
2784 mixin(MOVE_POS1
!("p", "mainLen - 1"));
2789 matchByte
= *(data
- reps
[0]);
2791 last
= repLens
[repMaxIndex
];
2792 if (last
<= mainLen
)
2795 if (last
< 2 && curByte
!= matchByte
)
2797 p
.backRes
= MARK_LIT
;
2801 p
.opt
[0].state
= cast(CState
)p
.state
;
2803 posState
= (position
& p
.pbMask
);
2806 const(CLzmaProb
)* probs
= mixin(LIT_PROBS
!("position", "*(data - 1)"));
2807 p
.opt
[1].price
= mixin(GET_PRICE_0
!"p.isMatch[p.state][posState]") +
2808 (!mixin(IsLitState
!"p.state") ?
2809 LitEnc_Matched_GetPrice(probs
, curByte
, matchByte
, p
.ProbPrices
.ptr
) :
2810 LitEnc_GetPrice(probs
, curByte
, p
.ProbPrices
.ptr
));
2813 mixin(MakeAs_Lit
!"&p.opt[1]");
2815 matchPrice
= mixin(GET_PRICE_1
!"p.isMatch[p.state][posState]");
2816 repMatchPrice
= matchPrice
+ mixin(GET_PRICE_1
!"p.isRep[p.state]");
2819 if (matchByte
== curByte
&& repLens
[0] == 0)
2821 uint shortRepPrice
= repMatchPrice
+ mixin(GetPrice_ShortRep
!("p", "p.state", "posState"));
2822 if (shortRepPrice
< p
.opt
[1].price
)
2824 p
.opt
[1].price
= shortRepPrice
;
2825 mixin(MakeAs_ShortRep
!"&p.opt[1]");
2829 p
.backRes
= p
.opt
[1].dist
;
2836 p
.opt
[0].reps
[0] = reps
[0];
2837 p
.opt
[0].reps
[1] = reps
[1];
2838 p
.opt
[0].reps
[2] = reps
[2];
2839 p
.opt
[0].reps
[3] = reps
[3];
2841 // ---------- REP ----------
2843 for (i
= 0; i
< LZMA_NUM_REPS
; i
++)
2845 uint repLen
= repLens
[i
];
2849 price
= repMatchPrice
+ GetPrice_PureRep(p
, i
, p
.state
, posState
);
2852 uint price2
= price
+ mixin(GET_PRICE_LEN
!("&p.repLenEnc", "posState", "repLen"));
2853 COptimal
*opt
= &p
.opt
[repLen
];
2854 if (price2
< opt
.price
)
2857 opt
.len
= cast(uint)repLen
;
2858 opt
.dist
= cast(uint)i
;
2862 while (--repLen
>= 2);
2866 // ---------- MATCH ----------
2868 uint len
= repLens
[0] + 1;
2872 uint normalMatchPrice
= matchPrice
+ mixin(GET_PRICE_0
!"p.isRep[p.state]");
2877 while (len
> p
.matches
[offs
])
2883 uint dist
= p
.matches
[cast(usize
)offs
+ 1];
2884 uint price
= normalMatchPrice
+ mixin(GET_PRICE_LEN
!("&p.lenEnc", "posState", "len"));
2885 uint lenToPosState
= mixin(GetLenToPosState
!"len");
2887 if (dist
< kNumFullDistances
)
2888 price
+= p
.distancesPrices
[lenToPosState
][dist
& (kNumFullDistances
- 1)];
2892 mixin(GetPosSlot2
!("dist", "slot"));
2893 price
+= p
.alignPrices
[dist
& kAlignMask
];
2894 price
+= p
.posSlotPrices
[lenToPosState
][slot
];
2899 if (price
< opt
.price
)
2902 opt
.len
= cast(uint)len
;
2903 opt
.dist
= dist
+ LZMA_NUM_REPS
;
2907 if (len
== p
.matches
[offs
])
2910 if (offs
== numPairs
)
2922 /* if (position >= 0) */
2925 printf("\n pos = %4X", position);
2926 for (i = cur; i <= last; i++)
2927 printf("\nprice[%4X] = %u", position - cur + i, p.opt[i].price);
2935 // ---------- Optimal Parsing ----------
2941 uint newLen
, numPairs
, prev
, state
, posState
, startLen
;
2942 uint litPrice
, matchPrice
, repMatchPrice
;
2944 ubyte curByte
, matchByte
;
2953 if (cur
>= kNumOpts
- 64)
2956 uint price
= p
.opt
[cur
].price
;
2958 for (j
= cur
+ 1; j
<= last
; j
++)
2960 uint price2
= p
.opt
[j
].price
;
2961 if (price
>= price2
)
2968 uint delta
= best
- cur
;
2971 mixin(MOVE_POS1
!("p", "delta"));
2978 newLen
= ReadMatchDistances(p
, &numPairs
);
2980 if (newLen
>= p
.numFastBytes
)
2982 p
.numPairs
= numPairs
;
2983 p
.longestMatchLen
= newLen
;
2987 curOpt
= &p
.opt
[cur
];
2991 // we need that check here, if skip_items in p->opt are possible
2993 if (curOpt->price >= kInfinityPrice)
2997 prev
= cur
- curOpt
.len
;
2999 if (curOpt
.len
== 1)
3001 state
= cast(uint)p
.opt
[prev
].state
;
3002 if (mixin(IsShortRep
!"curOpt"))
3003 state
= kShortRepNextStates
[state
];
3005 state
= kLiteralNextStates
[state
];
3009 const(COptimal
)* prevOpt
;
3011 uint dist
= curOpt
.dist
;
3015 prev
-= cast(uint)curOpt
.extra
;
3016 state
= kState_RepAfterLit
;
3017 if (curOpt
.extra
== 1)
3018 state
= (dist
< LZMA_NUM_REPS ? kState_RepAfterLit
: kState_MatchAfterLit
);
3022 state
= cast(uint)p
.opt
[prev
].state
;
3023 if (dist
< LZMA_NUM_REPS
)
3024 state
= kRepNextStates
[state
];
3026 state
= kMatchNextStates
[state
];
3029 prevOpt
= &p
.opt
[prev
];
3030 b0
= prevOpt
.reps
[0];
3032 if (dist
< LZMA_NUM_REPS
)
3037 reps
[1] = prevOpt
.reps
[1];
3038 reps
[2] = prevOpt
.reps
[2];
3039 reps
[3] = prevOpt
.reps
[3];
3044 b0
= prevOpt
.reps
[1];
3048 reps
[2] = prevOpt
.reps
[2];
3049 reps
[3] = prevOpt
.reps
[3];
3054 reps
[0] = prevOpt
.reps
[dist
];
3055 reps
[3] = prevOpt
.reps
[dist ^
1];
3061 reps
[0] = (dist
- LZMA_NUM_REPS
+ 1);
3063 reps
[2] = prevOpt
.reps
[1];
3064 reps
[3] = prevOpt
.reps
[2];
3068 curOpt
.state
= cast(CState
)state
;
3069 curOpt
.reps
[0] = reps
[0];
3070 curOpt
.reps
[1] = reps
[1];
3071 curOpt
.reps
[2] = reps
[2];
3072 curOpt
.reps
[3] = reps
[3];
3074 data
= p
.matchFinder
.GetPointerToCurrentPos(p
.matchFinderObj
) - 1;
3076 matchByte
= *(data
- reps
[0]);
3078 posState
= (position
& p
.pbMask
);
3081 The order of Price checks:
3085 < REP [ : LIT : REP_0 ]
3086 < MATCH [ : LIT : REP_0 ]
3090 uint curPrice
= curOpt
.price
;
3091 uint prob
= p
.isMatch
[state
][posState
];
3092 matchPrice
= curPrice
+ mixin(GET_PRICE_1
!"prob");
3093 litPrice
= curPrice
+ mixin(GET_PRICE_0
!"prob");
3096 nextOpt
= &p
.opt
[cast(usize
)cur
+ 1];
3097 nextIsLit
= 0/*False*/;
3099 // here we can allow skip_items in p->opt, if we don't check (nextOpt->price < kInfinityPrice)
3101 if ((nextOpt
.price
< kInfinityPrice
3102 // && !mixin(IsLitState!"state")
3103 && matchByte
== curByte
)
3104 || litPrice
> nextOpt
.price
3109 const(CLzmaProb
)* probs
= mixin(LIT_PROBS
!("position", "*(data - 1)"));
3110 litPrice
+= (!mixin(IsLitState
!"state") ?
3111 LitEnc_Matched_GetPrice(probs
, curByte
, matchByte
, p
.ProbPrices
.ptr
) :
3112 LitEnc_GetPrice(probs
, curByte
, p
.ProbPrices
.ptr
));
3114 if (litPrice
< nextOpt
.price
)
3116 nextOpt
.price
= litPrice
;
3118 mixin(MakeAs_Lit
!"nextOpt");
3119 nextIsLit
= 1/*True*/;
3123 repMatchPrice
= matchPrice
+ mixin(GET_PRICE_1
!"p.isRep[state]");
3125 numAvailFull
= p
.numAvail
;
3127 uint temp
= kNumOpts
- 1 - cur
;
3128 if (numAvailFull
> temp
)
3129 numAvailFull
= cast(uint)temp
;
3133 // ---------- SHORT_REP ----------
3134 if (mixin(IsLitState
!"state")) // 18.new
3135 if (matchByte
== curByte
)
3136 if (repMatchPrice
< nextOpt
.price
) // 18.new
3137 // if (numAvailFull < 2 || data[1] != *(data - reps[0] + 1))
3139 // nextOpt->price >= kInfinityPrice ||
3140 nextOpt
.len
< 2 // we can check nextOpt->len, if skip items are not allowed in p->opt
3141 ||
(nextOpt
.dist
!= 0
3142 // && nextOpt->extra <= 1 // 17.old
3146 uint shortRepPrice
= repMatchPrice
+ mixin(GetPrice_ShortRep
!("p", "state", "posState"));
3147 // if (shortRepPrice <= nextOpt->price) // 17.old
3148 if (shortRepPrice
< nextOpt
.price
) // 18.new
3150 nextOpt
.price
= shortRepPrice
;
3152 mixin(MakeAs_ShortRep
!"nextOpt");
3153 nextIsLit
= 0/*False*/;
3157 if (numAvailFull
< 2)
3159 numAvail
= (numAvailFull
<= p
.numFastBytes ? numAvailFull
: p
.numFastBytes
);
3161 // numAvail <= p->numFastBytes
3163 // ---------- LIT : REP_0 ----------
3166 && litPrice
!= 0 // 18.new
3167 && matchByte
!= curByte
3168 && numAvailFull
> 2)
3170 const ubyte *data2
= data
- reps
[0];
3171 if (data
[1] == data2
[1] && data
[2] == data2
[2])
3174 uint limit
= p
.numFastBytes
+ 1;
3175 if (limit
> numAvailFull
)
3176 limit
= numAvailFull
;
3177 for (len
= 3; len
< limit
&& data
[len
] == data2
[len
]; len
++)
3181 uint state2
= kLiteralNextStates
[state
];
3182 uint posState2
= (position
+ 1) & p
.pbMask
;
3183 uint price
= litPrice
+ mixin(GetPrice_Rep_0
!("p", "state2", "posState2"));
3185 uint offset
= cur
+ len
;
3195 // price2 = price + GetPrice_Len_Rep_0(p, len, state2, posState2);
3196 price2
= price
+ mixin(GET_PRICE_LEN
!("&p.repLenEnc", "posState2", "len"));
3198 opt
= &p
.opt
[offset
];
3200 if (price2
< opt
.price
)
3203 opt
.len
= cast(uint)len
;
3208 // while (len >= 3);
3214 startLen
= 2; /* speed optimization */
3217 // ---------- REP ----------
3218 uint repIndex
= 0; // 17.old
3219 // uint repIndex = mixin(IsLitState!"state") ? 0 : 1; // 18.notused
3220 for (; repIndex
< LZMA_NUM_REPS
; repIndex
++)
3224 const ubyte *data2
= data
- reps
[repIndex
];
3225 if (data
[0] != data2
[0] || data
[1] != data2
[1])
3228 for (len
= 2; len
< numAvail
&& data
[len
] == data2
[len
]; len
++)
3231 // if (len < startLen) continue; // 18.new: speed optimization
3234 uint offset
= cur
+ len
;
3240 price
= repMatchPrice
+ GetPrice_PureRep(p
, repIndex
, state
, posState
);
3243 uint price2
= price
+ mixin(GET_PRICE_LEN
!("&p.repLenEnc", "posState", "len2"));
3244 COptimal
*opt
= &p
.opt
[cur
+ len2
];
3245 if (price2
< opt
.price
)
3248 opt
.len
= cast(uint)len2
;
3249 opt
.dist
= cast(uint)repIndex
;
3253 while (--len2
>= 2);
3256 if (repIndex
== 0) startLen
= len
+ 1; // 17.old
3257 // startLen = len + 1; // 18.new
3261 // ---------- REP : LIT : REP_0 ----------
3262 // numFastBytes + 1 + numFastBytes
3264 uint len2
= len
+ 1;
3265 uint limit
= len2
+ p
.numFastBytes
;
3266 if (limit
> numAvailFull
)
3267 limit
= numAvailFull
;
3271 if (data
[len2
- 2] == data2
[len2
- 2])
3272 if (data
[len2
- 1] == data2
[len2
- 1])
3274 uint state2
= kRepNextStates
[state
];
3275 uint posState2
= (position
+ len
) & p
.pbMask
;
3276 price
+= mixin(GET_PRICE_LEN
!("&p.repLenEnc", "posState", "len"))
3277 + mixin(GET_PRICE_0
!"p.isMatch[state2][posState2]")
3278 + LitEnc_Matched_GetPrice(mixin(LIT_PROBS
!("position + len", "data[cast(usize)len - 1]")),
3279 data
[len
], data2
[len
], p
.ProbPrices
.ptr
);
3281 // state2 = kLiteralNextStates[state2];
3282 state2
= kState_LitAfterRep
;
3283 posState2
= (posState2
+ 1) & p
.pbMask
;
3286 price
+= mixin(GetPrice_Rep_0
!("p", "state2", "posState2"));
3288 for (; len2
< limit
&& data
[len2
] == data2
[len2
]; len2
++)
3295 uint offset
= cur
+ len
+ len2
;
3304 // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2);
3305 price2
= price
+ mixin(GET_PRICE_LEN
!("&p.repLenEnc", "posState2", "len2"));
3307 opt
= &p
.opt
[offset
];
3309 if (price2
< opt
.price
)
3312 opt
.len
= cast(uint)len2
;
3313 opt
.extra
= cast(CExtra
)(len
+ 1);
3314 opt
.dist
= cast(uint)repIndex
;
3317 // while (len2 >= 3);
3326 // ---------- MATCH ----------
3327 /* for (uint len = 2; len <= newLen; len++) */
3328 if (newLen
> numAvail
)
3331 for (numPairs
= 0; newLen
> p
.matches
[numPairs
]; numPairs
+= 2) {}
3332 p
.matches
[numPairs
] = cast(uint)newLen
;
3336 // startLen = 2; /* speed optimization */
3338 if (newLen
>= startLen
)
3340 uint normalMatchPrice
= matchPrice
+ mixin(GET_PRICE_0
!"p.isRep[state]");
3342 uint offs
, posSlot
, len
;
3345 uint offset
= cur
+ newLen
;
3351 while (startLen
> p
.matches
[offs
])
3353 dist
= p
.matches
[cast(usize
)offs
+ 1];
3355 // if (dist >= kNumFullDistances)
3356 mixin(GetPosSlot2
!("dist", "posSlot"));
3358 for (len
= /*2*/ startLen
; ; len
++)
3360 uint price
= normalMatchPrice
+ mixin(GET_PRICE_LEN
!("&p.lenEnc", "posState", "len"));
3363 uint lenNorm
= len
- 2;
3364 lenNorm
= mixin(GetLenToPosState2
!"lenNorm");
3365 if (dist
< kNumFullDistances
)
3366 price
+= p
.distancesPrices
[lenNorm
][dist
& (kNumFullDistances
- 1)];
3368 price
+= p
.posSlotPrices
[lenNorm
][posSlot
] + p
.alignPrices
[dist
& kAlignMask
];
3370 opt
= &p
.opt
[cur
+ len
];
3371 if (price
< opt
.price
)
3374 opt
.len
= cast(uint)len
;
3375 opt
.dist
= dist
+ LZMA_NUM_REPS
;
3380 if (len
== p
.matches
[offs
])
3382 // if (p->_maxMode) {
3383 // MATCH : LIT : REP_0
3385 const ubyte *data2
= data
- dist
- 1;
3386 uint len2
= len
+ 1;
3387 uint limit
= len2
+ p
.numFastBytes
;
3388 if (limit
> numAvailFull
)
3389 limit
= numAvailFull
;
3393 if (data
[len2
- 2] == data2
[len2
- 2])
3394 if (data
[len2
- 1] == data2
[len2
- 1])
3396 for (; len2
< limit
&& data
[len2
] == data2
[len2
]; len2
++)
3403 uint state2
= kMatchNextStates
[state
];
3404 uint posState2
= (position
+ len
) & p
.pbMask
;
3406 price
+= mixin(GET_PRICE_0
!"p.isMatch[state2][posState2]");
3407 price
+= LitEnc_Matched_GetPrice(mixin(LIT_PROBS
!("position + len", "data[cast(usize)len - 1]")),
3408 data
[len
], data2
[len
], p
.ProbPrices
.ptr
);
3410 // state2 = kLiteralNextStates[state2];
3411 state2
= kState_LitAfterMatch
;
3413 posState2
= (posState2
+ 1) & p
.pbMask
;
3414 price
+= mixin(GetPrice_Rep_0
!("p", "state2", "posState2"));
3416 offset
= cur
+ len
+ len2
;
3425 // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2);
3426 price2
= price
+ mixin(GET_PRICE_LEN
!("&p.repLenEnc", "posState2", "len2"));
3427 opt
= &p
.opt
[offset
];
3429 if (price2
< opt
.price
)
3432 opt
.len
= cast(uint)len2
;
3433 opt
.extra
= cast(CExtra
)(len
+ 1);
3434 opt
.dist
= dist
+ LZMA_NUM_REPS
;
3437 // while (len2 >= 3);
3443 if (offs
== numPairs
)
3445 dist
= p
.matches
[cast(usize
)offs
+ 1];
3446 // if (dist >= kNumFullDistances) {
3447 mixin(GetPosSlot2
!("dist", "posSlot"));
3455 p
.opt
[last
].price
= kInfinityPrice
;
3458 return Backward(p
, cur
);
3463 enum ChangePair(string smallDist
, string bigDist
) = `(((`~bigDist
~`) >> 7) > (`~smallDist
~`))`;
3467 private uint GetOptimumFast(CLzmaEnc
*p
)
3469 uint numAvail
, mainDist
;
3470 uint mainLen
, numPairs
, repIndex
, repLen
, i
;
3473 if (p
.additionalOffset
== 0)
3474 mainLen
= ReadMatchDistances(p
, &numPairs
);
3477 mainLen
= p
.longestMatchLen
;
3478 numPairs
= p
.numPairs
;
3481 numAvail
= p
.numAvail
;
3482 p
.backRes
= MARK_LIT
;
3485 // if (mainLen < 2 && p->state == 0) return 1; // 18.06.notused
3486 if (numAvail
> LZMA_MATCH_LEN_MAX
)
3487 numAvail
= LZMA_MATCH_LEN_MAX
;
3488 data
= p
.matchFinder
.GetPointerToCurrentPos(p
.matchFinderObj
) - 1;
3489 repLen
= repIndex
= 0;
3491 for (i
= 0; i
< LZMA_NUM_REPS
; i
++)
3494 const ubyte *data2
= data
- p
.reps
[i
];
3495 if (data
[0] != data2
[0] || data
[1] != data2
[1])
3497 for (len
= 2; len
< numAvail
&& data
[len
] == data2
[len
]; len
++)
3499 if (len
>= p
.numFastBytes
)
3501 p
.backRes
= cast(uint)i
;
3502 mixin(MOVE_POS1
!("p", "len - 1"));
3512 if (mainLen
>= p
.numFastBytes
)
3514 p
.backRes
= p
.matches
[cast(usize
)numPairs
- 1] + LZMA_NUM_REPS
;
3515 mixin(MOVE_POS1
!("p", "mainLen - 1"));
3519 mainDist
= 0; /* for GCC */
3523 mainDist
= p
.matches
[cast(usize
)numPairs
- 1];
3524 while (numPairs
> 2)
3527 if (mainLen
!= p
.matches
[cast(usize
)numPairs
- 4] + 1)
3529 dist2
= p
.matches
[cast(usize
)numPairs
- 3];
3530 if (!mixin(ChangePair
!("dist2", "mainDist")))
3536 if (mainLen
== 2 && mainDist
>= 0x80)
3541 if ( repLen
+ 1 >= mainLen
3542 ||
(repLen
+ 2 >= mainLen
&& mainDist
>= (1 << 9))
3543 ||
(repLen
+ 3 >= mainLen
&& mainDist
>= (1 << 15)))
3545 p
.backRes
= cast(uint)repIndex
;
3546 mixin(MOVE_POS1
!("p", "repLen - 1"));
3550 if (mainLen
< 2 || numAvail
<= 2)
3554 uint len1
= ReadMatchDistances(p
, &p
.numPairs
);
3555 p
.longestMatchLen
= len1
;
3559 uint newDist
= p
.matches
[cast(usize
)p
.numPairs
- 1];
3560 if ( (len1
>= mainLen
&& newDist
< mainDist
)
3561 ||
(len1
== mainLen
+ 1 && !mixin(ChangePair
!("mainDist", "newDist")))
3562 ||
(len1
> mainLen
+ 1)
3563 ||
(len1
+ 1 >= mainLen
&& mainLen
>= 3 && mixin(ChangePair
!("newDist", "mainDist"))))
3568 data
= p
.matchFinder
.GetPointerToCurrentPos(p
.matchFinderObj
) - 1;
3570 for (i
= 0; i
< LZMA_NUM_REPS
; i
++)
3573 const ubyte *data2
= data
- p
.reps
[i
];
3574 if (data
[0] != data2
[0] || data
[1] != data2
[1])
3576 limit
= mainLen
- 1;
3577 for (len
= 2;; len
++)
3581 if (data
[len
] != data2
[len
])
3586 p
.backRes
= mainDist
+ LZMA_NUM_REPS
;
3589 mixin(MOVE_POS1
!("p", "mainLen - 2"));
3597 private void WriteEndMarker(CLzmaEnc
*p
, uint posState
)
3603 CLzmaProb
*prob
= &p
.isMatch
[p
.state
][posState
];
3604 mixin(RC_BIT_PRE
!("&p.rc", "prob"));
3605 mixin(RC_BIT_1
!("&p.rc", "prob"));
3606 prob
= &p
.isRep
[p
.state
];
3607 mixin(RC_BIT_PRE
!("&p.rc", "prob"));
3608 mixin(RC_BIT_0
!("&p.rc", "prob"));
3610 p
.state
= kMatchNextStates
[p
.state
];
3613 LenEnc_Encode(&p
.lenProbs
, &p
.rc
, 0, posState
);
3617 // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[0], (1 << kNumPosSlotBits) - 1);
3618 CLzmaProb
*probs
= p
.posSlotEncoder
[0].ptr
;
3623 mixin(RC_BIT_PRE
!("p", "probs + m"));
3624 mixin(RC_BIT_1
!("&p.rc", "probs + m"));
3627 while (m
< (1 << kNumPosSlotBits
));
3630 // RangeEnc_EncodeDirectBits(&p->rc, ((uint)1 << (30 - kNumAlignBits)) - 1, 30 - kNumAlignBits); uint range = p->range;
3631 uint numBits
= 30 - kNumAlignBits
;
3636 mixin(RC_NORM
!"&p.rc");
3642 // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
3643 CLzmaProb
*probs
= p
.posAlignEncoder
.ptr
;
3648 mixin(RC_BIT_PRE
!("p", "probs + m"));
3649 mixin(RC_BIT_1
!("&p.rc", "probs + m"));
3652 while (m
< kAlignTableSize
);
3658 private SRes
CheckErrors(CLzmaEnc
*p
)
3660 if (p
.result
!= SZ_OK
)
3662 if (p
.rc
.res
!= SZ_OK
)
3663 p
.result
= SZ_ERROR_WRITE
;
3665 if ((p
.matchFinderBase
).result
!= SZ_OK
)
3666 p
.result
= SZ_ERROR_READ
;
3668 if (p
.result
!= SZ_OK
)
3669 p
.finished
= 1/*True*/;
3675 private SRes
Flush(CLzmaEnc
*p
, uint nowPos
)
3677 /* ReleaseMFStream(); */
3678 p
.finished
= 1/*True*/;
3680 WriteEndMarker(p
, nowPos
& p
.pbMask
);
3681 RangeEnc_FlushData(&p
.rc
);
3682 RangeEnc_FlushStream(&p
.rc
);
3683 return CheckErrors(p
);
3688 private void FillAlignPrices(CLzmaEnc
*p
)
3691 const CProbPrice
*ProbPrices
= p
.ProbPrices
.ptr
;
3692 const CLzmaProb
*probs
= p
.posAlignEncoder
.ptr
;
3693 // p->alignPriceCount = 0;
3694 for (i
= 0; i
< kAlignTableSize
/ 2; i
++)
3701 bit
= sym
& 1; sym
>>= 1; price
+= mixin(GET_PRICEa
!("probs[m]", "bit")); m
= (m
<< 1) + bit
;
3702 bit
= sym
& 1; sym
>>= 1; price
+= mixin(GET_PRICEa
!("probs[m]", "bit")); m
= (m
<< 1) + bit
;
3703 bit
= sym
& 1; sym
>>= 1; price
+= mixin(GET_PRICEa
!("probs[m]", "bit")); m
= (m
<< 1) + bit
;
3705 p
.alignPrices
[i
] = price
+ mixin(GET_PRICEa_0
!"prob");
3706 p
.alignPrices
[i
+ 8] = price
+ mixin(GET_PRICEa_1
!"prob");
3707 // p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
3713 private void FillDistancesPrices(CLzmaEnc
*p
)
3715 // int y; for (y = 0; y < 100; y++) {
3717 uint[kNumFullDistances
] tempPrices
;
3720 const CProbPrice
*ProbPrices
= p
.ProbPrices
.ptr
;
3721 p
.matchPriceCount
= 0;
3723 for (i
= kStartPosModelIndex
/ 2; i
< kNumFullDistances
/ 2; i
++)
3725 uint posSlot
= mixin(GetPosSlot1
!"i");
3726 uint footerBits
= (posSlot
>> 1) - 1;
3727 uint base
= ((2 |
(posSlot
& 1)) << footerBits
);
3728 const(CLzmaProb
)* probs
= p
.posEncoders
.ptr
+ cast(usize
)base
* 2;
3729 // tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base, footerBits, i - base, p->ProbPrices);
3733 uint offset
= cast(uint)1 << footerBits
;
3741 price
+= mixin(GET_PRICEa
!("probs[m]", "bit"));
3744 while (--footerBits
);
3747 uint prob
= probs
[m
];
3748 tempPrices
[base
] = price
+ mixin(GET_PRICEa_0
!"prob");
3749 tempPrices
[base
+ offset
] = price
+ mixin(GET_PRICEa_1
!"prob");
3753 for (lps
= 0; lps
< kNumLenToPosStates
; lps
++)
3756 uint distTableSize2
= (p
.distTableSize
+ 1) >> 1;
3757 uint *posSlotPrices
= p
.posSlotPrices
[lps
].ptr
;
3758 const CLzmaProb
*probs
= p
.posSlotEncoder
[lps
].ptr
;
3760 for (slot
= 0; slot
< distTableSize2
; slot
++)
3762 // posSlotPrices[slot] = RcTree_GetPrice(encoder, kNumPosSlotBits, slot, p->ProbPrices);
3765 uint sym
= slot
+ (1 << (kNumPosSlotBits
- 1));
3767 bit
= sym
& 1; sym
>>= 1; price
= mixin(GET_PRICEa
!("probs[sym]", "bit"));
3768 bit
= sym
& 1; sym
>>= 1; price
+= mixin(GET_PRICEa
!("probs[sym]", "bit"));
3769 bit
= sym
& 1; sym
>>= 1; price
+= mixin(GET_PRICEa
!("probs[sym]", "bit"));
3770 bit
= sym
& 1; sym
>>= 1; price
+= mixin(GET_PRICEa
!("probs[sym]", "bit"));
3771 bit
= sym
& 1; sym
>>= 1; price
+= mixin(GET_PRICEa
!("probs[sym]", "bit"));
3772 prob
= probs
[cast(usize
)slot
+ (1 << (kNumPosSlotBits
- 1))];
3773 posSlotPrices
[cast(usize
)slot
* 2 ] = price
+ mixin(GET_PRICEa_0
!"prob");
3774 posSlotPrices
[cast(usize
)slot
* 2 + 1] = price
+ mixin(GET_PRICEa_1
!"prob");
3778 uint delta
= (cast(uint)((kEndPosModelIndex
/ 2 - 1) - kNumAlignBits
) << kNumBitPriceShiftBits
);
3779 for (slot
= kEndPosModelIndex
/ 2; slot
< distTableSize2
; slot
++)
3781 posSlotPrices
[cast(usize
)slot
* 2 ] += delta
;
3782 posSlotPrices
[cast(usize
)slot
* 2 + 1] += delta
;
3783 delta
+= (cast(uint)1 << kNumBitPriceShiftBits
);
3788 uint *dp
= p
.distancesPrices
[lps
].ptr
;
3790 dp
[0] = posSlotPrices
[0];
3791 dp
[1] = posSlotPrices
[1];
3792 dp
[2] = posSlotPrices
[2];
3793 dp
[3] = posSlotPrices
[3];
3795 for (i
= 4; i
< kNumFullDistances
; i
+= 2)
3797 uint slotPrice
= posSlotPrices
[mixin(GetPosSlot1
!"i")];
3798 dp
[i
] = slotPrice
+ tempPrices
[i
];
3799 dp
[i
+ 1] = slotPrice
+ tempPrices
[i
+ 1];
3808 private void LzmaEnc_Construct(CLzmaEnc
*p
)
3810 RangeEnc_Construct(&p
.rc
);
3811 MatchFinder_Construct(&(p
.matchFinderBase
));
3814 CLzmaEncProps props
;
3815 LzmaEncProps_Init(&props
);
3816 LzmaEnc_SetProps(p
, &props
);
3819 //#ifndef LZMA_LOG_BSR
3820 LzmaEnc_FastPosInit(p
.g_FastPos
.ptr
);
3823 LzmaEnc_InitPriceTables(p
.ProbPrices
.ptr
);
3825 p
.saveState
.litProbs
= null;
3829 //==========================================================================
3833 //==========================================================================
3834 public CLzmaEncHandle
LzmaEnc_Create (ISzAllocPtr alloc
) {
3835 void *p
= ISzAlloc_Alloc(alloc
, CLzmaEnc
.sizeof
);
3836 if (p
) LzmaEnc_Construct(cast(CLzmaEnc
*)p
);
3841 private void LzmaEnc_FreeLits(CLzmaEnc
*p
, ISzAllocPtr alloc
)
3843 ISzAlloc_Free(alloc
, p
.litProbs
);
3844 ISzAlloc_Free(alloc
, p
.saveState
.litProbs
);
3846 p
.saveState
.litProbs
= null;
3849 private void LzmaEnc_Destruct(CLzmaEnc
*p
, ISzAllocPtr alloc
, ISzAllocPtr allocBig
)
3851 MatchFinder_Free(&(p
.matchFinderBase
), allocBig
);
3852 LzmaEnc_FreeLits(p
, alloc
);
3853 RangeEnc_Free(&p
.rc
, alloc
);
3857 //==========================================================================
3861 //==========================================================================
3862 public void LzmaEnc_Destroy (CLzmaEncHandle p
, ISzAllocPtr alloc
, ISzAllocPtr allocBig
) {
3864 LzmaEnc_Destruct(cast(CLzmaEnc
*)p
, alloc
, allocBig
);
3865 ISzAlloc_Free(alloc
, p
);
3871 private SRes
LzmaEnc_CodeOneBlock(CLzmaEnc
*p
, uint maxPackSize
, uint maxUnpackSize
)
3873 uint nowPos32
, startPos32
;
3876 p
.matchFinder
.Init(p
.matchFinderObj
);
3882 int rinres
= CheckErrors(p
);
3883 if (rinres
!= 0) return rinres
;
3885 nowPos32
= cast(uint)p
.nowPos64
;
3886 startPos32
= nowPos32
;
3888 if (p
.nowPos64
== 0)
3892 if (p
.matchFinder
.GetNumAvailableBytes(p
.matchFinderObj
) == 0)
3893 return Flush(p
, nowPos32
);
3894 ReadMatchDistances(p
, &numPairs
);
3895 RangeEnc_EncodeBit_0(&p
.rc
, &p
.isMatch
[kState_Start
][0]);
3896 // p->state = kLiteralNextStates[p->state];
3897 curByte
= *(p
.matchFinder
.GetPointerToCurrentPos(p
.matchFinderObj
) - p
.additionalOffset
);
3898 LitEnc_Encode(&p
.rc
, p
.litProbs
, curByte
);
3899 p
.additionalOffset
--;
3903 if (p
.matchFinder
.GetNumAvailableBytes(p
.matchFinderObj
) != 0)
3909 uint range
, ttt
, newBound
;
3913 len
= GetOptimumFast(p
);
3916 uint oci
= p
.optCur
;
3917 if (p
.optEnd
== oci
)
3918 len
= GetOptimum(p
, nowPos32
);
3921 const COptimal
*opt
= &p
.opt
[oci
];
3923 p
.backRes
= opt
.dist
;
3928 posState
= cast(uint)nowPos32
& p
.pbMask
;
3930 probs
= &p
.isMatch
[p
.state
][posState
];
3932 mixin(RC_BIT_PRE
!("&p.rc", "probs"));
3938 printf("\n pos = %6X, len = %3u pos = %6u", nowPos32, len, dist);
3942 if (dist
== MARK_LIT
)
3948 mixin(RC_BIT_0
!("&p.rc", "probs"));
3950 data
= p
.matchFinder
.GetPointerToCurrentPos(p
.matchFinderObj
) - p
.additionalOffset
;
3951 probs
= mixin(LIT_PROBS
!("nowPos32", "*(data - 1)"));
3954 p
.state
= kLiteralNextStates
[state
];
3955 if (mixin(IsLitState
!"state"))
3956 LitEnc_Encode(&p
.rc
, probs
, curByte
);
3958 LitEnc_EncodeMatched(&p
.rc
, probs
, curByte
, *(data
- p
.reps
[0]));
3962 mixin(RC_BIT_1
!("&p.rc", "probs"));
3963 probs
= &p
.isRep
[p
.state
];
3964 mixin(RC_BIT_PRE
!("&p.rc", "probs"));
3966 if (dist
< LZMA_NUM_REPS
)
3968 mixin(RC_BIT_1
!("&p.rc", "probs"));
3969 probs
= &p
.isRepG0
[p
.state
];
3970 mixin(RC_BIT_PRE
!("&p.rc", "probs"));
3973 mixin(RC_BIT_0
!("&p.rc", "probs"));
3974 probs
= &p
.isRep0Long
[p
.state
][posState
];
3975 mixin(RC_BIT_PRE
!("&p.rc", "probs"));
3978 mixin(RC_BIT_1_BASE
!("&p.rc", "probs"));
3982 mixin(RC_BIT_0_BASE
!("&p.rc", "probs"));
3983 p
.state
= kShortRepNextStates
[p
.state
];
3988 mixin(RC_BIT_1
!("&p.rc", "probs"));
3989 probs
= &p
.isRepG1
[p
.state
];
3990 mixin(RC_BIT_PRE
!("&p.rc", "probs"));
3993 mixin(RC_BIT_0_BASE
!("&p.rc", "probs"));
3998 mixin(RC_BIT_1
!("&p.rc", "probs"));
3999 probs
= &p
.isRepG2
[p
.state
];
4000 mixin(RC_BIT_PRE
!("&p.rc", "probs"));
4003 mixin(RC_BIT_0_BASE
!("&p.rc", "probs"));
4008 mixin(RC_BIT_1_BASE
!("&p.rc", "probs"));
4010 p
.reps
[3] = p
.reps
[2];
4012 p
.reps
[2] = p
.reps
[1];
4014 p
.reps
[1] = p
.reps
[0];
4018 mixin(RC_NORM
!"&p.rc");
4024 LenEnc_Encode(&p
.repLenProbs
, &p
.rc
, len
- LZMA_MATCH_LEN_MIN
, posState
);
4025 --p
.repLenEncCounter
;
4026 p
.state
= kRepNextStates
[p
.state
];
4032 mixin(RC_BIT_0
!("&p.rc", "probs"));
4034 p
.state
= kMatchNextStates
[p
.state
];
4036 LenEnc_Encode(&p
.lenProbs
, &p
.rc
, len
- LZMA_MATCH_LEN_MIN
, posState
);
4037 // --p->lenEnc.counter;
4039 dist
-= LZMA_NUM_REPS
;
4040 p
.reps
[3] = p
.reps
[2];
4041 p
.reps
[2] = p
.reps
[1];
4042 p
.reps
[1] = p
.reps
[0];
4043 p
.reps
[0] = dist
+ 1;
4045 p
.matchPriceCount
++;
4046 mixin(GetPosSlot
!("dist", "posSlot"));
4047 // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[mixin(GetLenToPosState!"len")], posSlot);
4049 uint sym
= cast(uint)posSlot
+ (1 << kNumPosSlotBits
);
4051 probs
= p
.posSlotEncoder
[mixin(GetLenToPosState
!"len")].ptr
;
4054 CLzmaProb
*prob
= probs
+ (sym
>> kNumPosSlotBits
);
4055 uint bit
= (sym
>> (kNumPosSlotBits
- 1)) & 1;
4057 mixin(RC_BIT
!("&p.rc", "prob", "bit"));
4059 while (sym
< (1 << kNumPosSlotBits
* 2));
4063 if (dist
>= kStartPosModelIndex
)
4065 uint footerBits
= ((posSlot
>> 1) - 1);
4067 if (dist
< kNumFullDistances
)
4069 uint base
= ((2 |
(posSlot
& 1)) << footerBits
);
4070 RcTree_ReverseEncode(&p
.rc
, p
.posEncoders
.ptr
+ base
, footerBits
, cast(uint)(dist
/* - base */));
4074 uint pos2
= (dist |
0xF) << (32 - footerBits
);
4076 // RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
4081 p->rc.low += range & (0 - ((dist >> --footerBits) & 1));
4084 while (footerBits > kNumAlignBits);
4089 p
.rc
.low
+= range
& (0 - (pos2
>> 31));
4091 mixin(RC_NORM
!"&p.rc");
4093 while (pos2
!= 0xF0000000);
4096 // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
4101 bit
= dist
& 1; dist
>>= 1; mixin(RC_BIT
!("&p.rc", "p.posAlignEncoder.ptr + m", "bit")); m
= (m
<< 1) + bit
;
4102 bit
= dist
& 1; dist
>>= 1; mixin(RC_BIT
!("&p.rc", "p.posAlignEncoder.ptr + m", "bit")); m
= (m
<< 1) + bit
;
4103 bit
= dist
& 1; dist
>>= 1; mixin(RC_BIT
!("&p.rc", "p.posAlignEncoder.ptr + m", "bit")); m
= (m
<< 1) + bit
;
4104 bit
= dist
& 1; mixin(RC_BIT
!("&p.rc", "p.posAlignEncoder.ptr + m", "bit"));
4106 // p->alignPriceCount++;
4113 nowPos32
+= cast(uint)len
;
4114 p
.additionalOffset
-= len
;
4116 if (p
.additionalOffset
== 0)
4123 if (p->alignPriceCount >= 16) // kAlignTableSize
4125 if (p->matchPriceCount >= 128)
4126 FillDistancesPrices(p);
4127 if (p->lenEnc.counter <= 0)
4128 LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices);
4130 if (p
.matchPriceCount
>= 64)
4133 // { int y; for (y = 0; y < 100; y++) {
4134 FillDistancesPrices(p
);
4136 LenPriceEnc_UpdateTables(&p
.lenEnc
, cast(uint)1 << p
.pb
, &p
.lenProbs
, p
.ProbPrices
.ptr
);
4138 if (p
.repLenEncCounter
<= 0)
4140 p
.repLenEncCounter
= REP_LEN_COUNT
;
4141 LenPriceEnc_UpdateTables(&p
.repLenEnc
, cast(uint)1 << p
.pb
, &p
.repLenProbs
, p
.ProbPrices
.ptr
);
4145 if (p
.matchFinder
.GetNumAvailableBytes(p
.matchFinderObj
) == 0)
4147 processed
= nowPos32
- startPos32
;
4151 if (processed
+ kNumOpts
+ 300 >= maxUnpackSize
4152 ||
mixin(RangeEnc_GetProcessed_sizet
!"&p.rc") + kPackReserve
>= maxPackSize
)
4155 else if (processed
>= (1 << 17))
4157 p
.nowPos64
+= nowPos32
- startPos32
;
4158 return CheckErrors(p
);
4163 p
.nowPos64
+= nowPos32
- startPos32
;
4164 return Flush(p
, nowPos32
);
4169 enum kBigHashDicLimit
= (cast(uint)1 << 24);
4171 private SRes
LzmaEnc_Alloc(CLzmaEnc
*p
, uint keepWindowSize
, ISzAllocPtr alloc
, ISzAllocPtr allocBig
)
4173 uint beforeSize
= kNumOpts
;
4176 if (!RangeEnc_Alloc(&p
.rc
, alloc
))
4177 return SZ_ERROR_MEM
;
4180 uint lclp
= p
.lc
+ p
.lp
;
4181 if (!p
.litProbs ||
!p
.saveState
.litProbs || p
.lclp
!= lclp
)
4183 LzmaEnc_FreeLits(p
, alloc
);
4184 p
.litProbs
= cast(CLzmaProb
*)ISzAlloc_Alloc(alloc
, (cast(uint)0x300 << lclp
) * CLzmaProb
.sizeof
);
4185 p
.saveState
.litProbs
= cast(CLzmaProb
*)ISzAlloc_Alloc(alloc
, (cast(uint)0x300 << lclp
) * CLzmaProb
.sizeof
);
4186 if (!p
.litProbs ||
!p
.saveState
.litProbs
)
4188 LzmaEnc_FreeLits(p
, alloc
);
4189 return SZ_ERROR_MEM
;
4195 (p
.matchFinderBase
).bigHash
= cast(ubyte)(p
.dictSize
> kBigHashDicLimit ?
1 : 0);
4198 dictSize
= p
.dictSize
;
4199 if (dictSize
== (cast(uint)2 << 30) ||
4200 dictSize
== (cast(uint)3 << 30))
4202 /* 21.03 : here we reduce the dictionary for 2 reasons:
4203 1) we don't want 32-bit back_distance matches in decoder for 2 GB dictionary.
4204 2) we want to elimate useless last MatchFinder_Normalize3() for corner cases,
4205 where data size is aligned for 1 GB: 5/6/8 GB.
4206 That reducing must be >= 1 for such corner cases. */
4210 if (beforeSize
+ dictSize
< keepWindowSize
)
4211 beforeSize
= keepWindowSize
- dictSize
;
4213 /* in worst case we can look ahead for
4214 max(LZMA_MATCH_LEN_MAX, numFastBytes + 1 + numFastBytes) bytes.
4215 we send larger value for (keepAfter) to MantchFinder_Create():
4216 (numFastBytes + LZMA_MATCH_LEN_MAX + 1)
4219 if (!MatchFinder_Create(&(p
.matchFinderBase
), dictSize
, beforeSize
,
4220 p
.numFastBytes
, LZMA_MATCH_LEN_MAX
+ 1 /* 21.03 */
4222 return SZ_ERROR_MEM
;
4223 p
.matchFinderObj
= &(p
.matchFinderBase
);
4224 MatchFinder_CreateVTable(&(p
.matchFinderBase
), &p
.matchFinder
);
4229 private void LzmaEnc_Init(CLzmaEnc
*p
)
4238 RangeEnc_Init(&p
.rc
);
4240 for (i
= 0; i
< (1 << kNumAlignBits
); i
++)
4241 p
.posAlignEncoder
[i
] = kProbInitValue
;
4243 for (i
= 0; i
< kNumStates
; i
++)
4246 for (j
= 0; j
< LZMA_NUM_PB_STATES_MAX
; j
++)
4248 p
.isMatch
[i
][j
] = kProbInitValue
;
4249 p
.isRep0Long
[i
][j
] = kProbInitValue
;
4251 p
.isRep
[i
] = kProbInitValue
;
4252 p
.isRepG0
[i
] = kProbInitValue
;
4253 p
.isRepG1
[i
] = kProbInitValue
;
4254 p
.isRepG2
[i
] = kProbInitValue
;
4258 for (i
= 0; i
< kNumLenToPosStates
; i
++)
4260 CLzmaProb
*probs
= p
.posSlotEncoder
[i
].ptr
;
4262 for (j
= 0; j
< (1 << kNumPosSlotBits
); j
++)
4263 probs
[j
] = kProbInitValue
;
4267 for (i
= 0; i
< kNumFullDistances
; i
++)
4268 p
.posEncoders
[i
] = kProbInitValue
;
4272 uint num
= cast(uint)0x300 << (p
.lp
+ p
.lc
);
4274 CLzmaProb
*probs
= p
.litProbs
;
4275 for (k
= 0; k
< num
; k
++)
4276 probs
[k
] = kProbInitValue
;
4280 LenEnc_Init(&p
.lenProbs
);
4281 LenEnc_Init(&p
.repLenProbs
);
4287 for (i
= 0; i
< kNumOpts
; i
++)
4288 p
.opt
[i
].price
= kInfinityPrice
;
4291 p
.additionalOffset
= 0;
4293 p
.pbMask
= (cast(uint)1 << p
.pb
) - 1;
4294 p
.lpMask
= (cast(uint)0x100 << p
.lp
) - (cast(uint)0x100 >> p
.lc
);
4296 // p->mf_Failure = False;
4300 private void LzmaEnc_InitPrices(CLzmaEnc
*p
)
4304 FillDistancesPrices(p
);
4308 p
.lenEnc
.tableSize
=
4309 p
.repLenEnc
.tableSize
=
4310 p
.numFastBytes
+ 1 - LZMA_MATCH_LEN_MIN
;
4312 p
.repLenEncCounter
= REP_LEN_COUNT
;
4314 LenPriceEnc_UpdateTables(&p
.lenEnc
, cast(uint)1 << p
.pb
, &p
.lenProbs
, p
.ProbPrices
.ptr
);
4315 LenPriceEnc_UpdateTables(&p
.repLenEnc
, cast(uint)1 << p
.pb
, &p
.repLenProbs
, p
.ProbPrices
.ptr
);
4318 private SRes
LzmaEnc_AllocAndInit(CLzmaEnc
*p
, uint keepWindowSize
, ISzAllocPtr alloc
, ISzAllocPtr allocBig
)
4321 for (i
= kEndPosModelIndex
/ 2; i
< kDicLogSizeMax
; i
++)
4322 if (p
.dictSize
<= (cast(uint)1 << i
))
4324 p
.distTableSize
= i
* 2;
4326 p
.finished
= 0/*False*/;
4328 int rinres
= LzmaEnc_Alloc(p
, keepWindowSize
, alloc
, allocBig
);
4329 if (rinres
!= 0) return rinres
;
4331 LzmaEnc_InitPrices(p
);
4336 private SRes
LzmaEnc_Prepare(CLzmaEncHandle pp
, ISeqOutStream
*outStream
, ISeqInStream
*inStream
,
4337 ISzAllocPtr alloc
, ISzAllocPtr allocBig
)
4339 CLzmaEnc
*p
= cast(CLzmaEnc
*)pp
;
4340 (p
.matchFinderBase
).stream
= inStream
;
4342 p
.rc
.outStream
= outStream
;
4343 return LzmaEnc_AllocAndInit(p
, 0, alloc
, allocBig
);
4346 private void LzmaEnc_SetInputBuf(CLzmaEnc
*p
, const ubyte *src
, usize srcLen
)
4348 (p
.matchFinderBase
).directInput
= 1;
4349 (p
.matchFinderBase
).bufferBase
= cast(ubyte *)src
;
4350 (p
.matchFinderBase
).directInputRem
= srcLen
;
4353 private SRes
LzmaEnc_MemPrepare(CLzmaEncHandle pp
, const ubyte *src
, usize srcLen
,
4354 uint keepWindowSize
, ISzAllocPtr alloc
, ISzAllocPtr allocBig
)
4356 CLzmaEnc
*p
= cast(CLzmaEnc
*)pp
;
4357 LzmaEnc_SetInputBuf(p
, src
, srcLen
);
4360 LzmaEnc_SetDataSize(pp
, srcLen
);
4361 return LzmaEnc_AllocAndInit(p
, keepWindowSize
, alloc
, allocBig
);
4364 private void LzmaEnc_Finish(CLzmaEncHandle pp
)
4370 enum SanityMagic
= 0xb0f0debeU
;
4372 struct CLzmaEnc_SeqOutStreamBuf
{
4374 version(LZMA_SANITY_MAGIC
) {
4384 #define MY_offsetof(type, m) ((size_t)&(((type *)0)->m))
4385 #define MY_container_of(ptr, type, m) ((type *)(void *)((char *)(void *)(1 ? (ptr) : &((type *)0)->m) - MY_offsetof(type, m)))
4386 #define CONTAINER_FROM_VTBL(ptr, type, m) MY_container_of(ptr, type, m)
4389 private usize
SeqOutStreamBuf_Write(ISeqOutStream
* pp
, const(void)* data
, usize size
) nothrow
4391 //CLzmaEnc_SeqOutStreamBuf *p = CONTAINER_FROM_VTBL(pp, CLzmaEnc_SeqOutStreamBuf, vt);
4392 CLzmaEnc_SeqOutStreamBuf
* p
= cast(CLzmaEnc_SeqOutStreamBuf
*)(cast(ubyte*)pp
-CLzmaEnc_SeqOutStreamBuf
.vt
.offsetof
);
4393 version(LZMA_SANITY_MAGIC
) {
4394 assert(p
.magic
== SanityMagic
);
4396 if (p
.overflow
) return 0; // ignore all writes
4399 p
.overflow
= 1/*True*/;
4400 if (size
== 0) return 0;
4402 import core
.stdc
.string
: memcpy
;
4403 memcpy(p
.data
, data
, size
);
4411 private SRes
LzmaEnc_Encode2(CLzmaEnc
*p
, ICompressProgress
*progress
)
4417 res
= LzmaEnc_CodeOneBlock(p
, 0, 0);
4418 if (res
!= SZ_OK || p
.finished
)
4422 //res = ICompressProgress_Progress(progress, p.nowPos64, mixin(RangeEnc_GetProcessed!"&p.rc"));
4423 res
= progress
.Progress(progress
, p
.nowPos64
, mixin(RangeEnc_GetProcessed
!"&p.rc"));
4426 res
= SZ_ERROR_PROGRESS
;
4435 if (res == SZ_OK && !Inline_MatchFinder_IsFinishedOK(&(p.matchFinderBase)))
4436 res = SZ_ERROR_FAIL;
4444 //==========================================================================
4448 //==========================================================================
4449 public SRes
LzmaEnc_Encode (CLzmaEncHandle pp
, ISeqOutStream
*outStream
, ISeqInStream
*inStream
,
4450 ICompressProgress
*progress
, ISzAllocPtr alloc
, ISzAllocPtr allocBig
)
4452 int rinres
= LzmaEnc_Prepare(pp
, outStream
, inStream
, alloc
, allocBig
);
4453 if (rinres
!= 0) return rinres
;
4454 return LzmaEnc_Encode2(cast(CLzmaEnc
*)pp
, progress
);
4458 //==========================================================================
4460 // LzmaEnc_WriteProperties
4462 //==========================================================================
4463 public SRes
LzmaEnc_WriteProperties (CLzmaEncHandle pp
, ubyte* props
, uint* size
) @nogc {
4464 if (*size
< LZMA_PROPS_SIZE
) return SZ_ERROR_PARAM
;
4465 *size
= LZMA_PROPS_SIZE
;
4467 const(CLzmaEnc
)* p
= cast(const(CLzmaEnc
)*)pp
;
4468 immutable uint dictSize
= p
.dictSize
;
4470 props
[0] = cast(ubyte)((p
.pb
* 5 + p
.lp
) * 9 + p
.lc
);
4472 // we write aligned dictionary value to properties for lzma decoder
4473 if (dictSize
>= (cast(uint)1 << 21)) {
4474 const uint kDictMask
= (cast(uint)1 << 20) - 1;
4475 v
= (dictSize
+ kDictMask
) & ~kDictMask
;
4476 if (v
< dictSize
) v
= dictSize
;
4480 v
= cast(uint)(2 + (i
& 1)) << (i
>> 1);
4482 } while (v
< dictSize
);
4485 SetUi32(props
+ 1, v
);
4490 //==========================================================================
4492 // LzmaEnc_IsWriteEndMark
4494 //==========================================================================
4495 public uint LzmaEnc_IsWriteEndMark (CLzmaEncHandle pp
) @nogc {
4496 return cast(uint)(cast(CLzmaEnc
*)pp
).writeEndMark
;
4500 //==========================================================================
4502 // LzmaEnc_MemEncode
4504 //==========================================================================
4505 public SRes
LzmaEnc_MemEncode (CLzmaEncHandle pp
, ubyte* dest
, usize
* destLen
, const(ubyte)* src
, usize srcLen
,
4506 int writeEndMark
, ICompressProgress
*progress
, ISzAllocPtr alloc
, ISzAllocPtr allocBig
)
4509 CLzmaEnc
*p
= cast(CLzmaEnc
*)pp
;
4511 CLzmaEnc_SeqOutStreamBuf outStream
;
4512 version(LZMA_SANITY_MAGIC
) {
4513 outStream
.magic
= SanityMagic
;
4516 //outStream.vt.Write = &SeqOutStreamBuf_Write;
4517 outStream
.vt
.Write
= delegate usize (ISeqOutStream
* pp
, const(void)* data
, usize size
) nothrow {
4518 return SeqOutStreamBuf_Write(pp
, data
, size
);
4521 outStream
.data
= dest
;
4522 outStream
.rem
= *destLen
;
4523 outStream
.overflow
= 0/*False*/;
4525 p
.writeEndMark
= writeEndMark
;
4526 p
.rc
.outStream
= &outStream
.vt
;
4528 res
= LzmaEnc_MemPrepare(pp
, src
, srcLen
, 0, alloc
, allocBig
);
4532 res
= LzmaEnc_Encode2(p
, progress
);
4533 if (res
== SZ_OK
&& p
.nowPos64
!= srcLen
)
4534 res
= SZ_ERROR_FAIL
;
4537 *destLen
-= outStream
.rem
;
4538 if (outStream
.overflow
)
4539 return SZ_ERROR_OUTPUT_EOF
;
4544 //==========================================================================
4548 //==========================================================================
4549 public SRes
LzmaEncode (ubyte* dest
, usize
* destLen
, const(ubyte)* src
, usize srcLen
,
4550 const(CLzmaEncProps
)* props
, ubyte* propsEncoded
, uint* propsSize
,
4551 int writeEndMark
, ICompressProgress
*progress
, ISzAllocPtr alloc
, ISzAllocPtr allocBig
)
4553 CLzmaEnc
*p
= cast(CLzmaEnc
*)LzmaEnc_Create(alloc
);
4556 return SZ_ERROR_MEM
;
4558 res
= LzmaEnc_SetProps(p
, props
);
4561 res
= LzmaEnc_WriteProperties(p
, propsEncoded
, propsSize
);
4563 res
= LzmaEnc_MemEncode(p
, dest
, destLen
, src
, srcLen
,
4564 writeEndMark
, progress
, alloc
, allocBig
);
4567 LzmaEnc_Destroy(p
, alloc
, allocBig
);