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 private import iv
.dlzma
;
19 // ////////////////////////////////////////////////////////////////////////// //
20 // ////////////////////////////////////////////////////////////////////////// //
21 // ////////////////////////////////////////////////////////////////////////// //
22 // ////////////////////////////////////////////////////////////////////////// //
25 private void SetUi32 (const(void)* p
, in uint v
) nothrow @trusted @nogc { pragma(inline
, true); *(cast(uint*)p
) = v
; }
26 private ushort GetUi16 (const(void)* v
) nothrow @trusted @nogc { pragma(inline
, true); return *(cast(const(ushort)*)v
); }
34 uint streamPos
; /* wrap over Zero is allowed (streamPos < pos). Use (uint32_t)(streamPos - pos) */
38 uint cyclicBufferSize
; /* it must be = (historySize + 1) */
40 ubyte streamEndWasReached
;
67 ulong expectedDataSize
;
70 //#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((const ubyte *)(p)->buffer)
72 //#define Inline_MatchFinder_GetNumAvailableBytes(p) ((uint)((p)->streamPos - (p)->pos))
73 enum Inline_MatchFinder_GetNumAvailableBytes(string p
) = `(cast(uint)((`~p
~`).streamPos - (`~p
~`).pos))`;
76 #define Inline_MatchFinder_IsFinishedOK(p) \
77 ((p)->streamEndWasReached \
78 && (p)->streamPos == (p)->pos \
79 && (!(p)->directInput || (p)->directInputRem == 0))
83 int MatchFinder_NeedMove(CMatchFinder *p);
84 /* uint8_t *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); */
85 void MatchFinder_MoveBlock(CMatchFinder *p);
86 void MatchFinder_ReadIfRequired(CMatchFinder *p);
88 void MatchFinder_Construct(CMatchFinder *p);
92 keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
94 int MatchFinder_Create(CMatchFinder *p, uint historySize,
95 uint keepAddBufferBefore, uint matchMaxLen, uint keepAddBufferAfter,
97 void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc);
98 void MatchFinder_Normalize3(uint subValue, CLzRef *items, usize numItems);
99 // void MatchFinder_ReduceOffsets(CMatchFinder *p, uint32_t subValue);
103 #define Inline_MatchFinder_InitPos(p, val) \
105 (p)->streamPos = (val);
109 #define Inline_MatchFinder_ReduceOffsets(p, subValue) \
110 (p)->pos -= (subValue); \
111 (p)->streamPos -= (subValue);
115 uint* GetMatchesSpec1(uint lenLimit, uint curMatch, uint pos, const ubyte *buffer, CLzRef *son,
116 usize _cyclicBufferPos, uint _cyclicBufferSize, uint _cutValue,
117 uint *distances, uint maxLen);
122 Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
123 Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
126 alias Mf_Init_Func
= void function (void *object
);
127 alias Mf_GetNumAvailableBytes_Func
= uint function (void *object
);
128 alias Mf_GetPointerToCurrentPos_Func
= const(ubyte)* function (void *object
);
129 alias Mf_GetMatches_Func
= uint* function (void *object
, uint *distances
);
130 alias Mf_Skip_Func
= void function (void *object
, uint);
132 struct /*_IMatchFinder*/ IMatchFinder2
{
134 Mf_GetNumAvailableBytes_Func GetNumAvailableBytes
;
135 Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos
;
136 Mf_GetMatches_Func GetMatches
;
141 void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder2 *vTable);
143 void MatchFinder_Init_LowHash(CMatchFinder *p);
144 void MatchFinder_Init_HighHash(CMatchFinder *p);
145 void MatchFinder_Init_4(CMatchFinder *p);
146 void MatchFinder_Init(CMatchFinder *p);
148 uint* Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, uint *distances);
149 uint* Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, uint *distances);
151 void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, uint num);
152 void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, uint num);
154 void LzFindPrepare(void);
158 /* LzHash.h -- HASH functions for LZ algorithms
159 2019-10-30 : Igor Pavlov : Public domain */
162 (kHash2Size >= (1 << 8)) : Required
163 (kHash3Size >= (1 << 16)) : Required
166 enum kHash2Size
= (1 << 10);
167 enum kHash3Size
= (1 << 16);
168 // #define kHash4Size (1 << 20)
170 enum kFix3HashSize
= (kHash2Size
);
171 enum kFix4HashSize
= (kHash2Size
+ kHash3Size
);
172 // #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
175 We use up to 3 crc values for hash:
179 (Shift_1 = 5) and (Shift_2 = 10) is good tradeoff.
180 Small values for Shift are not good for collision rate.
181 Big value for Shift_2 increases the minimum size
182 of hash table, that will be slow for small files.
185 enum kLzHash_CrcShift_1
= 5;
186 enum kLzHash_CrcShift_2
= 10;
190 enum kBlockMoveAlign
= (1 << 7); // alignment for memmove()
191 enum kBlockSizeAlign
= (1 << 16); // alignment for block allocation
192 enum kBlockSizeReserveMin
= (1 << 24); // it's 1/256 from 4 GB dictinary
194 enum kEmptyHashValue
= 0;
196 enum kMaxValForNormalize
= cast(uint)0;
197 // #define kMaxValForNormalize ((uint)(1 << 20) + 0xFFF) // for debug
199 // #define kNormalizeAlign (1 << 7) // alignment for speculated accesses
202 // #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
203 enum kFix5HashSize
= kFix4HashSize
;
205 // (crc[0 ... 255] & 0xFF) provides one-to-one correspondence to [0 ... 255]
209 if (cur[0]) and (h2) match, then cur[1] also match
210 if (cur[0]) and (hv) match, then cur[1] and cur[2] also match
213 uint temp
= p
.crc
[cur
[0]] ^ cur
[1];
214 h2
= temp
& (kHash2Size
- 1);
215 hv
= (temp ^
(cast(uint)cur
[2] << 8)) & p
.hashMask
;
219 uint temp
= p
.crc
[cur
[0]] ^ cur
[1];
220 h2
= temp
& (kHash2Size
- 1);
221 temp ^
= (cast(uint)cur
[2] << 8);
222 h3
= temp
& (kHash3Size
- 1);
223 hv
= (temp ^
(p
.crc
[cur
[3]] << kLzHash_CrcShift_1
)) & p
.hashMask
;
227 uint temp
= p
.crc
[cur
[0]] ^ cur
[1];
228 h2
= temp
& (kHash2Size
- 1);
229 temp ^
= (cast(uint)cur
[2] << 8);
230 h3
= temp
& (kHash3Size
- 1);
231 temp ^
= (p
.crc
[cur
[3]] << kLzHash_CrcShift_1
);
232 /* h4 = temp & p->hash4Mask; */ /* (kHash4Size - 1); */
233 hv
= (temp ^
(p
.crc
[cur
[4]] << kLzHash_CrcShift_2
)) & p
.hashMask
;
236 enum HASH_ZIP_CALC
= `hv = ((cur[2] | (cast(uint)cur[0] << 8)) ^ p.crc[cur[1]]) & 0xFFFF;`;
239 private void LzInWindow_Free(CMatchFinder
*p
, ISzAllocPtr alloc
)
243 ISzAlloc_Free(alloc
, p
.bufferBase
);
249 private int LzInWindow_Create2(CMatchFinder
*p
, uint blockSize
, ISzAllocPtr alloc
)
253 if (!p
.bufferBase || p
.blockSize
!= blockSize
)
256 LzInWindow_Free(p
, alloc
);
257 p
.blockSize
= blockSize
;
258 // blockSizeT = blockSize;
260 // printf("\nblockSize = 0x%x\n", blockSize);
263 // we can allocate 4GiB, but still use uint for (p->blockSize)
264 // we use uint type for (p->blockSize), because
265 // we don't want to wrap over 4 GiB,
266 // when we use (p->streamPos - p->pos) that is uint.
267 if (blockSize >= (uint)0 - (uint)kBlockSizeAlign)
269 blockSizeT = ((usize)1 << 32);
270 printf("\nchanged to blockSizeT = 4GiB\n");
275 p
.bufferBase
= cast(ubyte *)ISzAlloc_Alloc(alloc
, blockSize
);
276 // printf("\nbufferBase = %p\n", p->bufferBase);
277 // return 0; // for debug
279 return (p
.bufferBase
!= null);
282 private const(ubyte)* MatchFinder_GetPointerToCurrentPos(CMatchFinder
*p
) { pragma(inline
, true); return p
.buffer
; }
284 private uint MatchFinder_GetNumAvailableBytes(CMatchFinder
*p
) { pragma(inline
, true); return mixin(Inline_MatchFinder_GetNumAvailableBytes
!"p"); }
288 private void MatchFinder_ReadBlock(CMatchFinder
*p
)
290 if (p
.streamEndWasReached || p
.result
!= SZ_OK
)
293 /* We use (p->streamPos - p->pos) value.
294 (p->streamPos < p->pos) is allowed. */
298 uint curSize
= 0xFFFFFFFF - mixin(Inline_MatchFinder_GetNumAvailableBytes
!"p");
299 if (curSize
> p
.directInputRem
)
300 curSize
= cast(uint)p
.directInputRem
;
301 p
.directInputRem
-= curSize
;
302 p
.streamPos
+= curSize
;
303 if (p
.directInputRem
== 0)
304 p
.streamEndWasReached
= 1;
310 ubyte *dest
= p
.buffer
+ mixin(Inline_MatchFinder_GetNumAvailableBytes
!"p");
311 usize size
= cast(usize
)(p
.bufferBase
+ p
.blockSize
- dest
);
314 /* we call ReadBlock() after NeedMove() and MoveBlock().
315 NeedMove() and MoveBlock() povide more than (keepSizeAfter)
316 to the end of (blockSize).
317 So we don't execute this branch in normal code flow.
318 We can go here, if we will call ReadBlock() before NeedMove(), MoveBlock().
320 // p->result = SZ_ERROR_FAIL; // we can show error here
325 // if (size > kRead) size = kRead; // for debug
327 //p.result = ISeqInStream_Read(p.stream, dest, &size);
328 p
.result
= p
.stream
.Read(p
.stream
, dest
, &size
);
329 if (p
.result
!= SZ_OK
)
333 p
.streamEndWasReached
= 1;
336 p
.streamPos
+= cast(uint)size
;
337 if (mixin(Inline_MatchFinder_GetNumAvailableBytes
!"p") > p
.keepSizeAfter
)
339 /* here and in another (p->keepSizeAfter) checks we keep on 1 byte more than was requested by Create() function
340 (Inline_MatchFinder_GetNumAvailableBytes(p) >= p->keepSizeAfter) - minimal required size */
343 // on exit: (p->result != SZ_OK || p->streamEndWasReached || Inline_MatchFinder_GetNumAvailableBytes(p) > p->keepSizeAfter)
349 private void MatchFinder_MoveBlock (CMatchFinder
*p
) @nogc {
350 import core
.stdc
.string
: memmove
;
351 const usize offset
= cast(usize
)(p
.buffer
- p
.bufferBase
) - p
.keepSizeBefore
;
352 const usize keepBefore
= (offset
& (kBlockMoveAlign
- 1)) + p
.keepSizeBefore
;
353 p
.buffer
= p
.bufferBase
+ keepBefore
;
354 memmove(p
.bufferBase
,
355 p
.bufferBase
+ (offset
& ~(cast(usize
)kBlockMoveAlign
- 1)),
356 keepBefore
+ cast(usize
)mixin(Inline_MatchFinder_GetNumAvailableBytes
!"p"));
359 /* We call MoveBlock() before ReadBlock().
360 So MoveBlock() can be wasteful operation, if the whole input data
361 can fit in current block even without calling MoveBlock().
362 in important case where (dataSize <= historySize)
363 condition (p->blockSize > dataSize + p->keepSizeAfter) is met
364 So there is no MoveBlock() in that case case.
367 private int MatchFinder_NeedMove (CMatchFinder
*p
) @nogc {
370 if (p
.streamEndWasReached || p
.result
!= SZ_OK
)
372 return (cast(usize
)(p
.bufferBase
+ p
.blockSize
- p
.buffer
) <= p
.keepSizeAfter
);
375 private void MatchFinder_ReadIfRequired (CMatchFinder
*p
) {
376 if (p
.keepSizeAfter
>= mixin(Inline_MatchFinder_GetNumAvailableBytes
!"p"))
377 MatchFinder_ReadBlock(p
);
381 private void MatchFinder_SetDefaultSettings (CMatchFinder
* p
) @nogc {
388 enum kCrcPoly
= 0xEDB88320;
390 private void MatchFinder_Construct (CMatchFinder
* p
) @nogc {
395 p
.expectedDataSize
= cast(ulong)cast(long)-1;
396 MatchFinder_SetDefaultSettings(p
);
398 for (i
= 0; i
< 256; i
++)
400 uint r
= cast(uint)i
;
402 for (j
= 0; j
< 8; j
++)
403 r
= (r
>> 1) ^
(kCrcPoly
& (cast(uint)0 - (r
& 1)));
408 private void MatchFinder_FreeThisClassMemory(CMatchFinder
*p
, ISzAllocPtr alloc
)
410 ISzAlloc_Free(alloc
, p
.hash
);
414 private void MatchFinder_Free(CMatchFinder
*p
, ISzAllocPtr alloc
)
416 MatchFinder_FreeThisClassMemory(p
, alloc
);
417 LzInWindow_Free(p
, alloc
);
420 private CLzRef
* AllocRefs(usize num
, ISzAllocPtr alloc
)
422 usize sizeInBytes
= cast(usize
)num
* CLzRef
.sizeof
;
423 if (sizeInBytes
/ CLzRef
.sizeof
!= num
)
425 return cast(CLzRef
*)ISzAlloc_Alloc(alloc
, sizeInBytes
);
428 static assert(kBlockSizeReserveMin
>= kBlockSizeAlign
* 2, "Stop_Compiling_Bad_Reserve");
432 private uint GetBlockSize (CMatchFinder
* p
, uint historySize
) @nogc {
433 uint blockSize
= (p
.keepSizeBefore
+ p
.keepSizeAfter
);
435 if (historySize > kMaxHistorySize)
438 // printf("\nhistorySize == 0x%x\n", historySize);
440 if (p
.keepSizeBefore
< historySize || blockSize
< p
.keepSizeBefore
) // if 32-bit overflow
444 const uint kBlockSizeMax
= cast(uint)0 - cast(uint)kBlockSizeAlign
;
445 const uint rem
= kBlockSizeMax
- blockSize
;
446 const uint reserve
= (blockSize
>> (blockSize
< (cast(uint)1 << 30) ?
1 : 2))
447 + (1 << 12) + kBlockMoveAlign
+ kBlockSizeAlign
; // do not overflow 32-bit here
448 if (blockSize
>= kBlockSizeMax
449 || rem
< kBlockSizeReserveMin
) // we reject settings that will be slow
452 blockSize
= kBlockSizeMax
;
455 blockSize
+= reserve
;
456 blockSize
&= ~cast(uint)(kBlockSizeAlign
- 1);
459 // printf("\n LzFind_blockSize = %x\n", blockSize);
460 // printf("\n LzFind_blockSize = %d\n", blockSize >> 20);
465 private int MatchFinder_Create(CMatchFinder
*p
, uint historySize
,
466 uint keepAddBufferBefore
, uint matchMaxLen
, uint keepAddBufferAfter
,
469 /* we need one additional byte in (p->keepSizeBefore),
470 since we use MoveBlock() after (p->pos++) and before dictionary using */
471 // keepAddBufferBefore = (uint)0xFFFFFFFF - (1 << 22); // for debug
472 p
.keepSizeBefore
= historySize
+ keepAddBufferBefore
+ 1;
474 keepAddBufferAfter
+= matchMaxLen
;
475 /* we need (p->keepSizeAfter >= p->numHashBytes) */
476 if (keepAddBufferAfter
< p
.numHashBytes
)
477 keepAddBufferAfter
= p
.numHashBytes
;
478 // keepAddBufferAfter -= 2; // for debug
479 p
.keepSizeAfter
= keepAddBufferAfter
;
483 if (p
.directInput ||
LzInWindow_Create2(p
, GetBlockSize(p
, historySize
), alloc
))
485 const uint newCyclicBufferSize
= historySize
+ 1; // do not change it
487 p
.matchMaxLen
= matchMaxLen
;
492 if (p
.numHashBytes
!= 2)
495 if (hs
> p
.expectedDataSize
)
496 hs
= cast(uint)p
.expectedDataSize
;
503 // we propagated 16 bits in (hs). Low 16 bits must be set later
507 if (p
.numHashBytes
== 3)
511 /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */
514 // hs = ((uint)1 << 25) - 1; // for test
516 // (hash_size >= (1 << 16)) : Required for (numHashBytes > 2)
517 hs |
= (1 << 16) - 1; /* don't change it! */
519 // bt5: we adjust the size with recommended minimum size
520 if (p
.numHashBytes
>= 5)
521 hs |
= (256 << kLzHash_CrcShift_2
) - 1;
530 // hs4 = (1 << 16); // for test
531 p->hash4Mask = hs4 - 1;
534 if (p
.numHashBytes
> 2) p
.fixedHashSize
+= kHash2Size
;
535 if (p
.numHashBytes
> 3) p
.fixedHashSize
+= kHash3Size
;
536 // if (p->numHashBytes > 4) p->fixedHashSize += hs4; // kHash4Size;
537 hs
+= p
.fixedHashSize
;
543 p
.historySize
= historySize
;
545 p
.cyclicBufferSize
= newCyclicBufferSize
; // it must be = (historySize + 1)
547 numSons
= newCyclicBufferSize
;
550 newSize
= hs
+ numSons
;
552 // aligned size is not required here, but it can be better for some loops
553 enum NUM_REFS_ALIGN_MASK
= 0xF;
554 newSize
= (newSize
+ NUM_REFS_ALIGN_MASK
) & ~cast(usize
)NUM_REFS_ALIGN_MASK
;
556 if (p
.hash
&& p
.numRefs
== newSize
)
559 MatchFinder_FreeThisClassMemory(p
, alloc
);
561 p
.hash
= AllocRefs(newSize
, alloc
);
565 p
.son
= p
.hash
+ p
.hashSizeSum
;
571 MatchFinder_Free(p
, alloc
);
576 private void MatchFinder_SetLimits (CMatchFinder
* p
) @nogc {
578 uint n
= kMaxValForNormalize
- p
.pos
;
580 n
= cast(uint)cast(int)-1; // we allow (pos == 0) at start even with (kMaxValForNormalize == 0)
582 k
= p
.cyclicBufferSize
- p
.cyclicBufferPos
;
586 k
= mixin(Inline_MatchFinder_GetNumAvailableBytes
!"p");
588 const uint ksa
= p
.keepSizeAfter
;
589 uint mm
= p
.matchMaxLen
;
591 k
-= ksa
; // we must limit exactly to keepSizeAfter for ReadBlock
594 // the limitation for (p->lenLimit) update
595 k
-= mm
; // optimization : to reduce the number of checks
597 // k = 1; // non-optimized version : for debug
610 p
.posLimit
= p
.pos
+ n
;
614 private void MatchFinder_Init_LowHash (CMatchFinder
* p
) @nogc {
616 CLzRef
*items
= p
.hash
;
617 const usize numItems
= p
.fixedHashSize
;
618 for (i
= 0; i
< numItems
; i
++)
619 items
[i
] = kEmptyHashValue
;
623 private void MatchFinder_Init_HighHash (CMatchFinder
* p
) @nogc {
625 CLzRef
*items
= p
.hash
+ p
.fixedHashSize
;
626 const usize numItems
= cast(usize
)p
.hashMask
+ 1;
627 for (i
= 0; i
< numItems
; i
++)
628 items
[i
] = kEmptyHashValue
;
632 private void MatchFinder_Init_4 (CMatchFinder
* p
) @nogc {
633 p
.buffer
= p
.bufferBase
;
635 /* kEmptyHashValue = 0 (Zero) is used in hash tables as NO-VALUE marker.
636 the code in CMatchFinderMt expects (pos = 1) */
639 1; // it's smallest optimal value. do not change it
643 p
.streamEndWasReached
= 0;
647 // (CYC_TO_POS_OFFSET == 0) is expected by some optimized code
648 enum CYC_TO_POS_OFFSET
= 0;
649 // #define CYC_TO_POS_OFFSET 1 // for debug
651 private void MatchFinder_Init (CMatchFinder
* p
) {
652 MatchFinder_Init_HighHash(p
);
653 MatchFinder_Init_LowHash(p
);
654 MatchFinder_Init_4(p
);
656 MatchFinder_ReadBlock(p
);
658 /* if we init (cyclicBufferPos = pos), then we can use one variable
659 instead of both (cyclicBufferPos) and (pos) : only before (cyclicBufferPos) wrapping */
660 p
.cyclicBufferPos
= (p
.pos
- CYC_TO_POS_OFFSET
); // init with relation to (pos)
661 // p->cyclicBufferPos = 0; // smallest value
662 // p->son[0] = p->son[1] = 0; // unused: we can init skipped record for speculated accesses.
663 MatchFinder_SetLimits(p
);
668 // kEmptyHashValue must be zero
669 // #define SASUB_32(i) v = items[i]; m = v - subValue; if (v < subValue) m = kEmptyHashValue; items[i] = m;
670 //#define SASUB_32(i) v = items[i]; if (v < subValue) v = subValue; items[i] = v - subValue;
671 enum SASUB_32(string i
) = `v = items[`~i
~`]; if (v < subValue) v = subValue; items[`~i
~`] = v - subValue;`;
674 private void LzFind_SaturSub_32 (uint subValue
, CLzRef
* items
, const(CLzRef
)* lim
) @nogc {
688 while (items
!= lim
);
693 private void MatchFinder_Normalize3 (uint subValue
, CLzRef
* items
, usize numItems
) @nogc {
694 enum K_NORM_ALIGN_BLOCK_SIZE
= (1 << 6);
698 for (; numItems
!= 0 && (cast(uint)cast(ptrdiff_t
)items
& (K_NORM_ALIGN_BLOCK_SIZE
- 1)) != 0; numItems
--)
706 enum K_NORM_ALIGN_MASK
= (K_NORM_ALIGN_BLOCK_SIZE
/ 4 - 1);
707 lim
= items
+ (numItems
& ~cast(usize
)K_NORM_ALIGN_MASK
);
708 numItems
&= K_NORM_ALIGN_MASK
;
711 LzFind_SaturSub_32(subValue
, items
, lim
);
717 for (; numItems
!= 0; numItems
--)
727 // call MatchFinder_CheckLimits() only after (p->pos++) update
730 private void MatchFinder_CheckLimits (CMatchFinder
* p
) {
731 if (// !p->streamEndWasReached && p->result == SZ_OK &&
732 p
.keepSizeAfter
== mixin(Inline_MatchFinder_GetNumAvailableBytes
!"p"))
734 // we try to read only in exact state (p->keepSizeAfter == Inline_MatchFinder_GetNumAvailableBytes(p))
735 if (MatchFinder_NeedMove(p
))
736 MatchFinder_MoveBlock(p
);
737 MatchFinder_ReadBlock(p
);
740 if (p
.pos
== kMaxValForNormalize
)
741 if (mixin(Inline_MatchFinder_GetNumAvailableBytes
!"p") >= p
.numHashBytes
) // optional optimization for last bytes of data.
743 if we disable normalization for last bytes of data, and
744 if (data_size == 4 GiB), we don't call wastfull normalization,
745 but (pos) will be wrapped over Zero (0) in that case.
746 And we cannot resume later to normal operation
749 // MatchFinder_Normalize(p);
750 /* after normalization we need (p->pos >= p->historySize + 1); */
751 /* we can reduce subValue to aligned value, if want to keep alignment
752 of (p->pos) and (p->buffer) for speculated accesses. */
753 const uint subValue
= (p
.pos
- p
.historySize
- 1) /* & ~(uint)(kNormalizeAlign - 1) */;
754 // const uint subValue = (1 << 15); // for debug
755 // printf("\nMatchFinder_Normalize() subValue == 0x%x\n", subValue);
756 usize numSonRefs
= p
.cyclicBufferSize
;
760 //Inline_MatchFinder_ReduceOffsets(p, subValue);
762 p
.streamPos
-= subValue
;
764 MatchFinder_Normalize3(subValue
, p
.hash
, cast(usize
)p
.hashSizeSum
+ numSonRefs
);
767 if (p
.cyclicBufferPos
== p
.cyclicBufferSize
)
768 p
.cyclicBufferPos
= 0;
770 MatchFinder_SetLimits(p
);
778 private uint * Hc_GetMatchesSpec (usize lenLimit
, uint curMatch
, uint pos
, const(ubyte)* cur
, CLzRef
*son
,
779 usize _cyclicBufferPos
, uint _cyclicBufferSize
, uint cutValue
,
780 uint *d
, uint maxLen
) @nogc
783 son[_cyclicBufferPos] = curMatch;
786 uint delta = pos - curMatch;
787 if (cutValue-- == 0 || delta >= _cyclicBufferSize)
790 const ubyte *pb = cur - delta;
791 curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
792 if (pb[maxLen] == cur[maxLen] && *pb == *cur)
795 while (++len != lenLimit)
796 if (pb[len] != cur[len])
811 const(ubyte)* lim
= cur
+ lenLimit
;
812 son
[_cyclicBufferPos
] = curMatch
;
820 // if (curMatch2 >= curMatch) return null;
821 delta
= pos
- curMatch
;
822 if (delta
>= _cyclicBufferSize
)
826 curMatch
= son
[_cyclicBufferPos
- delta
+ ((delta
> _cyclicBufferPos
) ? _cyclicBufferSize
: 0)];
827 diff
= cast(ptrdiff_t
)0 - cast(ptrdiff_t
)delta
;
828 if (cur
[maxLen
] == cur
[cast(ptrdiff_t
)maxLen
+ diff
])
830 const(ubyte)* c
= cur
;
831 while (*c
== c
[diff
])
835 d
[0] = cast(uint)(lim
- cur
);
841 const uint len
= cast(uint)(c
- cur
);
845 d
[0] = cast(uint)len
;
860 private uint* GetMatchesSpec1 (uint lenLimit
, uint curMatch
, uint pos
, const(ubyte)* cur
, CLzRef
*son
,
861 usize _cyclicBufferPos
, uint _cyclicBufferSize
, uint cutValue
,
862 uint *d
, uint maxLen
) @nogc
864 CLzRef
*ptr0
= son
+ (cast(usize
)_cyclicBufferPos
<< 1) + 1;
865 CLzRef
*ptr1
= son
+ (cast(usize
)_cyclicBufferPos
<< 1);
866 uint len0
= 0, len1
= 0;
870 // if (curMatch >= pos) { *ptr0 = *ptr1 = kEmptyHashValue; return null; }
872 cmCheck
= cast(uint)(pos
- _cyclicBufferSize
);
873 if (cast(uint)pos
<= _cyclicBufferSize
)
876 if (cmCheck
< curMatch
)
879 const uint delta
= pos
- curMatch
;
881 CLzRef
*pair
= son
+ (cast(usize
)(_cyclicBufferPos
- delta
+ ((delta
> _cyclicBufferPos
) ? _cyclicBufferSize
: 0)) << 1);
882 const ubyte *pb
= cur
- delta
;
883 uint len
= (len0
< len1 ? len0
: len1
);
884 const uint pair0
= pair
[0];
885 if (pb
[len
] == cur
[len
])
887 if (++len
!= lenLimit
&& pb
[len
] == cur
[len
])
888 while (++len
!= lenLimit
)
889 if (pb
[len
] != cur
[len
])
893 maxLen
= cast(uint)len
;
894 *d
++ = cast(uint)len
;
904 if (pb
[len
] < cur
[len
])
907 // const uint curMatch2 = pair[1];
908 // if (curMatch2 >= curMatch) { *ptr0 = *ptr1 = kEmptyHashValue; return null; }
909 // curMatch = curMatch2;
923 while(--cutValue
&& cmCheck
< curMatch
);
925 *ptr0
= *ptr1
= kEmptyHashValue
;
930 private void SkipMatchesSpec (uint lenLimit
, uint curMatch
, uint pos
, const(ubyte)* cur
, CLzRef
*son
,
931 usize _cyclicBufferPos
, uint _cyclicBufferSize
, uint cutValue
) @nogc
933 CLzRef
*ptr0
= son
+ (cast(usize
)_cyclicBufferPos
<< 1) + 1;
934 CLzRef
*ptr1
= son
+ (cast(usize
)_cyclicBufferPos
<< 1);
935 uint len0
= 0, len1
= 0;
939 cmCheck
= cast(uint)(pos
- _cyclicBufferSize
);
940 if (cast(uint)pos
<= _cyclicBufferSize
)
943 if (// curMatch >= pos || // failure
947 const uint delta
= pos
- curMatch
;
949 CLzRef
*pair
= son
+ (cast(usize
)(_cyclicBufferPos
- delta
+ ((delta
> _cyclicBufferPos
) ? _cyclicBufferSize
: 0)) << 1);
950 const ubyte *pb
= cur
- delta
;
951 uint len
= (len0
< len1 ? len0
: len1
);
952 if (pb
[len
] == cur
[len
])
954 while (++len
!= lenLimit
)
955 if (pb
[len
] != cur
[len
])
966 if (pb
[len
] < cur
[len
])
982 while(--cutValue
&& cmCheck
< curMatch
);
984 *ptr0
= *ptr1
= kEmptyHashValue
;
992 { const uint pos1
= p
.pos
+ 1; p
.pos
= pos1
; if (pos1
== p
.posLimit
) MatchFinder_CheckLimits(p
); }
995 enum MOVE_POS_RET
= MOVE_POS
~`return distances;`;
998 private void MatchFinder_MovePos (CMatchFinder
*p
) {
999 pragma(inline
, true);
1000 /* we go here at the end of stream data, when (avail < num_hash_bytes)
1001 We don't update sons[cyclicBufferPos << btMode].
1002 So (sons) record will contain junk. And we cannot resume match searching
1003 to normal operation, even if we will provide more input data in buffer.
1004 p->sons[p->cyclicBufferPos << p->btMode] = 0; // kEmptyHashValue
1006 p->sons[(p->cyclicBufferPos << p->btMode) + 1] = 0; // kEmptyHashValue
1011 enum GET_MATCHES_HEADER2(string minLen
, string ret_op
) = `
1012 uint lenLimit; uint hv; ubyte *cur; uint curMatch;
1013 lenLimit = cast(uint)p.lenLimit; { if (lenLimit < `~minLen
~`) { MatchFinder_MovePos(p); `~ret_op
~`; } }
1017 enum GET_MATCHES_HEADER(string minLen
) = GET_MATCHES_HEADER2
!(minLen
, "return distances");
1018 //enum SKIP_HEADER(string minLen) = `do { `~GET_MATCHES_HEADER2!(minLen, "continue");
1019 enum SKIP_HEADER(string minLen
) = GET_MATCHES_HEADER2
!(minLen
, "continue");
1021 enum MF_PARAMS(string p
) = `lenLimit, curMatch, `~p
~`.pos, `~p
~`.buffer, `~p
~`.son, `~p
~`.cyclicBufferPos, `~p
~`.cyclicBufferSize, `~p
~`.cutValue`;
1023 //#define SKIP_FOOTER SkipMatchesSpec(MF_PARAMS(p)); mixin(MOVE_POS); } while (--num);
1024 enum SKIP_FOOTER
= `SkipMatchesSpec(`~MF_PARAMS
!"p"~`);`~MOVE_POS
;
1027 enum GET_MATCHES_FOOTER_BASE(string _maxLen_
, string func
) = `
1028 distances = `~func
~`(`~MF_PARAMS
!"p"~`, distances, cast(uint)`~_maxLen_
~`);`~MOVE_POS_RET
;
1030 enum GET_MATCHES_FOOTER_BT(string _maxLen_
) = GET_MATCHES_FOOTER_BASE
!(_maxLen_
, "GetMatchesSpec1");
1032 enum GET_MATCHES_FOOTER_HC(string _maxLen_
) = GET_MATCHES_FOOTER_BASE
!(_maxLen_
, "Hc_GetMatchesSpec");
1036 enum UPDATE_maxLen
= q
{
1037 const ptrdiff_t diff
= cast(ptrdiff_t
)0 - cast(ptrdiff_t
)d2
;
1038 const(ubyte)* c
= cur
+ maxLen
;
1039 const(ubyte)* lim
= cur
+ lenLimit
;
1040 for (; c
!= lim
; c
++) if (*(c
+ diff
) != *c
) break;
1041 maxLen
= cast(uint)(c
- cur
);
1045 private uint* Bt2_MatchFinder_GetMatches (CMatchFinder
* p
, uint* distances
) {
1046 mixin(GET_MATCHES_HEADER
!"2");
1048 curMatch
= p
.hash
[hv
];
1050 mixin(GET_MATCHES_FOOTER_BT
!"1");
1053 private uint* Bt3Zip_MatchFinder_GetMatches (CMatchFinder
* p
, uint* distances
) {
1054 mixin(GET_MATCHES_HEADER
!"3");
1055 mixin(HASH_ZIP_CALC
);
1056 curMatch
= p
.hash
[hv
];
1058 mixin(GET_MATCHES_FOOTER_BT
!"2");
1063 mmm
= p
.cyclicBufferSize
;
1064 if (pos
< mmm
) mmm
= pos
;
1068 private uint* Bt3_MatchFinder_GetMatches (CMatchFinder
* p
, uint* distances
) {
1073 mixin(GET_MATCHES_HEADER
!"3");
1080 d2
= pos
- hash
[h2
];
1082 curMatch
= (hash
+ kFix3HashSize
)[hv
];
1085 (hash
+ kFix3HashSize
)[hv
] = pos
;
1091 if (d2
< mmm
&& *(cur
- d2
) == *cur
)
1093 mixin(UPDATE_maxLen
);
1094 distances
[0] = cast(uint)maxLen
;
1095 distances
[1] = d2
- 1;
1097 if (maxLen
== lenLimit
)
1099 mixin(`SkipMatchesSpec(`~MF_PARAMS
!"p"~`);`);
1100 mixin(MOVE_POS_RET
);
1104 mixin(GET_MATCHES_FOOTER_BT
!"maxLen");
1108 private uint* Bt4_MatchFinder_GetMatches (CMatchFinder
* p
, uint* distances
) {
1110 uint h2
, h3
, d2
, d3
, pos
;
1113 mixin(GET_MATCHES_HEADER
!"4");
1120 d2
= pos
- hash
[h2
];
1121 d3
= pos
- (hash
+ kFix3HashSize
)[h3
];
1122 curMatch
= (hash
+ kFix4HashSize
)[hv
];
1125 (hash
+ kFix3HashSize
)[h3
] = pos
;
1126 (hash
+ kFix4HashSize
)[hv
] = pos
;
1134 if (d2
< mmm
&& *(cur
- d2
) == *cur
)
1137 distances
[1] = d2
- 1;
1139 if (*(cur
- d2
+ 2) == cur
[2])
1141 // distances[-2] = 3;
1143 else if (d3
< mmm
&& *(cur
- d3
) == *cur
)
1146 distances
[1] = d3
- 1;
1152 else if (d3
< mmm
&& *(cur
- d3
) == *cur
)
1155 distances
[1] = d3
- 1;
1161 mixin(UPDATE_maxLen
);
1162 distances
[-2] = cast(uint)maxLen
;
1163 if (maxLen
== lenLimit
)
1165 mixin(`SkipMatchesSpec(`~MF_PARAMS
!"p"~`);`);
1166 mixin(MOVE_POS_RET
);
1171 mixin(GET_MATCHES_FOOTER_BT
!"maxLen");
1175 private uint* Bt5_MatchFinder_GetMatches (CMatchFinder
* p
, uint* distances
) {
1177 uint h2
, h3
, d2
, d3
, maxLen
, pos
;
1179 mixin(GET_MATCHES_HEADER
!"5");
1186 d2
= pos
- hash
[h2
];
1187 d3
= pos
- (hash
+ kFix3HashSize
)[h3
];
1188 // d4 = pos - (hash + kFix4HashSize)[h4];
1190 curMatch
= (hash
+ kFix5HashSize
)[hv
];
1193 (hash
+ kFix3HashSize
)[h3
] = pos
;
1194 // (hash + kFix4HashSize)[h4] = pos;
1195 (hash
+ kFix5HashSize
)[hv
] = pos
;
1203 if (d2
< mmm
&& *(cur
- d2
) == *cur
)
1206 distances
[1] = d2
- 1;
1208 if (*(cur
- d2
+ 2) == cur
[2])
1211 else if (d3
< mmm
&& *(cur
- d3
) == *cur
)
1213 distances
[1] = d3
- 1;
1220 else if (d3
< mmm
&& *(cur
- d3
) == *cur
)
1222 distances
[1] = d3
- 1;
1230 if (*(cur
- d2
+ 3) != cur
[3])
1232 mixin(UPDATE_maxLen
);
1233 distances
[-2] = cast(uint)maxLen
;
1234 if (maxLen
== lenLimit
)
1236 mixin(`SkipMatchesSpec(`~MF_PARAMS
!"p"~`);`);
1237 mixin(MOVE_POS_RET
);
1242 mixin(GET_MATCHES_FOOTER_BT
!"maxLen");
1246 private uint* Hc4_MatchFinder_GetMatches (CMatchFinder
* p
, uint* distances
) {
1248 uint h2
, h3
, d2
, d3
, pos
;
1251 mixin(GET_MATCHES_HEADER
!"4");
1258 d2
= pos
- hash
[h2
];
1259 d3
= pos
- (hash
+ kFix3HashSize
)[h3
];
1260 curMatch
= (hash
+ kFix4HashSize
)[hv
];
1263 (hash
+ kFix3HashSize
)[h3
] = pos
;
1264 (hash
+ kFix4HashSize
)[hv
] = pos
;
1272 if (d2
< mmm
&& *(cur
- d2
) == *cur
)
1275 distances
[1] = d2
- 1;
1277 if (*(cur
- d2
+ 2) == cur
[2])
1279 // distances[-2] = 3;
1281 else if (d3
< mmm
&& *(cur
- d3
) == *cur
)
1284 distances
[1] = d3
- 1;
1290 else if (d3
< mmm
&& *(cur
- d3
) == *cur
)
1293 distances
[1] = d3
- 1;
1299 mixin(UPDATE_maxLen
);
1300 distances
[-2] = cast(uint)maxLen
;
1301 if (maxLen
== lenLimit
)
1303 p
.son
[p
.cyclicBufferPos
] = curMatch
;
1304 mixin(MOVE_POS_RET
);
1309 mixin(GET_MATCHES_FOOTER_HC
!"maxLen");
1313 private uint *Hc5_MatchFinder_GetMatches (CMatchFinder
* p
, uint* distances
) {
1315 uint h2
, h3
, d2
, d3
, maxLen
, pos
;
1317 mixin(GET_MATCHES_HEADER
!"5");
1324 d2
= pos
- hash
[h2
];
1325 d3
= pos
- (hash
+ kFix3HashSize
)[h3
];
1326 // d4 = pos - (hash + kFix4HashSize)[h4];
1328 curMatch
= (hash
+ kFix5HashSize
)[hv
];
1331 (hash
+ kFix3HashSize
)[h3
] = pos
;
1332 // (hash + kFix4HashSize)[h4] = pos;
1333 (hash
+ kFix5HashSize
)[hv
] = pos
;
1341 if (d2
< mmm
&& *(cur
- d2
) == *cur
)
1344 distances
[1] = d2
- 1;
1346 if (*(cur
- d2
+ 2) == cur
[2])
1349 else if (d3
< mmm
&& *(cur
- d3
) == *cur
)
1351 distances
[1] = d3
- 1;
1358 else if (d3
< mmm
&& *(cur
- d3
) == *cur
)
1360 distances
[1] = d3
- 1;
1368 if (*(cur
- d2
+ 3) != cur
[3])
1370 mixin(UPDATE_maxLen
);
1371 distances
[-2] = maxLen
;
1372 if (maxLen
== lenLimit
)
1374 p
.son
[p
.cyclicBufferPos
] = curMatch
;
1375 mixin(MOVE_POS_RET
);
1380 mixin(GET_MATCHES_FOOTER_HC
!"maxLen");
1384 private uint* Hc3Zip_MatchFinder_GetMatches (CMatchFinder
* p
, uint* distances
) {
1385 mixin(GET_MATCHES_HEADER
!"3");
1386 mixin(HASH_ZIP_CALC
);
1387 curMatch
= p
.hash
[hv
];
1389 mixin(GET_MATCHES_FOOTER_HC
!"2");
1393 private void Bt2_MatchFinder_Skip (CMatchFinder
* p
, uint num
) {
1394 do { mixin(SKIP_HEADER
!"2");
1397 curMatch
= p
.hash
[hv
];
1400 mixin(SKIP_FOOTER
); } while (--num
);
1403 private void Bt3Zip_MatchFinder_Skip (CMatchFinder
* p
, uint num
) {
1404 do { mixin(SKIP_HEADER
!"3");
1406 mixin(HASH_ZIP_CALC
);
1407 curMatch
= p
.hash
[hv
];
1410 mixin(SKIP_FOOTER
); } while (--num
);
1413 private void Bt3_MatchFinder_Skip (CMatchFinder
* p
, uint num
) {
1414 do { mixin(SKIP_HEADER
!"3");
1420 curMatch
= (hash
+ kFix3HashSize
)[hv
];
1422 (hash
+ kFix3HashSize
)[hv
] = p
.pos
;
1424 mixin(SKIP_FOOTER
); } while (--num
);
1427 private void Bt4_MatchFinder_Skip (CMatchFinder
* p
, uint num
) {
1428 do { mixin(SKIP_HEADER
!"4");
1434 curMatch
= (hash
+ kFix4HashSize
)[hv
];
1436 (hash
+ kFix3HashSize
)[h3
] =
1437 (hash
+ kFix4HashSize
)[hv
] = p
.pos
;
1439 mixin(SKIP_FOOTER
); } while (--num
);
1442 private void Bt5_MatchFinder_Skip (CMatchFinder
* p
, uint num
) {
1443 do { mixin(SKIP_HEADER
!"5");
1449 curMatch
= (hash
+ kFix5HashSize
)[hv
];
1451 (hash
+ kFix3HashSize
)[h3
] =
1452 // (hash + kFix4HashSize)[h4] =
1453 (hash
+ kFix5HashSize
)[hv
] = p
.pos
;
1455 mixin(SKIP_FOOTER
); } while (--num
);
1459 private void Hc4_MatchFinder_Skip (CMatchFinder
* p
, uint num
) {
1461 do { if (p
.lenLimit
< minLenSKH
) { MatchFinder_MovePos(p
); num
--; continue; } {
1467 /* (p->pos == p->posLimit) is not allowed here !!! */
1468 { const uint rem
= p
.posLimit
- pos
; if (num2
> rem
) num2
= rem
; }
1470 { const uint cycPos
= p
.cyclicBufferPos
;
1471 son
= p
.son
+ cycPos
;
1472 p
.cyclicBufferPos
= cycPos
+ num2
; }
1481 curMatch
= (hash
+ kFix4HashSize
)[hv
];
1483 (hash
+ kFix3HashSize
)[h3
] =
1484 (hash
+ kFix4HashSize
)[hv
] = pos
;
1487 cur
++; pos
++; *son
++ = curMatch
;
1491 if (pos
== p
.posLimit
) MatchFinder_CheckLimits(p
);
1496 private void Hc5_MatchFinder_Skip (CMatchFinder
* p
, uint num
) {
1498 do { if (p
.lenLimit
< minLenSKH
) { MatchFinder_MovePos(p
); num
--; continue; } {
1504 /* (p->pos == p->posLimit) is not allowed here !!! */
1505 { const uint rem
= p
.posLimit
- pos
; if (num2
> rem
) num2
= rem
; }
1507 { const uint cycPos
= p
.cyclicBufferPos
;
1508 son
= p
.son
+ cycPos
;
1509 p
.cyclicBufferPos
= cycPos
+ num2
; }
1518 curMatch
= (hash
+ kFix5HashSize
)[hv
];
1520 (hash
+ kFix3HashSize
)[h3
] =
1521 // (hash + kFix4HashSize)[h4] =
1522 (hash
+ kFix5HashSize
)[hv
] = pos
;
1525 cur
++; pos
++; *son
++ = curMatch
;
1529 if (pos
== p
.posLimit
) MatchFinder_CheckLimits(p
);
1534 private void Hc3Zip_MatchFinder_Skip (CMatchFinder
* p
, uint num
) {
1536 do { if (p
.lenLimit
< minLenSKH
) { MatchFinder_MovePos(p
); num
--; continue; } {
1542 /* (p->pos == p->posLimit) is not allowed here !!! */
1543 { const uint rem
= p
.posLimit
- pos
; if (num2
> rem
) num2
= rem
; }
1545 { const uint cycPos
= p
.cyclicBufferPos
;
1546 son
= p
.son
+ cycPos
;
1547 p
.cyclicBufferPos
= cycPos
+ num2
; }
1554 mixin(HASH_ZIP_CALC
);
1555 curMatch
= hash
[hv
];
1559 cur
++; pos
++; *son
++ = curMatch
;
1563 if (pos
== p
.posLimit
) MatchFinder_CheckLimits(p
);
1568 private void MatchFinder_CreateVTable (CMatchFinder
* p
, IMatchFinder2
* vTable
) @nogc {
1569 vTable
.Init
= cast(Mf_Init_Func
)&MatchFinder_Init
;
1570 vTable
.GetNumAvailableBytes
= cast(Mf_GetNumAvailableBytes_Func
)&MatchFinder_GetNumAvailableBytes
;
1571 vTable
.GetPointerToCurrentPos
= cast(Mf_GetPointerToCurrentPos_Func
)&MatchFinder_GetPointerToCurrentPos
;
1574 if (p
.numHashBytes
<= 4)
1576 vTable
.GetMatches
= cast(Mf_GetMatches_Func
)&Hc4_MatchFinder_GetMatches
;
1577 vTable
.Skip
= cast(Mf_Skip_Func
)&Hc4_MatchFinder_Skip
;
1581 vTable
.GetMatches
= cast(Mf_GetMatches_Func
)&Hc5_MatchFinder_GetMatches
;
1582 vTable
.Skip
= cast(Mf_Skip_Func
)&Hc5_MatchFinder_Skip
;
1585 else if (p
.numHashBytes
== 2)
1587 vTable
.GetMatches
= cast(Mf_GetMatches_Func
)&Bt2_MatchFinder_GetMatches
;
1588 vTable
.Skip
= cast(Mf_Skip_Func
)&Bt2_MatchFinder_Skip
;
1590 else if (p
.numHashBytes
== 3)
1592 vTable
.GetMatches
= cast(Mf_GetMatches_Func
)&Bt3_MatchFinder_GetMatches
;
1593 vTable
.Skip
= cast(Mf_Skip_Func
)&Bt3_MatchFinder_Skip
;
1595 else if (p
.numHashBytes
== 4)
1597 vTable
.GetMatches
= cast(Mf_GetMatches_Func
)&Bt4_MatchFinder_GetMatches
;
1598 vTable
.Skip
= cast(Mf_Skip_Func
)&Bt4_MatchFinder_Skip
;
1602 vTable
.GetMatches
= cast(Mf_GetMatches_Func
)&Bt5_MatchFinder_GetMatches
;
1603 vTable
.Skip
= cast(Mf_Skip_Func
)&Bt5_MatchFinder_Skip
;
1608 private void LzFindPrepare () @nogc {
1612 // ////////////////////////////////////////////////////////////////////////// //
1613 // ////////////////////////////////////////////////////////////////////////// //
1614 // ////////////////////////////////////////////////////////////////////////// //
1615 // ////////////////////////////////////////////////////////////////////////// //
1616 /* for good normalization speed we still reserve 256 MB before 4 GB range */
1617 enum kLzmaMaxHistorySize
= (cast(uint)15 << 28);
1619 enum kNumTopBits
= 24;
1620 enum kTopValue
= (cast(uint)1 << kNumTopBits
);
1622 enum kNumBitModelTotalBits
= 11;
1623 enum kBitModelTotal
= (1 << kNumBitModelTotalBits
);
1624 enum kNumMoveBits
= 5;
1625 enum kProbInitValue
= (kBitModelTotal
>> 1);
1627 enum kNumMoveReducingBits
= 4;
1628 enum kNumBitPriceShiftBits
= 4;
1629 // #define kBitPrice (1 << kNumBitPriceShiftBits)
1631 enum REP_LEN_COUNT
= 64;
1634 //==========================================================================
1636 // LzmaEncProps_Init
1638 //==========================================================================
1639 public void LzmaEncProps_Init (CLzmaEncProps
* p
) @nogc {
1641 p
.dictSize
= p
.mc
= 0;
1642 p
.reduceSize
= cast(ulong)cast(long)-1;
1643 p
.lc
= p
.lp
= p
.pb
= p
.algo
= p
.fb
= p
.btMode
= p
.numHashBytes
= -1;
1648 //==========================================================================
1650 // LzmaEncProps_Normalize
1652 //==========================================================================
1653 public void LzmaEncProps_Normalize (CLzmaEncProps
* p
) @nogc {
1654 int level
= p
.level
;
1655 if (level
< 0) level
= 5;
1658 if (p
.dictSize
== 0)
1660 ( level
<= 3 ?
(cast(uint)1 << (level
* 2 + 16)) :
1661 ( level
<= 6 ?
(cast(uint)1 << (level
+ 19)) :
1662 ( level
<= 7 ?
(cast(uint)1 << 25) : (cast(uint)1 << 26)
1665 if (p
.dictSize
> p
.reduceSize
)
1667 uint v
= cast(uint)p
.reduceSize
;
1668 const uint kReduceMin
= (cast(uint)1 << 12);
1675 if (p
.lc
< 0) p
.lc
= 3;
1676 if (p
.lp
< 0) p
.lp
= 0;
1677 if (p
.pb
< 0) p
.pb
= 2;
1679 if (p
.algo
< 0) p
.algo
= (level
< 5 ?
0 : 1);
1680 if (p
.fb
< 0) p
.fb
= (level
< 7 ?
32 : 64);
1681 if (p
.btMode
< 0) p
.btMode
= (p
.algo
== 0 ?
0 : 1);
1682 if (p
.numHashBytes
< 0) p
.numHashBytes
= (p
.btMode ?
4 : 5);
1683 if (p
.mc
== 0) p
.mc
= (16 + (cast(uint)p
.fb
>> 1)) >> (p
.btMode ?
0 : 1);
1687 //==========================================================================
1689 // LzmaEncProps_GetDictSize
1691 //==========================================================================
1692 public uint LzmaEncProps_GetDictSize (const(CLzmaEncProps
)* props2
) @nogc {
1693 CLzmaEncProps props
= *props2
;
1694 LzmaEncProps_Normalize(&props
);
1695 return props
.dictSize
;
1703 IF (SRC == 0) ZF = 1, DEST is undefined;
1704 AMD : DEST is unchanged;
1705 IF (SRC != 0) ZF = 0; DEST is index of top non-zero bit
1706 BSR is slow in some processors
1709 IF (SRC == 0) CF = 1, DEST is size_in_bits_of_register(src) (32 or 64)
1710 IF (SRC != 0) CF = 0, DEST = num_lead_zero_bits
1711 IF (DEST == 0) ZF = 1;
1713 LZCNT works only in new processors starting from Haswell.
1714 if LZCNT is not supported by processor, then it's executed as BSR.
1715 LZCNT can be faster than BSR, if supported.
1719 //k8: define this for ARM (for some reason)
1720 // #define LZMA_LOG_BSR
1725 C code: : (30 - __builtin_clz(x))
1726 gcc9/gcc10 for x64 /x86 : 30 - (bsr(x) xor 31)
1727 clang10 for x64 : 31 + (bsr(x) xor -32)
1730 #define MY_clz(x) ((uint)__builtin_clz(x))
1732 // __builtin_ia32_lzcnt_u32
1737 #define BSR2_RET(pos, res) { uint zz = 30 - MY_clz(pos); \
1738 res = (zz + zz) + (pos >> zz); }
1743 uint GetPosSlot1(uint pos);
1744 uint GetPosSlot1(uint pos)
1750 #define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
1751 #define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
1754 #else // ! LZMA_LOG_BSR
1757 enum kNumLogBits
= (11 + usize
.sizeof
/ 8 * 3);
1759 enum kDicLogSizeMaxCompress
= ((kNumLogBits
- 1) * 2 + 7);
1761 private void LzmaEnc_FastPosInit (ubyte* g_FastPos
) @nogc {
1767 for (slot
= 2; slot
< kNumLogBits
* 2; slot
++)
1769 usize k
= (cast(usize
)1 << ((slot
>> 1) - 1));
1771 for (j
= 0; j
< k
; j
++)
1772 g_FastPos
[j
] = cast(ubyte)slot
;
1777 /* we can use ((limit - pos) >> 31) only if (pos < ((uint)1 << 31)) */
1779 #define BSR2_RET(pos, res) { uint zz = 6 + ((kNumLogBits - 1) & \
1780 (0 - (((((uint)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
1781 res = p->g_FastPos[pos >> zz] + (zz * 2); }
1785 #define BSR2_RET(pos, res) { uint zz = 6 + ((kNumLogBits - 1) & \
1786 (0 - (((((uint)1 << (kNumLogBits)) - 1) - (pos >> 6)) >> 31))); \
1787 res = p->g_FastPos[pos >> zz] + (zz * 2); }
1790 enum BSR2_RET(string pos
, string res
) = `
1791 { uint zz = (`~pos
~` < (1 << (kNumLogBits + 6))) ? 6 : 6 + kNumLogBits - 1;
1792 `~res
~` = p.g_FastPos[`~pos
~` >> zz] + (zz * 2); }
1796 #define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
1797 p->g_FastPos[pos >> 6] + 12 : \
1798 p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
1801 enum GetPosSlot1(string pos
) = `p.g_FastPos[`~pos
~`]`;
1803 enum GetPosSlot2(string pos
, string res
) = BSR2_RET
!(pos
, res
);
1805 enum GetPosSlot(string pos
, string res
) = `{
1806 if (`~pos
~` < kNumFullDistances) `~res
~` = p.g_FastPos[`~pos
~` & (kNumFullDistances - 1)];
1807 else {`~BSR2_RET
!(pos
, res
)~`}
1810 //#endif // LZMA_LOG_BSR
1813 enum LZMA_NUM_REPS
= 4;
1815 alias CState
= ushort;
1816 alias CExtra
= ushort;
1824 // > 1 : MATCH (extra-1) : LIT : REP0 (len)
1827 uint[LZMA_NUM_REPS
] reps
;
1832 enum kNumOpts
= (1 << 11);
1833 enum kPackReserve
= (kNumOpts
* 8);
1834 // #define kNumOpts (1 << 12)
1835 // #define kPackReserve (1 + kNumOpts * 2)
1837 enum kNumLenToPosStates
= 4;
1838 enum kNumPosSlotBits
= 6;
1839 // #define kDicLogSizeMin 0
1840 enum kDicLogSizeMax
= 32;
1841 enum kDistTableSizeMax
= (kDicLogSizeMax
* 2);
1843 enum kNumAlignBits
= 4;
1844 enum kAlignTableSize
= (1 << kNumAlignBits
);
1845 enum kAlignMask
= (kAlignTableSize
- 1);
1847 enum kStartPosModelIndex
= 4;
1848 enum kEndPosModelIndex
= 14;
1849 enum kNumFullDistances
= (1 << (kEndPosModelIndex
>> 1));
1851 enum LZMA_PB_MAX
= 4;
1852 enum LZMA_LC_MAX
= 8;
1853 enum LZMA_LP_MAX
= 4;
1855 enum LZMA_NUM_PB_STATES_MAX
= (1 << LZMA_PB_MAX
);
1857 enum kLenNumLowBits
= 3;
1858 enum kLenNumLowSymbols
= (1 << kLenNumLowBits
);
1859 enum kLenNumHighBits
= 8;
1860 enum kLenNumHighSymbols
= (1 << kLenNumHighBits
);
1861 enum kLenNumSymbolsTotal
= (kLenNumLowSymbols
* 2 + kLenNumHighSymbols
);
1863 enum LZMA_MATCH_LEN_MIN
= 2;
1864 enum LZMA_MATCH_LEN_MAX
= (LZMA_MATCH_LEN_MIN
+ kLenNumSymbolsTotal
- 1);
1866 enum kNumStates
= 12;
1870 CLzmaProb
[LZMA_NUM_PB_STATES_MAX
<< (kLenNumLowBits
+ 1)] low
;
1871 CLzmaProb
[kLenNumHighSymbols
] high
;
1875 struct CLenPriceEnc
{
1877 uint[kLenNumSymbolsTotal
][LZMA_NUM_PB_STATES_MAX
] prices
;
1878 // uint prices1[LZMA_NUM_PB_STATES_MAX][kLenNumLowSymbols * 2];
1879 // uint prices2[kLenNumSymbolsTotal];
1882 enum GET_PRICE_LEN(string p
, string posState
, string len
) =
1883 `((`~p
~`).prices[`~posState
~`][cast(usize)(`~len
~`) - LZMA_MATCH_LEN_MIN])`;
1886 #define GET_PRICE_LEN(p, posState, len) \
1887 ((p)->prices2[(usize)(len) - 2] + ((p)->prices1[posState][((len) - 2) & (kLenNumLowSymbols * 2 - 1)] & (((len) - 2 - kLenNumLowSymbols * 2) >> 9)))
1898 ISeqOutStream
*outStream
;
1905 CLzmaProb
*litProbs
;
1908 uint[LZMA_NUM_REPS
] reps
;
1910 CLzmaProb
[1 << kNumAlignBits
] posAlignEncoder
;
1911 CLzmaProb
[kNumStates
] isRep
;
1912 CLzmaProb
[kNumStates
] isRepG0
;
1913 CLzmaProb
[kNumStates
] isRepG1
;
1914 CLzmaProb
[kNumStates
] isRepG2
;
1915 CLzmaProb
[LZMA_NUM_PB_STATES_MAX
][kNumStates
] isMatch
;
1916 CLzmaProb
[LZMA_NUM_PB_STATES_MAX
][kNumStates
] isRep0Long
;
1918 CLzmaProb
[1 << kNumPosSlotBits
][kNumLenToPosStates
] posSlotEncoder
;
1919 CLzmaProb
[kNumFullDistances
] posEncoders
;
1922 CLenEnc repLenProbs
;
1926 alias CProbPrice
= uint;
1927 alias BoolInt
= int;
1931 void *matchFinderObj
;
1932 IMatchFinder2 matchFinder
;
1937 uint longestMatchLen
;
1943 uint additionalOffset
;
1944 uint[LZMA_NUM_REPS
] reps
;
1945 uint lpMask
, pbMask
;
1946 CLzmaProb
*litProbs
;
1955 BoolInt writeEndMark
;
1957 BoolInt multiThread
;
1959 // BoolInt _maxMode;
1963 uint matchPriceCount
;
1964 // uint alignPriceCount;
1965 int repLenEncCounter
;
1972 CMatchFinder matchFinderBase
;
1975 // we suppose that we have 8-bytes alignment after CMatchFinder
1978 CProbPrice
[kBitModelTotal
>> kNumMoveReducingBits
] ProbPrices
;
1980 // we want {len , dist} pairs to be 8-bytes aligned in matches array
1981 uint[LZMA_MATCH_LEN_MAX
* 2 + 2] matches
;
1983 // we want 8-bytes alignment here
1984 uint[kAlignTableSize
] alignPrices
;
1985 uint[kDistTableSizeMax
][kNumLenToPosStates
] posSlotPrices
;
1986 uint[kNumFullDistances
][kNumLenToPosStates
] distancesPrices
;
1988 CLzmaProb
[1 << kNumAlignBits
] posAlignEncoder
;
1989 CLzmaProb
[kNumStates
] isRep
;
1990 CLzmaProb
[kNumStates
] isRepG0
;
1991 CLzmaProb
[kNumStates
] isRepG1
;
1992 CLzmaProb
[kNumStates
] isRepG2
;
1993 CLzmaProb
[LZMA_NUM_PB_STATES_MAX
][kNumStates
] isMatch
;
1994 CLzmaProb
[LZMA_NUM_PB_STATES_MAX
][kNumStates
] isRep0Long
;
1995 CLzmaProb
[1 << kNumPosSlotBits
][kNumLenToPosStates
] posSlotEncoder
;
1996 CLzmaProb
[kNumFullDistances
] posEncoders
;
1999 CLenEnc repLenProbs
;
2001 //#ifndef LZMA_LOG_BSR
2002 ubyte[1 << kNumLogBits
] g_FastPos
;
2005 CLenPriceEnc lenEnc
;
2006 CLenPriceEnc repLenEnc
;
2008 COptimal
[kNumOpts
] opt
;
2010 CSaveState saveState
;
2012 // BoolInt mf_Failure;
2016 //#define MFB (p.matchFinderBase)
2019 //==========================================================================
2023 //==========================================================================
2024 public SRes
LzmaEnc_SetProps (CLzmaEncHandle pp
, const(CLzmaEncProps
)* props2
) @nogc {
2025 CLzmaEnc
*p
= cast(CLzmaEnc
*)pp
;
2026 CLzmaEncProps props
= *props2
;
2027 LzmaEncProps_Normalize(&props
);
2029 if (props
.lc
> LZMA_LC_MAX
2030 || props
.lp
> LZMA_LP_MAX
2031 || props
.pb
> LZMA_PB_MAX
)
2032 return SZ_ERROR_PARAM
;
2035 if (props
.dictSize
> kLzmaMaxHistorySize
)
2036 props
.dictSize
= kLzmaMaxHistorySize
;
2038 //#ifndef LZMA_LOG_BSR
2040 const ulong dict64
= props
.dictSize
;
2041 if (dict64
> (cast(ulong)1 << kDicLogSizeMaxCompress
))
2042 return SZ_ERROR_PARAM
;
2046 p
.dictSize
= props
.dictSize
;
2048 uint fb
= cast(uint)props
.fb
;
2051 if (fb
> LZMA_MATCH_LEN_MAX
)
2052 fb
= LZMA_MATCH_LEN_MAX
;
2053 p
.numFastBytes
= fb
;
2055 p
.lc
= cast(uint)props
.lc
;
2056 p
.lp
= cast(uint)props
.lp
;
2057 p
.pb
= cast(uint)props
.pb
;
2058 p
.fastMode
= (props
.algo
== 0);
2059 // p->_maxMode = True;
2060 (p
.matchFinderBase
).btMode
= cast(ubyte)(props
.btMode ?
1 : 0);
2062 uint numHashBytes
= 4;
2065 if (props
.numHashBytes
< 2) numHashBytes
= 2;
2066 else if (props
.numHashBytes
< 4) numHashBytes
= cast(uint)props
.numHashBytes
;
2068 if (props
.numHashBytes
>= 5) numHashBytes
= 5;
2070 (p
.matchFinderBase
).numHashBytes
= numHashBytes
;
2073 (p
.matchFinderBase
).cutValue
= props
.mc
;
2075 p
.writeEndMark
= cast(BoolInt
)props
.writeEndMark
;
2081 //==========================================================================
2083 // LzmaEnc_SetDataSize
2085 //==========================================================================
2086 public void LzmaEnc_SetDataSize (CLzmaEncHandle pp
, ulong expectedDataSiize
) @nogc {
2087 CLzmaEnc
*p
= cast(CLzmaEnc
*)pp
;
2088 (p
.matchFinderBase
).expectedDataSize
= expectedDataSiize
;
2092 enum kState_Start
= 0;
2093 enum kState_LitAfterMatch
= 4;
2094 enum kState_LitAfterRep
= 5;
2095 enum kState_MatchAfterLit
= 7;
2096 enum kState_RepAfterLit
= 8;
2098 immutable ubyte[kNumStates
] kLiteralNextStates
= [0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5];
2099 immutable ubyte[kNumStates
] kMatchNextStates
= [7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10];
2100 immutable ubyte[kNumStates
] kRepNextStates
= [8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11];
2101 immutable ubyte[kNumStates
] kShortRepNextStates
= [9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11];
2103 enum IsLitState(string s
) = `((`~s
~`) < 7)`;
2104 enum GetLenToPosState2(string len
) = `(((`~len
~`) < kNumLenToPosStates - 1) ? (`~len
~`) : kNumLenToPosStates - 1)`;
2105 enum GetLenToPosState(string len
) = `(((`~len
~`) < kNumLenToPosStates + 1) ? (`~len
~`) - 2 : kNumLenToPosStates - 1)`;
2107 enum kInfinityPrice
= (1 << 30);
2109 private void RangeEnc_Construct (CRangeEnc
* p
) @nogc {
2114 enum RangeEnc_GetProcessed(string p
) = `((`~p
~`).processed + cast(usize)((`~p
~`).buf - (`~p
~`).bufBase) + (`~p
~`).cacheSize)`;
2115 enum RangeEnc_GetProcessed_sizet(string p
) = `(cast(usize)(`~p
~`).processed + cast(usize)((`~p
~`).buf - (`~p
~`).bufBase) + cast(usize)(`~p
~`).cacheSize)`;
2117 enum RC_BUF_SIZE
= (1 << 16);
2119 private int RangeEnc_Alloc (CRangeEnc
*p
, ISzAllocPtr alloc
) {
2122 p
.bufBase
= cast(ubyte *)ISzAlloc_Alloc(alloc
, RC_BUF_SIZE
);
2125 p
.bufLim
= p
.bufBase
+ RC_BUF_SIZE
;
2130 private void RangeEnc_Free (CRangeEnc
*p
, ISzAllocPtr alloc
) {
2131 ISzAlloc_Free(alloc
, p
.bufBase
);
2136 private void RangeEnc_Init (CRangeEnc
* p
) @nogc {
2137 /* Stream.Init(); */
2138 p
.range
= 0xFFFFFFFF;
2150 private void RangeEnc_FlushStream (CRangeEnc
* p
) {
2154 num
= cast(usize
)(p
.buf
- p
.bufBase
);
2157 if (num != ISeqOutStream_Write(p.outStream, p.bufBase, num))
2158 p.res = SZ_ERROR_WRITE;
2160 if (p
.outStream
.Write(p
.outStream
, p
.bufBase
, num
) != num
) p
.res
= SZ_ERROR_WRITE
;
2167 private void RangeEnc_ShiftLow(CRangeEnc
*p
)
2169 uint low
= cast(uint)p
.low
;
2170 uint high
= cast(uint)(p
.low
>> 32);
2171 p
.low
= cast(uint)(low
<< 8);
2172 if (low
< cast(uint)0xFF000000 || high
!= 0)
2176 *buf
++ = cast(ubyte)(p
.cache
+ high
);
2177 p
.cache
= cast(uint)(low
>> 24);
2179 if (buf
== p
.bufLim
)
2180 RangeEnc_FlushStream(p
);
2181 if (p
.cacheSize
== 0)
2188 *buf
++ = cast(ubyte)(high
);
2190 if (buf
== p
.bufLim
)
2191 RangeEnc_FlushStream(p
);
2192 if (--p
.cacheSize
== 0)
2199 private void RangeEnc_FlushData(CRangeEnc
*p
)
2202 for (i
= 0; i
< 5; i
++)
2203 RangeEnc_ShiftLow(p
);
2206 enum RC_NORM(string p
) = `if (range < kTopValue) { range <<= 8; RangeEnc_ShiftLow(`~p
~`); }`;
2208 enum RC_BIT_PRE(string p
, string prob
) = `
2210 newBound = (range >> kNumBitModelTotalBits) * ttt;
2213 // #define LZMA_ENC_USE_BRANCH
2215 version(LZMA_ENC_USE_BRANCH
) {
2217 enum RC_BIT(string p
, string prob
, string bit
) = `{
2218 `~RC_BIT_PRE
!(p
, prob
)~`
2219 if (`~bit
~` == 0) { range = newBound; ttt += (kBitModelTotal - ttt) >> kNumMoveBits; }
2220 else { (`~p
~`).low += newBound; range -= newBound; ttt -= ttt >> kNumMoveBits; }
2221 *(`~prob
~`) = cast(CLzmaProb)ttt;
2228 enum RC_BIT(string p
, string prob
, string bit
) = `{
2230 `~RC_BIT_PRE
!(p
, prob
)~`
2231 mask = 0 - cast(uint)`~bit
~`;
2235 (`~p
~`).low += mask;
2236 mask = cast(uint)`~bit
~` - 1;
2237 range += newBound & mask;
2238 mask &= (kBitModelTotal - ((1 << kNumMoveBits) - 1));
2239 mask += ((1 << kNumMoveBits) - 1);
2240 ttt += cast(uint)(cast(int)(mask - ttt) >> kNumMoveBits);
2241 *(`~prob
~`) = cast(CLzmaProb)ttt;
2249 enum RC_BIT_0_BASE(string p
, string prob
) =
2250 `range = newBound; *(`~prob
~`) = cast(CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));`;
2252 enum RC_BIT_1_BASE(string p
, string prob
) =
2253 `range -= newBound; (`~p
~`).low += newBound; *(`~prob
~`) = cast(CLzmaProb)(ttt - (ttt >> kNumMoveBits));`;
2255 enum RC_BIT_0(string p
, string prob
) =
2256 RC_BIT_0_BASE
!(p
, prob
)~
2259 enum RC_BIT_1(string p
, string prob
) =
2260 RC_BIT_1_BASE
!(p
, prob
)~
2263 private void RangeEnc_EncodeBit_0(CRangeEnc
*p
, CLzmaProb
*prob
)
2265 uint range
, ttt
, newBound
;
2267 mixin(RC_BIT_PRE
!("p", "prob"));
2268 mixin(RC_BIT_0
!("p", "prob"));
2272 private void LitEnc_Encode(CRangeEnc
*p
, CLzmaProb
*probs
, uint sym
)
2274 uint range
= p
.range
;
2279 // RangeEnc_EncodeBit(p, probs + (sym >> 8), (sym >> 7) & 1);
2280 CLzmaProb
*prob
= probs
+ (sym
>> 8);
2281 uint bit
= (sym
>> 7) & 1;
2283 mixin(RC_BIT
!("p", "prob", "bit"));
2285 while (sym
< 0x10000);
2289 private void LitEnc_EncodeMatched(CRangeEnc
*p
, CLzmaProb
*probs
, uint sym
, uint matchByte
)
2291 uint range
= p
.range
;
2300 // RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (sym >> 8)), (sym >> 7) & 1);
2301 prob
= probs
+ (offs
+ (matchByte
& offs
) + (sym
>> 8));
2302 bit
= (sym
>> 7) & 1;
2304 offs
&= ~(matchByte ^ sym
);
2305 mixin(RC_BIT
!("p", "prob", "bit"));
2307 while (sym
< 0x10000);
2313 private void LzmaEnc_InitPriceTables(CProbPrice
*ProbPrices
)
2316 for (i
= 0; i
< (kBitModelTotal
>> kNumMoveReducingBits
); i
++)
2318 const uint kCyclesBits
= kNumBitPriceShiftBits
;
2319 uint w
= (i
<< kNumMoveReducingBits
) + (1 << (kNumMoveReducingBits
- 1));
2322 for (j
= 0; j
< kCyclesBits
; j
++)
2326 while (w
>= (cast(uint)1 << 16))
2332 ProbPrices
[i
] = cast(CProbPrice
)((cast(uint)kNumBitModelTotalBits
<< kCyclesBits
) - 15 - bitCount
);
2333 // printf("\n%3d: %5d", i, ProbPrices[i]);
2338 enum GET_PRICE(string prob
, string bit
) =
2339 `p.ProbPrices[((`~prob
~`) ^ cast(uint)(((-cast(int)(`~bit
~`))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]`;
2341 enum GET_PRICEa(string prob
, string bit
) =
2342 `ProbPrices[((`~prob
~`) ^ cast(uint)((-(cast(int)(`~bit
~`))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]`;
2344 enum GET_PRICE_0(string prob
) = `p.ProbPrices[(`~prob
~`) >> kNumMoveReducingBits]`;
2345 enum GET_PRICE_1(string prob
) = `p.ProbPrices[((`~prob
~`) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]`;
2347 enum GET_PRICEa_0(string prob
) = `ProbPrices[(`~prob
~`) >> kNumMoveReducingBits]`;
2348 enum GET_PRICEa_1(string prob
) = `ProbPrices[((`~prob
~`) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]`;
2351 private uint LitEnc_GetPrice(const CLzmaProb
*probs
, uint sym
, const CProbPrice
*ProbPrices
)
2359 price
+= mixin(GET_PRICEa
!("probs[sym]", "bit"));
2366 private uint LitEnc_Matched_GetPrice(const CLzmaProb
*probs
, uint sym
, uint matchByte
, const CProbPrice
*ProbPrices
)
2374 price
+= mixin(GET_PRICEa
!("probs[offs + (matchByte & offs) + (sym >> 8)]", "(sym >> 7) & 1"));
2376 offs
&= ~(matchByte ^ sym
);
2378 while (sym
< 0x10000);
2383 private void RcTree_ReverseEncode(CRangeEnc
*rc
, CLzmaProb
*probs
, uint numBits
, uint sym
)
2385 uint range
= rc
.range
;
2391 // RangeEnc_EncodeBit(rc, probs + m, bit);
2393 mixin(RC_BIT
!("rc", "probs + m", "bit"));
2402 private void LenEnc_Init (CLenEnc
* p
) @nogc {
2404 for (i
= 0; i
< (LZMA_NUM_PB_STATES_MAX
<< (kLenNumLowBits
+ 1)); i
++)
2405 p
.low
[i
] = kProbInitValue
;
2406 for (i
= 0; i
< kLenNumHighSymbols
; i
++)
2407 p
.high
[i
] = kProbInitValue
;
2410 private void LenEnc_Encode(CLenEnc
*p
, CRangeEnc
*rc
, uint sym
, uint posState
)
2412 uint range
, ttt
, newBound
;
2413 CLzmaProb
*probs
= p
.low
.ptr
;
2415 mixin(RC_BIT_PRE
!("rc", "probs"));
2416 if (sym
>= kLenNumLowSymbols
)
2418 mixin(RC_BIT_1
!("rc", "probs"));
2419 probs
+= kLenNumLowSymbols
;
2420 mixin(RC_BIT_PRE
!("rc", "probs"));
2421 if (sym
>= kLenNumLowSymbols
* 2)
2423 mixin(RC_BIT_1
!("rc", "probs"));
2425 // RcTree_Encode(rc, p->high, kLenNumHighBits, sym - kLenNumLowSymbols * 2);
2426 LitEnc_Encode(rc
, p
.high
.ptr
, sym
- kLenNumLowSymbols
* 2);
2429 sym
-= kLenNumLowSymbols
;
2432 // RcTree_Encode(rc, probs + (posState << kLenNumLowBits), kLenNumLowBits, sym);
2436 mixin(RC_BIT_0
!("rc", "probs"));
2437 probs
+= (posState
<< (1 + kLenNumLowBits
));
2438 bit
= (sym
>> 2) ; mixin(RC_BIT
!("rc", "probs + 1", "bit")); m
= (1 << 1) + bit
;
2439 bit
= (sym
>> 1) & 1; mixin(RC_BIT
!("rc", "probs + m", "bit")); m
= (m
<< 1) + bit
;
2440 bit
= sym
& 1; mixin(RC_BIT
!("rc", "probs + m", "bit"));
2445 private void SetPrices_3 (const(CLzmaProb
)* probs
, uint startPrice
, uint* prices
, const(CProbPrice
)* ProbPrices
) @nogc {
2447 for (i
= 0; i
< 8; i
+= 2)
2449 uint price
= startPrice
;
2451 price
+= mixin(GET_PRICEa
!("probs[1 ]", "(i >> 2)"));
2452 price
+= mixin(GET_PRICEa
!("probs[2 + (i >> 2)]", "(i >> 1) & 1"));
2453 prob
= probs
[4 + (i
>> 1)];
2454 prices
[i
] = price
+ mixin(GET_PRICEa_0
!"prob");
2455 prices
[i
+ 1] = price
+ mixin(GET_PRICEa_1
!"prob");
2461 private void LenPriceEnc_UpdateTables(
2464 const(CLenEnc
)* enc
,
2465 const(CProbPrice
)* ProbPrices
)
2470 uint prob
= enc
.low
[0];
2473 b
= mixin(GET_PRICEa_1
!"prob");
2474 a
= mixin(GET_PRICEa_0
!"prob");
2475 c
= b
+ mixin(GET_PRICEa_0
!"enc.low[kLenNumLowSymbols]");
2476 for (posState
= 0; posState
< numPosStates
; posState
++)
2478 uint *prices
= p
.prices
[posState
].ptr
;
2479 const(CLzmaProb
)* probs
= enc
.low
.ptr
+ (posState
<< (1 + kLenNumLowBits
));
2480 SetPrices_3(probs
, a
, prices
, ProbPrices
);
2481 SetPrices_3(probs
+ kLenNumLowSymbols
, c
, prices
+ kLenNumLowSymbols
, ProbPrices
);
2489 a = GET_PRICEa_0(enc->low[0]);
2490 for (i = 0; i < kLenNumLowSymbols; i++)
2492 a = GET_PRICEa_1(enc->low[0]);
2493 b = a + GET_PRICEa_0(enc->low[kLenNumLowSymbols]);
2494 for (i = kLenNumLowSymbols; i < kLenNumLowSymbols * 2; i++)
2496 a += GET_PRICEa_1(enc->low[kLenNumLowSymbols]);
2500 // p->counter = numSymbols;
2504 uint i
= p
.tableSize
;
2506 if (i
> kLenNumLowSymbols
* 2)
2508 const(CLzmaProb
)* probs
= enc
.high
.ptr
;
2509 uint *prices
= p
.prices
[0].ptr
+ kLenNumLowSymbols
* 2;
2510 i
-= kLenNumLowSymbols
* 2 - 1;
2512 b
+= mixin(GET_PRICEa_1
!"enc.low[kLenNumLowSymbols]");
2517 // RcTree_GetPrice(enc->high, kLenNumHighBits, i - kLenNumLowSymbols * 2, ProbPrices);
2518 LitEnc_GetPrice(probs, i - kLenNumLowSymbols * 2, ProbPrices);
2520 // uint price = a + RcTree_GetPrice(probs, kLenNumHighBits - 1, sym, ProbPrices);
2521 uint sym
= --i
+ (1 << (kLenNumHighBits
- 1));
2527 price
+= mixin(GET_PRICEa
!("probs[sym]", "bit"));
2532 uint prob
= probs
[cast(usize
)i
+ (1 << (kLenNumHighBits
- 1))];
2533 prices
[cast(usize
)i
* 2 ] = price
+ mixin(GET_PRICEa_0
!"prob");
2534 prices
[cast(usize
)i
* 2 + 1] = price
+ mixin(GET_PRICEa_1
!"prob");
2540 import core
.stdc
.string
: memcpy
;
2542 usize num
= (p
.tableSize
- kLenNumLowSymbols
* 2) * (p
.prices
[0][0]).sizeof
;
2543 for (posState
= 1; posState
< numPosStates
; posState
++)
2544 memcpy(p
.prices
[posState
].ptr
+ kLenNumLowSymbols
* 2, p
.prices
[0].ptr
+ kLenNumLowSymbols
* 2, num
);
2552 g_STAT_OFFSET += num;
2553 printf("\n MovePos %u", num);
2557 enum MOVE_POS1(string p
, string num
) = `{
2558 `~p
~`.additionalOffset += (`~num
~`);
2559 `~p
~`.matchFinder.Skip(`~p
~`.matchFinderObj, cast(uint)(`~num
~`)); }
2563 private uint ReadMatchDistances(CLzmaEnc
*p
, uint *numPairsRes
)
2567 p
.additionalOffset
++;
2568 p
.numAvail
= p
.matchFinder
.GetNumAvailableBytes(p
.matchFinderObj
);
2570 const uint *d
= p
.matchFinder
.GetMatches(p
.matchFinderObj
, p
.matches
.ptr
);
2571 // if (!d) { p->mf_Failure = True; *numPairsRes = 0; return 0; }
2572 numPairs
= cast(uint)(d
- p
.matches
.ptr
);
2574 *numPairsRes
= numPairs
;
2578 printf("\n i = %u numPairs = %u ", g_STAT_OFFSET, numPairs / 2);
2582 for (i = 0; i < numPairs; i += 2)
2583 printf("%2u %6u | ", p.matches[i], p.matches[i + 1]);
2591 const uint len
= p
.matches
[cast(usize
)numPairs
- 2];
2592 if (len
!= p
.numFastBytes
)
2595 uint numAvail
= p
.numAvail
;
2596 if (numAvail
> LZMA_MATCH_LEN_MAX
)
2597 numAvail
= LZMA_MATCH_LEN_MAX
;
2599 const(ubyte)* p1
= p
.matchFinder
.GetPointerToCurrentPos(p
.matchFinderObj
) - 1;
2600 const(ubyte)* p2
= p1
+ len
;
2601 const ptrdiff_t dif
= cast(ptrdiff_t
)-1 - cast(ptrdiff_t
)p
.matches
[cast(usize
)numPairs
- 1];
2602 const(ubyte)* lim
= p1
+ numAvail
;
2603 for (; p2
!= lim
&& *p2
== p2
[dif
]; p2
++)
2605 return cast(uint)(p2
- p1
);
2611 enum MARK_LIT
= (cast(uint)cast(int)-1);
2613 enum MakeAs_Lit(string p
) = `{ (`~p
~`).dist = MARK_LIT; (`~p
~`).extra = 0; }`;
2614 enum MakeAs_ShortRep(string p
) = `{ (`~p
~`).dist = 0; (`~p
~`).extra = 0; }`;
2615 enum IsShortRep(string p
) = `((`~p
~`).dist == 0)`;
2618 enum GetPrice_ShortRep(string p
, string state
, string posState
) =
2619 `( `~GET_PRICE_0
!(p
~`.isRepG0[`~state
~`]`)~` + `~GET_PRICE_0
!(p
~`.isRep0Long[`~state
~`][`~posState
~`]`)~`)`;
2621 enum GetPrice_Rep_0(string p
, string state
, string posState
) = `(
2622 `~GET_PRICE_1
!(p
~`.isMatch[`~state
~`][`~posState
~`]`)~`
2623 + `~GET_PRICE_1
!(p
~`.isRep0Long[`~state
~`][`~posState
~`]`)~`)
2624 + `~GET_PRICE_1
!(p
~`.isRep[`~state
~`]`)~`
2625 + `~GET_PRICE_0
!(p
~`.isRepG0[`~state
~`]`);
2628 private uint GetPrice_PureRep(const(CLzmaEnc
)* p
, uint repIndex
, usize state
, usize posState
)
2631 uint prob
= p
.isRepG0
[state
];
2634 price
= mixin(GET_PRICE_0
!"prob");
2635 price
+= mixin(GET_PRICE_1
!"p.isRep0Long[state][posState]");
2639 price
= mixin(GET_PRICE_1
!"prob");
2640 prob
= p
.isRepG1
[state
];
2642 price
+= mixin(GET_PRICE_0
!"prob");
2645 price
+= mixin(GET_PRICE_1
!"prob");
2646 price
+= mixin(GET_PRICE
!("p.isRepG2[state]", "repIndex - 2"));
2653 private uint Backward(CLzmaEnc
*p
, uint cur
)
2660 uint dist
= p
.opt
[cur
].dist
;
2661 uint len
= cast(uint)p
.opt
[cur
].len
;
2662 uint extra
= cast(uint)p
.opt
[cur
].extra
;
2668 p
.opt
[wr
].len
= cast(uint)len
;
2673 p
.opt
[wr
].dist
= dist
;
2681 p
.opt
[wr
].dist
= MARK_LIT
;
2694 p
.opt
[wr
].dist
= dist
;
2695 p
.opt
[wr
].len
= cast(uint)len
;
2701 enum LIT_PROBS(string pos
, string prevByte
) =
2702 `(p.litProbs + cast(uint)3 * (((((`~pos
~`) << 8) + (`~prevByte
~`)) & p.lpMask) << p.lc))`;
2705 private uint GetOptimum(CLzmaEnc
*p
, uint position
)
2708 uint[LZMA_NUM_REPS
] reps
;
2709 uint[LZMA_NUM_REPS
] repLens
;
2714 uint numPairs
, mainLen
, repMaxIndex
, i
, posState
;
2715 uint matchPrice
, repMatchPrice
;
2717 ubyte curByte
, matchByte
;
2719 p
.optCur
= p
.optEnd
= 0;
2721 if (p
.additionalOffset
== 0)
2722 mainLen
= ReadMatchDistances(p
, &numPairs
);
2725 mainLen
= p
.longestMatchLen
;
2726 numPairs
= p
.numPairs
;
2729 numAvail
= p
.numAvail
;
2732 p
.backRes
= MARK_LIT
;
2735 if (numAvail
> LZMA_MATCH_LEN_MAX
)
2736 numAvail
= LZMA_MATCH_LEN_MAX
;
2738 data
= p
.matchFinder
.GetPointerToCurrentPos(p
.matchFinderObj
) - 1;
2741 for (i
= 0; i
< LZMA_NUM_REPS
; i
++)
2744 const(ubyte)* data2
;
2745 reps
[i
] = p
.reps
[i
];
2746 data2
= data
- reps
[i
];
2747 if (data
[0] != data2
[0] || data
[1] != data2
[1])
2752 for (len
= 2; len
< numAvail
&& data
[len
] == data2
[len
]; len
++)
2755 if (len
> repLens
[repMaxIndex
])
2757 if (len
== LZMA_MATCH_LEN_MAX
) // 21.03 : optimization
2761 if (repLens
[repMaxIndex
] >= p
.numFastBytes
)
2764 p
.backRes
= cast(uint)repMaxIndex
;
2765 len
= repLens
[repMaxIndex
];
2766 mixin(MOVE_POS1
!("p", "len - 1"));
2770 matches
= p
.matches
.ptr
;
2771 //!#define MATCHES matches
2772 // #define MATCHES p->matches
2774 if (mainLen
>= p
.numFastBytes
)
2776 p
.backRes
= p
.matches
[cast(usize
)numPairs
- 1] + LZMA_NUM_REPS
;
2777 mixin(MOVE_POS1
!("p", "mainLen - 1"));
2782 matchByte
= *(data
- reps
[0]);
2784 last
= repLens
[repMaxIndex
];
2785 if (last
<= mainLen
)
2788 if (last
< 2 && curByte
!= matchByte
)
2790 p
.backRes
= MARK_LIT
;
2794 p
.opt
[0].state
= cast(CState
)p
.state
;
2796 posState
= (position
& p
.pbMask
);
2799 const(CLzmaProb
)* probs
= mixin(LIT_PROBS
!("position", "*(data - 1)"));
2800 p
.opt
[1].price
= mixin(GET_PRICE_0
!"p.isMatch[p.state][posState]") +
2801 (!mixin(IsLitState
!"p.state") ?
2802 LitEnc_Matched_GetPrice(probs
, curByte
, matchByte
, p
.ProbPrices
.ptr
) :
2803 LitEnc_GetPrice(probs
, curByte
, p
.ProbPrices
.ptr
));
2806 mixin(MakeAs_Lit
!"&p.opt[1]");
2808 matchPrice
= mixin(GET_PRICE_1
!"p.isMatch[p.state][posState]");
2809 repMatchPrice
= matchPrice
+ mixin(GET_PRICE_1
!"p.isRep[p.state]");
2812 if (matchByte
== curByte
&& repLens
[0] == 0)
2814 uint shortRepPrice
= repMatchPrice
+ mixin(GetPrice_ShortRep
!("p", "p.state", "posState"));
2815 if (shortRepPrice
< p
.opt
[1].price
)
2817 p
.opt
[1].price
= shortRepPrice
;
2818 mixin(MakeAs_ShortRep
!"&p.opt[1]");
2822 p
.backRes
= p
.opt
[1].dist
;
2829 p
.opt
[0].reps
[0] = reps
[0];
2830 p
.opt
[0].reps
[1] = reps
[1];
2831 p
.opt
[0].reps
[2] = reps
[2];
2832 p
.opt
[0].reps
[3] = reps
[3];
2834 // ---------- REP ----------
2836 for (i
= 0; i
< LZMA_NUM_REPS
; i
++)
2838 uint repLen
= repLens
[i
];
2842 price
= repMatchPrice
+ GetPrice_PureRep(p
, i
, p
.state
, posState
);
2845 uint price2
= price
+ mixin(GET_PRICE_LEN
!("&p.repLenEnc", "posState", "repLen"));
2846 COptimal
*opt
= &p
.opt
[repLen
];
2847 if (price2
< opt
.price
)
2850 opt
.len
= cast(uint)repLen
;
2851 opt
.dist
= cast(uint)i
;
2855 while (--repLen
>= 2);
2859 // ---------- MATCH ----------
2861 uint len
= repLens
[0] + 1;
2865 uint normalMatchPrice
= matchPrice
+ mixin(GET_PRICE_0
!"p.isRep[p.state]");
2870 while (len
> p
.matches
[offs
])
2876 uint dist
= p
.matches
[cast(usize
)offs
+ 1];
2877 uint price
= normalMatchPrice
+ mixin(GET_PRICE_LEN
!("&p.lenEnc", "posState", "len"));
2878 uint lenToPosState
= mixin(GetLenToPosState
!"len");
2880 if (dist
< kNumFullDistances
)
2881 price
+= p
.distancesPrices
[lenToPosState
][dist
& (kNumFullDistances
- 1)];
2885 mixin(GetPosSlot2
!("dist", "slot"));
2886 price
+= p
.alignPrices
[dist
& kAlignMask
];
2887 price
+= p
.posSlotPrices
[lenToPosState
][slot
];
2892 if (price
< opt
.price
)
2895 opt
.len
= cast(uint)len
;
2896 opt
.dist
= dist
+ LZMA_NUM_REPS
;
2900 if (len
== p
.matches
[offs
])
2903 if (offs
== numPairs
)
2915 /* if (position >= 0) */
2918 printf("\n pos = %4X", position);
2919 for (i = cur; i <= last; i++)
2920 printf("\nprice[%4X] = %u", position - cur + i, p.opt[i].price);
2928 // ---------- Optimal Parsing ----------
2934 uint newLen
, numPairs
, prev
, state
, posState
, startLen
;
2935 uint litPrice
, matchPrice
, repMatchPrice
;
2937 ubyte curByte
, matchByte
;
2946 if (cur
>= kNumOpts
- 64)
2949 uint price
= p
.opt
[cur
].price
;
2951 for (j
= cur
+ 1; j
<= last
; j
++)
2953 uint price2
= p
.opt
[j
].price
;
2954 if (price
>= price2
)
2961 uint delta
= best
- cur
;
2964 mixin(MOVE_POS1
!("p", "delta"));
2971 newLen
= ReadMatchDistances(p
, &numPairs
);
2973 if (newLen
>= p
.numFastBytes
)
2975 p
.numPairs
= numPairs
;
2976 p
.longestMatchLen
= newLen
;
2980 curOpt
= &p
.opt
[cur
];
2984 // we need that check here, if skip_items in p->opt are possible
2986 if (curOpt->price >= kInfinityPrice)
2990 prev
= cur
- curOpt
.len
;
2992 if (curOpt
.len
== 1)
2994 state
= cast(uint)p
.opt
[prev
].state
;
2995 if (mixin(IsShortRep
!"curOpt"))
2996 state
= kShortRepNextStates
[state
];
2998 state
= kLiteralNextStates
[state
];
3002 const(COptimal
)* prevOpt
;
3004 uint dist
= curOpt
.dist
;
3008 prev
-= cast(uint)curOpt
.extra
;
3009 state
= kState_RepAfterLit
;
3010 if (curOpt
.extra
== 1)
3011 state
= (dist
< LZMA_NUM_REPS ? kState_RepAfterLit
: kState_MatchAfterLit
);
3015 state
= cast(uint)p
.opt
[prev
].state
;
3016 if (dist
< LZMA_NUM_REPS
)
3017 state
= kRepNextStates
[state
];
3019 state
= kMatchNextStates
[state
];
3022 prevOpt
= &p
.opt
[prev
];
3023 b0
= prevOpt
.reps
[0];
3025 if (dist
< LZMA_NUM_REPS
)
3030 reps
[1] = prevOpt
.reps
[1];
3031 reps
[2] = prevOpt
.reps
[2];
3032 reps
[3] = prevOpt
.reps
[3];
3037 b0
= prevOpt
.reps
[1];
3041 reps
[2] = prevOpt
.reps
[2];
3042 reps
[3] = prevOpt
.reps
[3];
3047 reps
[0] = prevOpt
.reps
[dist
];
3048 reps
[3] = prevOpt
.reps
[dist ^
1];
3054 reps
[0] = (dist
- LZMA_NUM_REPS
+ 1);
3056 reps
[2] = prevOpt
.reps
[1];
3057 reps
[3] = prevOpt
.reps
[2];
3061 curOpt
.state
= cast(CState
)state
;
3062 curOpt
.reps
[0] = reps
[0];
3063 curOpt
.reps
[1] = reps
[1];
3064 curOpt
.reps
[2] = reps
[2];
3065 curOpt
.reps
[3] = reps
[3];
3067 data
= p
.matchFinder
.GetPointerToCurrentPos(p
.matchFinderObj
) - 1;
3069 matchByte
= *(data
- reps
[0]);
3071 posState
= (position
& p
.pbMask
);
3074 The order of Price checks:
3078 < REP [ : LIT : REP_0 ]
3079 < MATCH [ : LIT : REP_0 ]
3083 uint curPrice
= curOpt
.price
;
3084 uint prob
= p
.isMatch
[state
][posState
];
3085 matchPrice
= curPrice
+ mixin(GET_PRICE_1
!"prob");
3086 litPrice
= curPrice
+ mixin(GET_PRICE_0
!"prob");
3089 nextOpt
= &p
.opt
[cast(usize
)cur
+ 1];
3090 nextIsLit
= 0/*False*/;
3092 // here we can allow skip_items in p->opt, if we don't check (nextOpt->price < kInfinityPrice)
3094 if ((nextOpt
.price
< kInfinityPrice
3095 // && !mixin(IsLitState!"state")
3096 && matchByte
== curByte
)
3097 || litPrice
> nextOpt
.price
3102 const(CLzmaProb
)* probs
= mixin(LIT_PROBS
!("position", "*(data - 1)"));
3103 litPrice
+= (!mixin(IsLitState
!"state") ?
3104 LitEnc_Matched_GetPrice(probs
, curByte
, matchByte
, p
.ProbPrices
.ptr
) :
3105 LitEnc_GetPrice(probs
, curByte
, p
.ProbPrices
.ptr
));
3107 if (litPrice
< nextOpt
.price
)
3109 nextOpt
.price
= litPrice
;
3111 mixin(MakeAs_Lit
!"nextOpt");
3112 nextIsLit
= 1/*True*/;
3116 repMatchPrice
= matchPrice
+ mixin(GET_PRICE_1
!"p.isRep[state]");
3118 numAvailFull
= p
.numAvail
;
3120 uint temp
= kNumOpts
- 1 - cur
;
3121 if (numAvailFull
> temp
)
3122 numAvailFull
= cast(uint)temp
;
3126 // ---------- SHORT_REP ----------
3127 if (mixin(IsLitState
!"state")) // 18.new
3128 if (matchByte
== curByte
)
3129 if (repMatchPrice
< nextOpt
.price
) // 18.new
3130 // if (numAvailFull < 2 || data[1] != *(data - reps[0] + 1))
3132 // nextOpt->price >= kInfinityPrice ||
3133 nextOpt
.len
< 2 // we can check nextOpt->len, if skip items are not allowed in p->opt
3134 ||
(nextOpt
.dist
!= 0
3135 // && nextOpt->extra <= 1 // 17.old
3139 uint shortRepPrice
= repMatchPrice
+ mixin(GetPrice_ShortRep
!("p", "state", "posState"));
3140 // if (shortRepPrice <= nextOpt->price) // 17.old
3141 if (shortRepPrice
< nextOpt
.price
) // 18.new
3143 nextOpt
.price
= shortRepPrice
;
3145 mixin(MakeAs_ShortRep
!"nextOpt");
3146 nextIsLit
= 0/*False*/;
3150 if (numAvailFull
< 2)
3152 numAvail
= (numAvailFull
<= p
.numFastBytes ? numAvailFull
: p
.numFastBytes
);
3154 // numAvail <= p->numFastBytes
3156 // ---------- LIT : REP_0 ----------
3159 && litPrice
!= 0 // 18.new
3160 && matchByte
!= curByte
3161 && numAvailFull
> 2)
3163 const ubyte *data2
= data
- reps
[0];
3164 if (data
[1] == data2
[1] && data
[2] == data2
[2])
3167 uint limit
= p
.numFastBytes
+ 1;
3168 if (limit
> numAvailFull
)
3169 limit
= numAvailFull
;
3170 for (len
= 3; len
< limit
&& data
[len
] == data2
[len
]; len
++)
3174 uint state2
= kLiteralNextStates
[state
];
3175 uint posState2
= (position
+ 1) & p
.pbMask
;
3176 uint price
= litPrice
+ mixin(GetPrice_Rep_0
!("p", "state2", "posState2"));
3178 uint offset
= cur
+ len
;
3188 // price2 = price + GetPrice_Len_Rep_0(p, len, state2, posState2);
3189 price2
= price
+ mixin(GET_PRICE_LEN
!("&p.repLenEnc", "posState2", "len"));
3191 opt
= &p
.opt
[offset
];
3193 if (price2
< opt
.price
)
3196 opt
.len
= cast(uint)len
;
3201 // while (len >= 3);
3207 startLen
= 2; /* speed optimization */
3210 // ---------- REP ----------
3211 uint repIndex
= 0; // 17.old
3212 // uint repIndex = mixin(IsLitState!"state") ? 0 : 1; // 18.notused
3213 for (; repIndex
< LZMA_NUM_REPS
; repIndex
++)
3217 const ubyte *data2
= data
- reps
[repIndex
];
3218 if (data
[0] != data2
[0] || data
[1] != data2
[1])
3221 for (len
= 2; len
< numAvail
&& data
[len
] == data2
[len
]; len
++)
3224 // if (len < startLen) continue; // 18.new: speed optimization
3227 uint offset
= cur
+ len
;
3233 price
= repMatchPrice
+ GetPrice_PureRep(p
, repIndex
, state
, posState
);
3236 uint price2
= price
+ mixin(GET_PRICE_LEN
!("&p.repLenEnc", "posState", "len2"));
3237 COptimal
*opt
= &p
.opt
[cur
+ len2
];
3238 if (price2
< opt
.price
)
3241 opt
.len
= cast(uint)len2
;
3242 opt
.dist
= cast(uint)repIndex
;
3246 while (--len2
>= 2);
3249 if (repIndex
== 0) startLen
= len
+ 1; // 17.old
3250 // startLen = len + 1; // 18.new
3254 // ---------- REP : LIT : REP_0 ----------
3255 // numFastBytes + 1 + numFastBytes
3257 uint len2
= len
+ 1;
3258 uint limit
= len2
+ p
.numFastBytes
;
3259 if (limit
> numAvailFull
)
3260 limit
= numAvailFull
;
3264 if (data
[len2
- 2] == data2
[len2
- 2])
3265 if (data
[len2
- 1] == data2
[len2
- 1])
3267 uint state2
= kRepNextStates
[state
];
3268 uint posState2
= (position
+ len
) & p
.pbMask
;
3269 price
+= mixin(GET_PRICE_LEN
!("&p.repLenEnc", "posState", "len"))
3270 + mixin(GET_PRICE_0
!"p.isMatch[state2][posState2]")
3271 + LitEnc_Matched_GetPrice(mixin(LIT_PROBS
!("position + len", "data[cast(usize)len - 1]")),
3272 data
[len
], data2
[len
], p
.ProbPrices
.ptr
);
3274 // state2 = kLiteralNextStates[state2];
3275 state2
= kState_LitAfterRep
;
3276 posState2
= (posState2
+ 1) & p
.pbMask
;
3279 price
+= mixin(GetPrice_Rep_0
!("p", "state2", "posState2"));
3281 for (; len2
< limit
&& data
[len2
] == data2
[len2
]; len2
++)
3288 uint offset
= cur
+ len
+ len2
;
3297 // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2);
3298 price2
= price
+ mixin(GET_PRICE_LEN
!("&p.repLenEnc", "posState2", "len2"));
3300 opt
= &p
.opt
[offset
];
3302 if (price2
< opt
.price
)
3305 opt
.len
= cast(uint)len2
;
3306 opt
.extra
= cast(CExtra
)(len
+ 1);
3307 opt
.dist
= cast(uint)repIndex
;
3310 // while (len2 >= 3);
3319 // ---------- MATCH ----------
3320 /* for (uint len = 2; len <= newLen; len++) */
3321 if (newLen
> numAvail
)
3324 for (numPairs
= 0; newLen
> p
.matches
[numPairs
]; numPairs
+= 2) {}
3325 p
.matches
[numPairs
] = cast(uint)newLen
;
3329 // startLen = 2; /* speed optimization */
3331 if (newLen
>= startLen
)
3333 uint normalMatchPrice
= matchPrice
+ mixin(GET_PRICE_0
!"p.isRep[state]");
3335 uint offs
, posSlot
, len
;
3338 uint offset
= cur
+ newLen
;
3344 while (startLen
> p
.matches
[offs
])
3346 dist
= p
.matches
[cast(usize
)offs
+ 1];
3348 // if (dist >= kNumFullDistances)
3349 mixin(GetPosSlot2
!("dist", "posSlot"));
3351 for (len
= /*2*/ startLen
; ; len
++)
3353 uint price
= normalMatchPrice
+ mixin(GET_PRICE_LEN
!("&p.lenEnc", "posState", "len"));
3356 uint lenNorm
= len
- 2;
3357 lenNorm
= mixin(GetLenToPosState2
!"lenNorm");
3358 if (dist
< kNumFullDistances
)
3359 price
+= p
.distancesPrices
[lenNorm
][dist
& (kNumFullDistances
- 1)];
3361 price
+= p
.posSlotPrices
[lenNorm
][posSlot
] + p
.alignPrices
[dist
& kAlignMask
];
3363 opt
= &p
.opt
[cur
+ len
];
3364 if (price
< opt
.price
)
3367 opt
.len
= cast(uint)len
;
3368 opt
.dist
= dist
+ LZMA_NUM_REPS
;
3373 if (len
== p
.matches
[offs
])
3375 // if (p->_maxMode) {
3376 // MATCH : LIT : REP_0
3378 const ubyte *data2
= data
- dist
- 1;
3379 uint len2
= len
+ 1;
3380 uint limit
= len2
+ p
.numFastBytes
;
3381 if (limit
> numAvailFull
)
3382 limit
= numAvailFull
;
3386 if (data
[len2
- 2] == data2
[len2
- 2])
3387 if (data
[len2
- 1] == data2
[len2
- 1])
3389 for (; len2
< limit
&& data
[len2
] == data2
[len2
]; len2
++)
3396 uint state2
= kMatchNextStates
[state
];
3397 uint posState2
= (position
+ len
) & p
.pbMask
;
3399 price
+= mixin(GET_PRICE_0
!"p.isMatch[state2][posState2]");
3400 price
+= LitEnc_Matched_GetPrice(mixin(LIT_PROBS
!("position + len", "data[cast(usize)len - 1]")),
3401 data
[len
], data2
[len
], p
.ProbPrices
.ptr
);
3403 // state2 = kLiteralNextStates[state2];
3404 state2
= kState_LitAfterMatch
;
3406 posState2
= (posState2
+ 1) & p
.pbMask
;
3407 price
+= mixin(GetPrice_Rep_0
!("p", "state2", "posState2"));
3409 offset
= cur
+ len
+ len2
;
3418 // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2);
3419 price2
= price
+ mixin(GET_PRICE_LEN
!("&p.repLenEnc", "posState2", "len2"));
3420 opt
= &p
.opt
[offset
];
3422 if (price2
< opt
.price
)
3425 opt
.len
= cast(uint)len2
;
3426 opt
.extra
= cast(CExtra
)(len
+ 1);
3427 opt
.dist
= dist
+ LZMA_NUM_REPS
;
3430 // while (len2 >= 3);
3436 if (offs
== numPairs
)
3438 dist
= p
.matches
[cast(usize
)offs
+ 1];
3439 // if (dist >= kNumFullDistances) {
3440 mixin(GetPosSlot2
!("dist", "posSlot"));
3448 p
.opt
[last
].price
= kInfinityPrice
;
3451 return Backward(p
, cur
);
3456 enum ChangePair(string smallDist
, string bigDist
) = `(((`~bigDist
~`) >> 7) > (`~smallDist
~`))`;
3460 private uint GetOptimumFast(CLzmaEnc
*p
)
3462 uint numAvail
, mainDist
;
3463 uint mainLen
, numPairs
, repIndex
, repLen
, i
;
3466 if (p
.additionalOffset
== 0)
3467 mainLen
= ReadMatchDistances(p
, &numPairs
);
3470 mainLen
= p
.longestMatchLen
;
3471 numPairs
= p
.numPairs
;
3474 numAvail
= p
.numAvail
;
3475 p
.backRes
= MARK_LIT
;
3478 // if (mainLen < 2 && p->state == 0) return 1; // 18.06.notused
3479 if (numAvail
> LZMA_MATCH_LEN_MAX
)
3480 numAvail
= LZMA_MATCH_LEN_MAX
;
3481 data
= p
.matchFinder
.GetPointerToCurrentPos(p
.matchFinderObj
) - 1;
3482 repLen
= repIndex
= 0;
3484 for (i
= 0; i
< LZMA_NUM_REPS
; i
++)
3487 const ubyte *data2
= data
- p
.reps
[i
];
3488 if (data
[0] != data2
[0] || data
[1] != data2
[1])
3490 for (len
= 2; len
< numAvail
&& data
[len
] == data2
[len
]; len
++)
3492 if (len
>= p
.numFastBytes
)
3494 p
.backRes
= cast(uint)i
;
3495 mixin(MOVE_POS1
!("p", "len - 1"));
3505 if (mainLen
>= p
.numFastBytes
)
3507 p
.backRes
= p
.matches
[cast(usize
)numPairs
- 1] + LZMA_NUM_REPS
;
3508 mixin(MOVE_POS1
!("p", "mainLen - 1"));
3512 mainDist
= 0; /* for GCC */
3516 mainDist
= p
.matches
[cast(usize
)numPairs
- 1];
3517 while (numPairs
> 2)
3520 if (mainLen
!= p
.matches
[cast(usize
)numPairs
- 4] + 1)
3522 dist2
= p
.matches
[cast(usize
)numPairs
- 3];
3523 if (!mixin(ChangePair
!("dist2", "mainDist")))
3529 if (mainLen
== 2 && mainDist
>= 0x80)
3534 if ( repLen
+ 1 >= mainLen
3535 ||
(repLen
+ 2 >= mainLen
&& mainDist
>= (1 << 9))
3536 ||
(repLen
+ 3 >= mainLen
&& mainDist
>= (1 << 15)))
3538 p
.backRes
= cast(uint)repIndex
;
3539 mixin(MOVE_POS1
!("p", "repLen - 1"));
3543 if (mainLen
< 2 || numAvail
<= 2)
3547 uint len1
= ReadMatchDistances(p
, &p
.numPairs
);
3548 p
.longestMatchLen
= len1
;
3552 uint newDist
= p
.matches
[cast(usize
)p
.numPairs
- 1];
3553 if ( (len1
>= mainLen
&& newDist
< mainDist
)
3554 ||
(len1
== mainLen
+ 1 && !mixin(ChangePair
!("mainDist", "newDist")))
3555 ||
(len1
> mainLen
+ 1)
3556 ||
(len1
+ 1 >= mainLen
&& mainLen
>= 3 && mixin(ChangePair
!("newDist", "mainDist"))))
3561 data
= p
.matchFinder
.GetPointerToCurrentPos(p
.matchFinderObj
) - 1;
3563 for (i
= 0; i
< LZMA_NUM_REPS
; i
++)
3566 const ubyte *data2
= data
- p
.reps
[i
];
3567 if (data
[0] != data2
[0] || data
[1] != data2
[1])
3569 limit
= mainLen
- 1;
3570 for (len
= 2;; len
++)
3574 if (data
[len
] != data2
[len
])
3579 p
.backRes
= mainDist
+ LZMA_NUM_REPS
;
3582 mixin(MOVE_POS1
!("p", "mainLen - 2"));
3590 private void WriteEndMarker(CLzmaEnc
*p
, uint posState
)
3596 CLzmaProb
*prob
= &p
.isMatch
[p
.state
][posState
];
3597 mixin(RC_BIT_PRE
!("&p.rc", "prob"));
3598 mixin(RC_BIT_1
!("&p.rc", "prob"));
3599 prob
= &p
.isRep
[p
.state
];
3600 mixin(RC_BIT_PRE
!("&p.rc", "prob"));
3601 mixin(RC_BIT_0
!("&p.rc", "prob"));
3603 p
.state
= kMatchNextStates
[p
.state
];
3606 LenEnc_Encode(&p
.lenProbs
, &p
.rc
, 0, posState
);
3610 // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[0], (1 << kNumPosSlotBits) - 1);
3611 CLzmaProb
*probs
= p
.posSlotEncoder
[0].ptr
;
3616 mixin(RC_BIT_PRE
!("p", "probs + m"));
3617 mixin(RC_BIT_1
!("&p.rc", "probs + m"));
3620 while (m
< (1 << kNumPosSlotBits
));
3623 // RangeEnc_EncodeDirectBits(&p->rc, ((uint)1 << (30 - kNumAlignBits)) - 1, 30 - kNumAlignBits); uint range = p->range;
3624 uint numBits
= 30 - kNumAlignBits
;
3629 mixin(RC_NORM
!"&p.rc");
3635 // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
3636 CLzmaProb
*probs
= p
.posAlignEncoder
.ptr
;
3641 mixin(RC_BIT_PRE
!("p", "probs + m"));
3642 mixin(RC_BIT_1
!("&p.rc", "probs + m"));
3645 while (m
< kAlignTableSize
);
3651 private SRes
CheckErrors(CLzmaEnc
*p
)
3653 if (p
.result
!= SZ_OK
)
3655 if (p
.rc
.res
!= SZ_OK
)
3656 p
.result
= SZ_ERROR_WRITE
;
3658 if ((p
.matchFinderBase
).result
!= SZ_OK
)
3659 p
.result
= SZ_ERROR_READ
;
3661 if (p
.result
!= SZ_OK
)
3662 p
.finished
= 1/*True*/;
3668 private SRes
Flush(CLzmaEnc
*p
, uint nowPos
)
3670 /* ReleaseMFStream(); */
3671 p
.finished
= 1/*True*/;
3673 WriteEndMarker(p
, nowPos
& p
.pbMask
);
3674 RangeEnc_FlushData(&p
.rc
);
3675 RangeEnc_FlushStream(&p
.rc
);
3676 return CheckErrors(p
);
3681 private void FillAlignPrices(CLzmaEnc
*p
)
3684 const CProbPrice
*ProbPrices
= p
.ProbPrices
.ptr
;
3685 const CLzmaProb
*probs
= p
.posAlignEncoder
.ptr
;
3686 // p->alignPriceCount = 0;
3687 for (i
= 0; i
< kAlignTableSize
/ 2; i
++)
3694 bit
= sym
& 1; sym
>>= 1; price
+= mixin(GET_PRICEa
!("probs[m]", "bit")); m
= (m
<< 1) + bit
;
3695 bit
= sym
& 1; sym
>>= 1; price
+= mixin(GET_PRICEa
!("probs[m]", "bit")); m
= (m
<< 1) + bit
;
3696 bit
= sym
& 1; sym
>>= 1; price
+= mixin(GET_PRICEa
!("probs[m]", "bit")); m
= (m
<< 1) + bit
;
3698 p
.alignPrices
[i
] = price
+ mixin(GET_PRICEa_0
!"prob");
3699 p
.alignPrices
[i
+ 8] = price
+ mixin(GET_PRICEa_1
!"prob");
3700 // p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
3706 private void FillDistancesPrices(CLzmaEnc
*p
)
3708 // int y; for (y = 0; y < 100; y++) {
3710 uint[kNumFullDistances
] tempPrices
;
3713 const CProbPrice
*ProbPrices
= p
.ProbPrices
.ptr
;
3714 p
.matchPriceCount
= 0;
3716 for (i
= kStartPosModelIndex
/ 2; i
< kNumFullDistances
/ 2; i
++)
3718 uint posSlot
= mixin(GetPosSlot1
!"i");
3719 uint footerBits
= (posSlot
>> 1) - 1;
3720 uint base
= ((2 |
(posSlot
& 1)) << footerBits
);
3721 const(CLzmaProb
)* probs
= p
.posEncoders
.ptr
+ cast(usize
)base
* 2;
3722 // tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base, footerBits, i - base, p->ProbPrices);
3726 uint offset
= cast(uint)1 << footerBits
;
3734 price
+= mixin(GET_PRICEa
!("probs[m]", "bit"));
3737 while (--footerBits
);
3740 uint prob
= probs
[m
];
3741 tempPrices
[base
] = price
+ mixin(GET_PRICEa_0
!"prob");
3742 tempPrices
[base
+ offset
] = price
+ mixin(GET_PRICEa_1
!"prob");
3746 for (lps
= 0; lps
< kNumLenToPosStates
; lps
++)
3749 uint distTableSize2
= (p
.distTableSize
+ 1) >> 1;
3750 uint *posSlotPrices
= p
.posSlotPrices
[lps
].ptr
;
3751 const CLzmaProb
*probs
= p
.posSlotEncoder
[lps
].ptr
;
3753 for (slot
= 0; slot
< distTableSize2
; slot
++)
3755 // posSlotPrices[slot] = RcTree_GetPrice(encoder, kNumPosSlotBits, slot, p->ProbPrices);
3758 uint sym
= slot
+ (1 << (kNumPosSlotBits
- 1));
3760 bit
= sym
& 1; sym
>>= 1; price
= mixin(GET_PRICEa
!("probs[sym]", "bit"));
3761 bit
= sym
& 1; sym
>>= 1; price
+= mixin(GET_PRICEa
!("probs[sym]", "bit"));
3762 bit
= sym
& 1; sym
>>= 1; price
+= mixin(GET_PRICEa
!("probs[sym]", "bit"));
3763 bit
= sym
& 1; sym
>>= 1; price
+= mixin(GET_PRICEa
!("probs[sym]", "bit"));
3764 bit
= sym
& 1; sym
>>= 1; price
+= mixin(GET_PRICEa
!("probs[sym]", "bit"));
3765 prob
= probs
[cast(usize
)slot
+ (1 << (kNumPosSlotBits
- 1))];
3766 posSlotPrices
[cast(usize
)slot
* 2 ] = price
+ mixin(GET_PRICEa_0
!"prob");
3767 posSlotPrices
[cast(usize
)slot
* 2 + 1] = price
+ mixin(GET_PRICEa_1
!"prob");
3771 uint delta
= (cast(uint)((kEndPosModelIndex
/ 2 - 1) - kNumAlignBits
) << kNumBitPriceShiftBits
);
3772 for (slot
= kEndPosModelIndex
/ 2; slot
< distTableSize2
; slot
++)
3774 posSlotPrices
[cast(usize
)slot
* 2 ] += delta
;
3775 posSlotPrices
[cast(usize
)slot
* 2 + 1] += delta
;
3776 delta
+= (cast(uint)1 << kNumBitPriceShiftBits
);
3781 uint *dp
= p
.distancesPrices
[lps
].ptr
;
3783 dp
[0] = posSlotPrices
[0];
3784 dp
[1] = posSlotPrices
[1];
3785 dp
[2] = posSlotPrices
[2];
3786 dp
[3] = posSlotPrices
[3];
3788 for (i
= 4; i
< kNumFullDistances
; i
+= 2)
3790 uint slotPrice
= posSlotPrices
[mixin(GetPosSlot1
!"i")];
3791 dp
[i
] = slotPrice
+ tempPrices
[i
];
3792 dp
[i
+ 1] = slotPrice
+ tempPrices
[i
+ 1];
3801 private void LzmaEnc_Construct(CLzmaEnc
*p
)
3803 RangeEnc_Construct(&p
.rc
);
3804 MatchFinder_Construct(&(p
.matchFinderBase
));
3807 CLzmaEncProps props
;
3808 LzmaEncProps_Init(&props
);
3809 LzmaEnc_SetProps(p
, &props
);
3812 //#ifndef LZMA_LOG_BSR
3813 LzmaEnc_FastPosInit(p
.g_FastPos
.ptr
);
3816 LzmaEnc_InitPriceTables(p
.ProbPrices
.ptr
);
3818 p
.saveState
.litProbs
= null;
3822 //==========================================================================
3826 //==========================================================================
3827 public CLzmaEncHandle
LzmaEnc_Create (ISzAllocPtr alloc
) {
3828 void *p
= ISzAlloc_Alloc(alloc
, CLzmaEnc
.sizeof
);
3829 if (p
) LzmaEnc_Construct(cast(CLzmaEnc
*)p
);
3834 private void LzmaEnc_FreeLits(CLzmaEnc
*p
, ISzAllocPtr alloc
)
3836 ISzAlloc_Free(alloc
, p
.litProbs
);
3837 ISzAlloc_Free(alloc
, p
.saveState
.litProbs
);
3839 p
.saveState
.litProbs
= null;
3842 private void LzmaEnc_Destruct(CLzmaEnc
*p
, ISzAllocPtr alloc
, ISzAllocPtr allocBig
)
3844 MatchFinder_Free(&(p
.matchFinderBase
), allocBig
);
3845 LzmaEnc_FreeLits(p
, alloc
);
3846 RangeEnc_Free(&p
.rc
, alloc
);
3850 //==========================================================================
3854 //==========================================================================
3855 public void LzmaEnc_Destroy (CLzmaEncHandle p
, ISzAllocPtr alloc
, ISzAllocPtr allocBig
) {
3857 LzmaEnc_Destruct(cast(CLzmaEnc
*)p
, alloc
, allocBig
);
3858 ISzAlloc_Free(alloc
, p
);
3864 private SRes
LzmaEnc_CodeOneBlock(CLzmaEnc
*p
, uint maxPackSize
, uint maxUnpackSize
)
3866 uint nowPos32
, startPos32
;
3869 p
.matchFinder
.Init(p
.matchFinderObj
);
3875 int rinres
= CheckErrors(p
);
3876 if (rinres
!= 0) return rinres
;
3878 nowPos32
= cast(uint)p
.nowPos64
;
3879 startPos32
= nowPos32
;
3881 if (p
.nowPos64
== 0)
3885 if (p
.matchFinder
.GetNumAvailableBytes(p
.matchFinderObj
) == 0)
3886 return Flush(p
, nowPos32
);
3887 ReadMatchDistances(p
, &numPairs
);
3888 RangeEnc_EncodeBit_0(&p
.rc
, &p
.isMatch
[kState_Start
][0]);
3889 // p->state = kLiteralNextStates[p->state];
3890 curByte
= *(p
.matchFinder
.GetPointerToCurrentPos(p
.matchFinderObj
) - p
.additionalOffset
);
3891 LitEnc_Encode(&p
.rc
, p
.litProbs
, curByte
);
3892 p
.additionalOffset
--;
3896 if (p
.matchFinder
.GetNumAvailableBytes(p
.matchFinderObj
) != 0)
3902 uint range
, ttt
, newBound
;
3906 len
= GetOptimumFast(p
);
3909 uint oci
= p
.optCur
;
3910 if (p
.optEnd
== oci
)
3911 len
= GetOptimum(p
, nowPos32
);
3914 const COptimal
*opt
= &p
.opt
[oci
];
3916 p
.backRes
= opt
.dist
;
3921 posState
= cast(uint)nowPos32
& p
.pbMask
;
3923 probs
= &p
.isMatch
[p
.state
][posState
];
3925 mixin(RC_BIT_PRE
!("&p.rc", "probs"));
3931 printf("\n pos = %6X, len = %3u pos = %6u", nowPos32, len, dist);
3935 if (dist
== MARK_LIT
)
3941 mixin(RC_BIT_0
!("&p.rc", "probs"));
3943 data
= p
.matchFinder
.GetPointerToCurrentPos(p
.matchFinderObj
) - p
.additionalOffset
;
3944 probs
= mixin(LIT_PROBS
!("nowPos32", "*(data - 1)"));
3947 p
.state
= kLiteralNextStates
[state
];
3948 if (mixin(IsLitState
!"state"))
3949 LitEnc_Encode(&p
.rc
, probs
, curByte
);
3951 LitEnc_EncodeMatched(&p
.rc
, probs
, curByte
, *(data
- p
.reps
[0]));
3955 mixin(RC_BIT_1
!("&p.rc", "probs"));
3956 probs
= &p
.isRep
[p
.state
];
3957 mixin(RC_BIT_PRE
!("&p.rc", "probs"));
3959 if (dist
< LZMA_NUM_REPS
)
3961 mixin(RC_BIT_1
!("&p.rc", "probs"));
3962 probs
= &p
.isRepG0
[p
.state
];
3963 mixin(RC_BIT_PRE
!("&p.rc", "probs"));
3966 mixin(RC_BIT_0
!("&p.rc", "probs"));
3967 probs
= &p
.isRep0Long
[p
.state
][posState
];
3968 mixin(RC_BIT_PRE
!("&p.rc", "probs"));
3971 mixin(RC_BIT_1_BASE
!("&p.rc", "probs"));
3975 mixin(RC_BIT_0_BASE
!("&p.rc", "probs"));
3976 p
.state
= kShortRepNextStates
[p
.state
];
3981 mixin(RC_BIT_1
!("&p.rc", "probs"));
3982 probs
= &p
.isRepG1
[p
.state
];
3983 mixin(RC_BIT_PRE
!("&p.rc", "probs"));
3986 mixin(RC_BIT_0_BASE
!("&p.rc", "probs"));
3991 mixin(RC_BIT_1
!("&p.rc", "probs"));
3992 probs
= &p
.isRepG2
[p
.state
];
3993 mixin(RC_BIT_PRE
!("&p.rc", "probs"));
3996 mixin(RC_BIT_0_BASE
!("&p.rc", "probs"));
4001 mixin(RC_BIT_1_BASE
!("&p.rc", "probs"));
4003 p
.reps
[3] = p
.reps
[2];
4005 p
.reps
[2] = p
.reps
[1];
4007 p
.reps
[1] = p
.reps
[0];
4011 mixin(RC_NORM
!"&p.rc");
4017 LenEnc_Encode(&p
.repLenProbs
, &p
.rc
, len
- LZMA_MATCH_LEN_MIN
, posState
);
4018 --p
.repLenEncCounter
;
4019 p
.state
= kRepNextStates
[p
.state
];
4025 mixin(RC_BIT_0
!("&p.rc", "probs"));
4027 p
.state
= kMatchNextStates
[p
.state
];
4029 LenEnc_Encode(&p
.lenProbs
, &p
.rc
, len
- LZMA_MATCH_LEN_MIN
, posState
);
4030 // --p->lenEnc.counter;
4032 dist
-= LZMA_NUM_REPS
;
4033 p
.reps
[3] = p
.reps
[2];
4034 p
.reps
[2] = p
.reps
[1];
4035 p
.reps
[1] = p
.reps
[0];
4036 p
.reps
[0] = dist
+ 1;
4038 p
.matchPriceCount
++;
4039 mixin(GetPosSlot
!("dist", "posSlot"));
4040 // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[mixin(GetLenToPosState!"len")], posSlot);
4042 uint sym
= cast(uint)posSlot
+ (1 << kNumPosSlotBits
);
4044 probs
= p
.posSlotEncoder
[mixin(GetLenToPosState
!"len")].ptr
;
4047 CLzmaProb
*prob
= probs
+ (sym
>> kNumPosSlotBits
);
4048 uint bit
= (sym
>> (kNumPosSlotBits
- 1)) & 1;
4050 mixin(RC_BIT
!("&p.rc", "prob", "bit"));
4052 while (sym
< (1 << kNumPosSlotBits
* 2));
4056 if (dist
>= kStartPosModelIndex
)
4058 uint footerBits
= ((posSlot
>> 1) - 1);
4060 if (dist
< kNumFullDistances
)
4062 uint base
= ((2 |
(posSlot
& 1)) << footerBits
);
4063 RcTree_ReverseEncode(&p
.rc
, p
.posEncoders
.ptr
+ base
, footerBits
, cast(uint)(dist
/* - base */));
4067 uint pos2
= (dist |
0xF) << (32 - footerBits
);
4069 // RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
4074 p->rc.low += range & (0 - ((dist >> --footerBits) & 1));
4077 while (footerBits > kNumAlignBits);
4082 p
.rc
.low
+= range
& (0 - (pos2
>> 31));
4084 mixin(RC_NORM
!"&p.rc");
4086 while (pos2
!= 0xF0000000);
4089 // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
4094 bit
= dist
& 1; dist
>>= 1; mixin(RC_BIT
!("&p.rc", "p.posAlignEncoder.ptr + m", "bit")); m
= (m
<< 1) + bit
;
4095 bit
= dist
& 1; dist
>>= 1; mixin(RC_BIT
!("&p.rc", "p.posAlignEncoder.ptr + m", "bit")); m
= (m
<< 1) + bit
;
4096 bit
= dist
& 1; dist
>>= 1; mixin(RC_BIT
!("&p.rc", "p.posAlignEncoder.ptr + m", "bit")); m
= (m
<< 1) + bit
;
4097 bit
= dist
& 1; mixin(RC_BIT
!("&p.rc", "p.posAlignEncoder.ptr + m", "bit"));
4099 // p->alignPriceCount++;
4106 nowPos32
+= cast(uint)len
;
4107 p
.additionalOffset
-= len
;
4109 if (p
.additionalOffset
== 0)
4116 if (p->alignPriceCount >= 16) // kAlignTableSize
4118 if (p->matchPriceCount >= 128)
4119 FillDistancesPrices(p);
4120 if (p->lenEnc.counter <= 0)
4121 LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices);
4123 if (p
.matchPriceCount
>= 64)
4126 // { int y; for (y = 0; y < 100; y++) {
4127 FillDistancesPrices(p
);
4129 LenPriceEnc_UpdateTables(&p
.lenEnc
, cast(uint)1 << p
.pb
, &p
.lenProbs
, p
.ProbPrices
.ptr
);
4131 if (p
.repLenEncCounter
<= 0)
4133 p
.repLenEncCounter
= REP_LEN_COUNT
;
4134 LenPriceEnc_UpdateTables(&p
.repLenEnc
, cast(uint)1 << p
.pb
, &p
.repLenProbs
, p
.ProbPrices
.ptr
);
4138 if (p
.matchFinder
.GetNumAvailableBytes(p
.matchFinderObj
) == 0)
4140 processed
= nowPos32
- startPos32
;
4144 if (processed
+ kNumOpts
+ 300 >= maxUnpackSize
4145 ||
mixin(RangeEnc_GetProcessed_sizet
!"&p.rc") + kPackReserve
>= maxPackSize
)
4148 else if (processed
>= (1 << 17))
4150 p
.nowPos64
+= nowPos32
- startPos32
;
4151 return CheckErrors(p
);
4156 p
.nowPos64
+= nowPos32
- startPos32
;
4157 return Flush(p
, nowPos32
);
4162 enum kBigHashDicLimit
= (cast(uint)1 << 24);
4164 private SRes
LzmaEnc_Alloc(CLzmaEnc
*p
, uint keepWindowSize
, ISzAllocPtr alloc
, ISzAllocPtr allocBig
)
4166 uint beforeSize
= kNumOpts
;
4169 if (!RangeEnc_Alloc(&p
.rc
, alloc
))
4170 return SZ_ERROR_MEM
;
4173 uint lclp
= p
.lc
+ p
.lp
;
4174 if (!p
.litProbs ||
!p
.saveState
.litProbs || p
.lclp
!= lclp
)
4176 LzmaEnc_FreeLits(p
, alloc
);
4177 p
.litProbs
= cast(CLzmaProb
*)ISzAlloc_Alloc(alloc
, (cast(uint)0x300 << lclp
) * CLzmaProb
.sizeof
);
4178 p
.saveState
.litProbs
= cast(CLzmaProb
*)ISzAlloc_Alloc(alloc
, (cast(uint)0x300 << lclp
) * CLzmaProb
.sizeof
);
4179 if (!p
.litProbs ||
!p
.saveState
.litProbs
)
4181 LzmaEnc_FreeLits(p
, alloc
);
4182 return SZ_ERROR_MEM
;
4188 (p
.matchFinderBase
).bigHash
= cast(ubyte)(p
.dictSize
> kBigHashDicLimit ?
1 : 0);
4191 dictSize
= p
.dictSize
;
4192 if (dictSize
== (cast(uint)2 << 30) ||
4193 dictSize
== (cast(uint)3 << 30))
4195 /* 21.03 : here we reduce the dictionary for 2 reasons:
4196 1) we don't want 32-bit back_distance matches in decoder for 2 GB dictionary.
4197 2) we want to elimate useless last MatchFinder_Normalize3() for corner cases,
4198 where data size is aligned for 1 GB: 5/6/8 GB.
4199 That reducing must be >= 1 for such corner cases. */
4203 if (beforeSize
+ dictSize
< keepWindowSize
)
4204 beforeSize
= keepWindowSize
- dictSize
;
4206 /* in worst case we can look ahead for
4207 max(LZMA_MATCH_LEN_MAX, numFastBytes + 1 + numFastBytes) bytes.
4208 we send larger value for (keepAfter) to MantchFinder_Create():
4209 (numFastBytes + LZMA_MATCH_LEN_MAX + 1)
4212 if (!MatchFinder_Create(&(p
.matchFinderBase
), dictSize
, beforeSize
,
4213 p
.numFastBytes
, LZMA_MATCH_LEN_MAX
+ 1 /* 21.03 */
4215 return SZ_ERROR_MEM
;
4216 p
.matchFinderObj
= &(p
.matchFinderBase
);
4217 MatchFinder_CreateVTable(&(p
.matchFinderBase
), &p
.matchFinder
);
4222 private void LzmaEnc_Init(CLzmaEnc
*p
)
4231 RangeEnc_Init(&p
.rc
);
4233 for (i
= 0; i
< (1 << kNumAlignBits
); i
++)
4234 p
.posAlignEncoder
[i
] = kProbInitValue
;
4236 for (i
= 0; i
< kNumStates
; i
++)
4239 for (j
= 0; j
< LZMA_NUM_PB_STATES_MAX
; j
++)
4241 p
.isMatch
[i
][j
] = kProbInitValue
;
4242 p
.isRep0Long
[i
][j
] = kProbInitValue
;
4244 p
.isRep
[i
] = kProbInitValue
;
4245 p
.isRepG0
[i
] = kProbInitValue
;
4246 p
.isRepG1
[i
] = kProbInitValue
;
4247 p
.isRepG2
[i
] = kProbInitValue
;
4251 for (i
= 0; i
< kNumLenToPosStates
; i
++)
4253 CLzmaProb
*probs
= p
.posSlotEncoder
[i
].ptr
;
4255 for (j
= 0; j
< (1 << kNumPosSlotBits
); j
++)
4256 probs
[j
] = kProbInitValue
;
4260 for (i
= 0; i
< kNumFullDistances
; i
++)
4261 p
.posEncoders
[i
] = kProbInitValue
;
4265 uint num
= cast(uint)0x300 << (p
.lp
+ p
.lc
);
4267 CLzmaProb
*probs
= p
.litProbs
;
4268 for (k
= 0; k
< num
; k
++)
4269 probs
[k
] = kProbInitValue
;
4273 LenEnc_Init(&p
.lenProbs
);
4274 LenEnc_Init(&p
.repLenProbs
);
4280 for (i
= 0; i
< kNumOpts
; i
++)
4281 p
.opt
[i
].price
= kInfinityPrice
;
4284 p
.additionalOffset
= 0;
4286 p
.pbMask
= (cast(uint)1 << p
.pb
) - 1;
4287 p
.lpMask
= (cast(uint)0x100 << p
.lp
) - (cast(uint)0x100 >> p
.lc
);
4289 // p->mf_Failure = False;
4293 private void LzmaEnc_InitPrices(CLzmaEnc
*p
)
4297 FillDistancesPrices(p
);
4301 p
.lenEnc
.tableSize
=
4302 p
.repLenEnc
.tableSize
=
4303 p
.numFastBytes
+ 1 - LZMA_MATCH_LEN_MIN
;
4305 p
.repLenEncCounter
= REP_LEN_COUNT
;
4307 LenPriceEnc_UpdateTables(&p
.lenEnc
, cast(uint)1 << p
.pb
, &p
.lenProbs
, p
.ProbPrices
.ptr
);
4308 LenPriceEnc_UpdateTables(&p
.repLenEnc
, cast(uint)1 << p
.pb
, &p
.repLenProbs
, p
.ProbPrices
.ptr
);
4311 private SRes
LzmaEnc_AllocAndInit(CLzmaEnc
*p
, uint keepWindowSize
, ISzAllocPtr alloc
, ISzAllocPtr allocBig
)
4314 for (i
= kEndPosModelIndex
/ 2; i
< kDicLogSizeMax
; i
++)
4315 if (p
.dictSize
<= (cast(uint)1 << i
))
4317 p
.distTableSize
= i
* 2;
4319 p
.finished
= 0/*False*/;
4321 int rinres
= LzmaEnc_Alloc(p
, keepWindowSize
, alloc
, allocBig
);
4322 if (rinres
!= 0) return rinres
;
4324 LzmaEnc_InitPrices(p
);
4329 private SRes
LzmaEnc_Prepare(CLzmaEncHandle pp
, ISeqOutStream
*outStream
, ISeqInStream
*inStream
,
4330 ISzAllocPtr alloc
, ISzAllocPtr allocBig
)
4332 CLzmaEnc
*p
= cast(CLzmaEnc
*)pp
;
4333 (p
.matchFinderBase
).stream
= inStream
;
4335 p
.rc
.outStream
= outStream
;
4336 return LzmaEnc_AllocAndInit(p
, 0, alloc
, allocBig
);
4339 private void LzmaEnc_SetInputBuf(CLzmaEnc
*p
, const ubyte *src
, usize srcLen
)
4341 (p
.matchFinderBase
).directInput
= 1;
4342 (p
.matchFinderBase
).bufferBase
= cast(ubyte *)src
;
4343 (p
.matchFinderBase
).directInputRem
= srcLen
;
4346 private SRes
LzmaEnc_MemPrepare(CLzmaEncHandle pp
, const ubyte *src
, usize srcLen
,
4347 uint keepWindowSize
, ISzAllocPtr alloc
, ISzAllocPtr allocBig
)
4349 CLzmaEnc
*p
= cast(CLzmaEnc
*)pp
;
4350 LzmaEnc_SetInputBuf(p
, src
, srcLen
);
4353 LzmaEnc_SetDataSize(pp
, srcLen
);
4354 return LzmaEnc_AllocAndInit(p
, keepWindowSize
, alloc
, allocBig
);
4357 private void LzmaEnc_Finish(CLzmaEncHandle pp
)
4363 struct CLzmaEnc_SeqOutStreamBuf
{
4372 #define MY_offsetof(type, m) ((size_t)&(((type *)0)->m))
4373 #define MY_container_of(ptr, type, m) ((type *)(void *)((char *)(void *)(1 ? (ptr) : &((type *)0)->m) - MY_offsetof(type, m)))
4374 #define CONTAINER_FROM_VTBL(ptr, type, m) MY_container_of(ptr, type, m)
4377 private usize
SeqOutStreamBuf_Write(ISeqOutStream
* pp
, const(void)* data
, usize size
) nothrow
4379 //CLzmaEnc_SeqOutStreamBuf *p = CONTAINER_FROM_VTBL(pp, CLzmaEnc_SeqOutStreamBuf, vt);
4380 CLzmaEnc_SeqOutStreamBuf
* p
= cast(CLzmaEnc_SeqOutStreamBuf
*)(cast(ubyte*)pp
-CLzmaEnc_SeqOutStreamBuf
.vt
.offsetof
);
4384 p
.overflow
= 1/*True*/;
4386 import core
.stdc
.string
: memcpy
;
4387 memcpy(p
.data
, data
, size
);
4395 private SRes
LzmaEnc_Encode2(CLzmaEnc
*p
, ICompressProgress
*progress
)
4401 res
= LzmaEnc_CodeOneBlock(p
, 0, 0);
4402 if (res
!= SZ_OK || p
.finished
)
4406 //res = ICompressProgress_Progress(progress, p.nowPos64, mixin(RangeEnc_GetProcessed!"&p.rc"));
4407 res
= progress
.Progress(progress
, p
.nowPos64
, mixin(RangeEnc_GetProcessed
!"&p.rc"));
4410 res
= SZ_ERROR_PROGRESS
;
4419 if (res == SZ_OK && !Inline_MatchFinder_IsFinishedOK(&(p.matchFinderBase)))
4420 res = SZ_ERROR_FAIL;
4428 //==========================================================================
4432 //==========================================================================
4433 public SRes
LzmaEnc_Encode (CLzmaEncHandle pp
, ISeqOutStream
*outStream
, ISeqInStream
*inStream
,
4434 ICompressProgress
*progress
, ISzAllocPtr alloc
, ISzAllocPtr allocBig
)
4436 int rinres
= LzmaEnc_Prepare(pp
, outStream
, inStream
, alloc
, allocBig
);
4437 if (rinres
!= 0) return rinres
;
4438 return LzmaEnc_Encode2(cast(CLzmaEnc
*)pp
, progress
);
4442 //==========================================================================
4444 // LzmaEnc_WriteProperties
4446 //==========================================================================
4447 public SRes
LzmaEnc_WriteProperties (CLzmaEncHandle pp
, ubyte* props
, uint* size
) @nogc {
4448 if (*size
< LZMA_PROPS_SIZE
) return SZ_ERROR_PARAM
;
4449 *size
= LZMA_PROPS_SIZE
;
4451 const(CLzmaEnc
)* p
= cast(const(CLzmaEnc
)*)pp
;
4452 immutable uint dictSize
= p
.dictSize
;
4454 props
[0] = cast(ubyte)((p
.pb
* 5 + p
.lp
) * 9 + p
.lc
);
4456 // we write aligned dictionary value to properties for lzma decoder
4457 if (dictSize
>= (cast(uint)1 << 21)) {
4458 const uint kDictMask
= (cast(uint)1 << 20) - 1;
4459 v
= (dictSize
+ kDictMask
) & ~kDictMask
;
4460 if (v
< dictSize
) v
= dictSize
;
4464 v
= cast(uint)(2 + (i
& 1)) << (i
>> 1);
4466 } while (v
< dictSize
);
4469 SetUi32(props
+ 1, v
);
4474 //==========================================================================
4476 // LzmaEnc_IsWriteEndMark
4478 //==========================================================================
4479 public uint LzmaEnc_IsWriteEndMark (CLzmaEncHandle pp
) @nogc {
4480 return cast(uint)(cast(CLzmaEnc
*)pp
).writeEndMark
;
4484 //==========================================================================
4486 // LzmaEnc_MemEncode
4488 //==========================================================================
4489 public SRes
LzmaEnc_MemEncode (CLzmaEncHandle pp
, ubyte* dest
, usize
* destLen
, const(ubyte)* src
, usize srcLen
,
4490 int writeEndMark
, ICompressProgress
*progress
, ISzAllocPtr alloc
, ISzAllocPtr allocBig
)
4493 CLzmaEnc
*p
= cast(CLzmaEnc
*)pp
;
4495 CLzmaEnc_SeqOutStreamBuf outStream
;
4497 //outStream.vt.Write = &SeqOutStreamBuf_Write;
4498 outStream
.vt
.Write
= delegate usize (ISeqOutStream
* pp
, const(void)* data
, usize size
) nothrow {
4499 return SeqOutStreamBuf_Write(pp
, data
, size
);
4502 outStream
.data
= dest
;
4503 outStream
.rem
= *destLen
;
4504 outStream
.overflow
= 0/*False*/;
4506 p
.writeEndMark
= writeEndMark
;
4507 p
.rc
.outStream
= &outStream
.vt
;
4509 res
= LzmaEnc_MemPrepare(pp
, src
, srcLen
, 0, alloc
, allocBig
);
4513 res
= LzmaEnc_Encode2(p
, progress
);
4514 if (res
== SZ_OK
&& p
.nowPos64
!= srcLen
)
4515 res
= SZ_ERROR_FAIL
;
4518 *destLen
-= outStream
.rem
;
4519 if (outStream
.overflow
)
4520 return SZ_ERROR_OUTPUT_EOF
;
4525 //==========================================================================
4529 //==========================================================================
4530 public SRes
LzmaEncode (ubyte* dest
, usize
* destLen
, const(ubyte)* src
, usize srcLen
,
4531 const(CLzmaEncProps
)* props
, ubyte* propsEncoded
, usize
* propsSize
,
4532 int writeEndMark
, ICompressProgress
*progress
, ISzAllocPtr alloc
, ISzAllocPtr allocBig
)
4534 CLzmaEnc
*p
= cast(CLzmaEnc
*)LzmaEnc_Create(alloc
);
4537 return SZ_ERROR_MEM
;
4539 res
= LzmaEnc_SetProps(p
, props
);
4542 res
= LzmaEnc_WriteProperties(p
, propsEncoded
, propsSize
);
4544 res
= LzmaEnc_MemEncode(p
, dest
, destLen
, src
, srcLen
,
4545 writeEndMark
, progress
, alloc
, allocBig
);
4548 LzmaEnc_Destroy(p
, alloc
, allocBig
);