1 /* LzFindMt.c -- multithreaded Match finder for LZ algorithms
2 2018-12-29 : Igor Pavlov : Public domain */
10 static void MtSync_Construct(CMtSync
*p
)
12 p
->wasCreated
= False
;
13 p
->csWasInitialized
= False
;
14 p
->csWasEntered
= False
;
15 Thread_Construct(&p
->thread
);
16 Event_Construct(&p
->canStart
);
17 Event_Construct(&p
->wasStarted
);
18 Event_Construct(&p
->wasStopped
);
19 Semaphore_Construct(&p
->freeSemaphore
);
20 Semaphore_Construct(&p
->filledSemaphore
);
23 static void MtSync_GetNextBlock(CMtSync
*p
)
27 p
->numProcessedBlocks
= 1;
29 p
->stopWriting
= False
;
31 Event_Reset(&p
->wasStarted
);
32 Event_Reset(&p
->wasStopped
);
34 Event_Set(&p
->canStart
);
35 Event_Wait(&p
->wasStarted
);
37 // if (mt) MatchFinder_Init_LowHash(mt->MatchFinder);
41 CriticalSection_Leave(&p
->cs
);
42 p
->csWasEntered
= False
;
43 p
->numProcessedBlocks
++;
44 Semaphore_Release1(&p
->freeSemaphore
);
46 Semaphore_Wait(&p
->filledSemaphore
);
47 CriticalSection_Enter(&p
->cs
);
48 p
->csWasEntered
= True
;
51 /* MtSync_StopWriting must be called if Writing was started */
53 static void MtSync_StopWriting(CMtSync
*p
)
55 UInt32 myNumBlocks
= p
->numProcessedBlocks
;
56 if (!Thread_WasCreated(&p
->thread
) || p
->needStart
)
58 p
->stopWriting
= True
;
61 CriticalSection_Leave(&p
->cs
);
62 p
->csWasEntered
= False
;
64 Semaphore_Release1(&p
->freeSemaphore
);
66 Event_Wait(&p
->wasStopped
);
68 while (myNumBlocks
++ != p
->numProcessedBlocks
)
70 Semaphore_Wait(&p
->filledSemaphore
);
71 Semaphore_Release1(&p
->freeSemaphore
);
76 static void MtSync_Destruct(CMtSync
*p
)
78 if (Thread_WasCreated(&p
->thread
))
80 MtSync_StopWriting(p
);
83 Event_Set(&p
->canStart
);
84 Thread_Wait(&p
->thread
);
85 Thread_Close(&p
->thread
);
87 if (p
->csWasInitialized
)
89 CriticalSection_Delete(&p
->cs
);
90 p
->csWasInitialized
= False
;
93 Event_Close(&p
->canStart
);
94 Event_Close(&p
->wasStarted
);
95 Event_Close(&p
->wasStopped
);
96 Semaphore_Close(&p
->freeSemaphore
);
97 Semaphore_Close(&p
->filledSemaphore
);
99 p
->wasCreated
= False
;
102 #define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; }
104 static SRes
MtSync_Create2(CMtSync
*p
, THREAD_FUNC_TYPE startAddress
, void *obj
, UInt32 numBlocks
)
109 RINOK_THREAD(CriticalSection_Init(&p
->cs
));
110 p
->csWasInitialized
= True
;
112 RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p
->canStart
));
113 RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p
->wasStarted
));
114 RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p
->wasStopped
));
116 RINOK_THREAD(Semaphore_Create(&p
->freeSemaphore
, numBlocks
, numBlocks
));
117 RINOK_THREAD(Semaphore_Create(&p
->filledSemaphore
, 0, numBlocks
));
121 RINOK_THREAD(Thread_Create(&p
->thread
, startAddress
, obj
));
122 p
->wasCreated
= True
;
126 static SRes
MtSync_Create(CMtSync
*p
, THREAD_FUNC_TYPE startAddress
, void *obj
, UInt32 numBlocks
)
128 SRes res
= MtSync_Create2(p
, startAddress
, obj
, numBlocks
);
134 void MtSync_Init(CMtSync
*p
) { p
->needStart
= True
; }
136 #define kMtMaxValForNormalize 0xFFFFFFFF
138 #define DEF_GetHeads2(name, v, action) \
139 static void GetHeads ## name(const Byte *p, UInt32 pos, \
140 UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \
141 { action; for (; numHeads != 0; numHeads--) { \
142 const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } }
144 #define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;)
146 DEF_GetHeads2(2, (p
[0] | ((UInt32
)p
[1] << 8)), UNUSED_VAR(hashMask
); UNUSED_VAR(crc
); )
147 DEF_GetHeads(3, (crc
[p
[0]] ^ p
[1] ^ ((UInt32
)p
[2] << 8)) & hashMask
)
148 DEF_GetHeads(4, (crc
[p
[0]] ^ p
[1] ^ ((UInt32
)p
[2] << 8) ^ (crc
[p
[3]] << 5)) & hashMask
)
149 DEF_GetHeads(4b
, (crc
[p
[0]] ^ p
[1] ^ ((UInt32
)p
[2] << 8) ^ ((UInt32
)p
[3] << 16)) & hashMask
)
150 /* DEF_GetHeads(5, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */
152 static void HashThreadFunc(CMatchFinderMt
*mt
)
154 CMtSync
*p
= &mt
->hashSync
;
157 UInt32 numProcessedBlocks
= 0;
158 Event_Wait(&p
->canStart
);
159 Event_Set(&p
->wasStarted
);
161 MatchFinder_Init_HighHash(mt
->MatchFinder
);
169 p
->numProcessedBlocks
= numProcessedBlocks
;
170 Event_Set(&p
->wasStopped
);
175 CMatchFinder
*mf
= mt
->MatchFinder
;
176 if (MatchFinder_NeedMove(mf
))
178 CriticalSection_Enter(&mt
->btSync
.cs
);
179 CriticalSection_Enter(&mt
->hashSync
.cs
);
181 const Byte
*beforePtr
= Inline_MatchFinder_GetPointerToCurrentPos(mf
);
183 MatchFinder_MoveBlock(mf
);
184 offset
= beforePtr
- Inline_MatchFinder_GetPointerToCurrentPos(mf
);
185 mt
->pointerToCurPos
-= offset
;
186 mt
->buffer
-= offset
;
188 CriticalSection_Leave(&mt
->btSync
.cs
);
189 CriticalSection_Leave(&mt
->hashSync
.cs
);
193 Semaphore_Wait(&p
->freeSemaphore
);
195 MatchFinder_ReadIfRequired(mf
);
196 if (mf
->pos
> (kMtMaxValForNormalize
- kMtHashBlockSize
))
198 UInt32 subValue
= (mf
->pos
- mf
->historySize
- 1);
199 MatchFinder_ReduceOffsets(mf
, subValue
);
200 MatchFinder_Normalize3(subValue
, mf
->hash
+ mf
->fixedHashSize
, (size_t)mf
->hashMask
+ 1);
203 UInt32
*heads
= mt
->hashBuf
+ ((numProcessedBlocks
++) & kMtHashNumBlocksMask
) * kMtHashBlockSize
;
204 UInt32 num
= mf
->streamPos
- mf
->pos
;
207 if (num
>= mf
->numHashBytes
)
209 num
= num
- mf
->numHashBytes
+ 1;
210 if (num
> kMtHashBlockSize
- 2)
211 num
= kMtHashBlockSize
- 2;
212 mt
->GetHeadsFunc(mf
->buffer
, mf
->pos
, mf
->hash
+ mf
->fixedHashSize
, mf
->hashMask
, heads
+ 2, num
, mf
->crc
);
220 Semaphore_Release1(&p
->filledSemaphore
);
225 static void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt
*p
)
227 MtSync_GetNextBlock(&p
->hashSync
);
228 p
->hashBufPosLimit
= p
->hashBufPos
= ((p
->hashSync
.numProcessedBlocks
- 1) & kMtHashNumBlocksMask
) * kMtHashBlockSize
;
229 p
->hashBufPosLimit
+= p
->hashBuf
[p
->hashBufPos
++];
230 p
->hashNumAvail
= p
->hashBuf
[p
->hashBufPos
++];
233 #define kEmptyHashValue 0
235 #define MFMT_GM_INLINE
237 #ifdef MFMT_GM_INLINE
240 we use size_t for _cyclicBufferPos instead of UInt32
241 to eliminate "movsx" BUG in old MSVC x64 compiler.
245 static UInt32
*GetMatchesSpecN(UInt32 lenLimit
, UInt32 pos
, const Byte
*cur
, CLzRef
*son
,
246 size_t _cyclicBufferPos
, UInt32 _cyclicBufferSize
, UInt32 _cutValue
,
247 UInt32
*distances
, UInt32 _maxLen
, const UInt32
*hash
, const UInt32
*limit
, UInt32 size
, UInt32
*posRes
)
251 UInt32
*_distances
= ++distances
;
252 UInt32 delta
= *hash
++;
254 CLzRef
*ptr0
= son
+ ((size_t)_cyclicBufferPos
<< 1) + 1;
255 CLzRef
*ptr1
= son
+ ((size_t)_cyclicBufferPos
<< 1);
256 unsigned len0
= 0, len1
= 0;
257 UInt32 cutValue
= _cutValue
;
258 unsigned maxLen
= (unsigned)_maxLen
;
263 UInt32 delta = *hash;
264 if (delta < _cyclicBufferSize)
266 UInt32 cyc1 = _cyclicBufferPos + 1;
267 CLzRef *pair = son + ((size_t)(cyc1 - delta + ((delta > cyc1) ? _cyclicBufferSize : 0)) << 1);
268 Byte b = *(cur + 1 - delta);
269 _distances[0] = pair[0];
274 if (cutValue
== 0 || delta
>= _cyclicBufferSize
)
276 *ptr0
= *ptr1
= kEmptyHashValue
;
282 CLzRef
*pair
= son
+ ((size_t)(_cyclicBufferPos
- delta
+ ((_cyclicBufferPos
< delta
) ? _cyclicBufferSize
: 0)) << 1);
283 const Byte
*pb
= cur
- delta
;
284 unsigned len
= (len0
< len1
? len0
: len1
);
285 UInt32 pair0
= *pair
;
286 if (pb
[len
] == cur
[len
])
288 if (++len
!= lenLimit
&& pb
[len
] == cur
[len
])
289 while (++len
!= lenLimit
)
290 if (pb
[len
] != cur
[len
])
295 *distances
++ = (UInt32
)len
;
296 *distances
++ = delta
- 1;
299 UInt32 pair1
= pair
[1];
307 UInt32 curMatch
= pos
- delta
;
308 // delta = pos - *pair;
309 // delta = pos - pair[((UInt32)pb[len] - (UInt32)cur[len]) >> 31];
310 if (pb
[len
] < cur
[len
])
312 delta
= pos
- pair
[1];
326 if (--cutValue
== 0 || delta
>= _cyclicBufferSize
)
328 *ptr0
= *ptr1
= kEmptyHashValue
;
336 UInt32 num
= (UInt32
)(distances
- _distances
);
337 _distances
[-1] = num
;
340 while (distances
< limit
&& --size
!= 0);
349 static void BtGetMatches(CMatchFinderMt
*p
, UInt32
*distances
)
351 UInt32 numProcessed
= 0;
353 UInt32 limit
= kMtBtBlockSize
- (p
->matchMaxLen
* 2); // * 2
355 distances
[1] = p
->hashNumAvail
;
357 while (curPos
< limit
)
359 if (p
->hashBufPos
== p
->hashBufPosLimit
)
361 MatchFinderMt_GetNextBlock_Hash(p
);
362 distances
[1] = numProcessed
+ p
->hashNumAvail
;
363 if (p
->hashNumAvail
>= p
->numHashBytes
)
365 distances
[0] = curPos
+ p
->hashNumAvail
;
367 for (; p
->hashNumAvail
!= 0; p
->hashNumAvail
--)
372 UInt32 size
= p
->hashBufPosLimit
- p
->hashBufPos
;
373 UInt32 lenLimit
= p
->matchMaxLen
;
375 UInt32 cyclicBufferPos
= p
->cyclicBufferPos
;
376 if (lenLimit
>= p
->hashNumAvail
)
377 lenLimit
= p
->hashNumAvail
;
379 UInt32 size2
= p
->hashNumAvail
- lenLimit
+ 1;
382 size2
= p
->cyclicBufferSize
- cyclicBufferPos
;
387 #ifndef MFMT_GM_INLINE
388 while (curPos
< limit
&& size
-- != 0)
390 UInt32
*startDistances
= distances
+ curPos
;
391 UInt32 num
= (UInt32
)(GetMatchesSpec1(lenLimit
, pos
- p
->hashBuf
[p
->hashBufPos
++],
392 pos
, p
->buffer
, p
->son
, cyclicBufferPos
, p
->cyclicBufferSize
, p
->cutValue
,
393 startDistances
+ 1, p
->numHashBytes
- 1) - startDistances
);
394 *startDistances
= num
- 1;
403 curPos
= (UInt32
)(GetMatchesSpecN(lenLimit
, pos
, p
->buffer
, p
->son
, cyclicBufferPos
, p
->cyclicBufferSize
, p
->cutValue
,
404 distances
+ curPos
, p
->numHashBytes
- 1, p
->hashBuf
+ p
->hashBufPos
,
406 size
, &posRes
) - distances
);
407 p
->hashBufPos
+= posRes
- pos
;
408 cyclicBufferPos
+= posRes
- pos
;
409 p
->buffer
+= posRes
- pos
;
414 numProcessed
+= pos
- p
->pos
;
415 p
->hashNumAvail
-= pos
- p
->pos
;
417 if (cyclicBufferPos
== p
->cyclicBufferSize
)
419 p
->cyclicBufferPos
= cyclicBufferPos
;
423 distances
[0] = curPos
;
426 static void BtFillBlock(CMatchFinderMt
*p
, UInt32 globalBlockIndex
)
428 CMtSync
*sync
= &p
->hashSync
;
429 if (!sync
->needStart
)
431 CriticalSection_Enter(&sync
->cs
);
432 sync
->csWasEntered
= True
;
435 BtGetMatches(p
, p
->btBuf
+ (globalBlockIndex
& kMtBtNumBlocksMask
) * kMtBtBlockSize
);
437 if (p
->pos
> kMtMaxValForNormalize
- kMtBtBlockSize
)
439 UInt32 subValue
= p
->pos
- p
->cyclicBufferSize
;
440 MatchFinder_Normalize3(subValue
, p
->son
, (size_t)p
->cyclicBufferSize
* 2);
444 if (!sync
->needStart
)
446 CriticalSection_Leave(&sync
->cs
);
447 sync
->csWasEntered
= False
;
451 void BtThreadFunc(CMatchFinderMt
*mt
)
453 CMtSync
*p
= &mt
->btSync
;
456 UInt32 blockIndex
= 0;
457 Event_Wait(&p
->canStart
);
458 Event_Set(&p
->wasStarted
);
465 p
->numProcessedBlocks
= blockIndex
;
466 MtSync_StopWriting(&mt
->hashSync
);
467 Event_Set(&p
->wasStopped
);
470 Semaphore_Wait(&p
->freeSemaphore
);
471 BtFillBlock(mt
, blockIndex
++);
472 Semaphore_Release1(&p
->filledSemaphore
);
477 void MatchFinderMt_Construct(CMatchFinderMt
*p
)
480 MtSync_Construct(&p
->hashSync
);
481 MtSync_Construct(&p
->btSync
);
484 static void MatchFinderMt_FreeMem(CMatchFinderMt
*p
, ISzAllocPtr alloc
)
486 ISzAlloc_Free(alloc
, p
->hashBuf
);
490 void MatchFinderMt_Destruct(CMatchFinderMt
*p
, ISzAllocPtr alloc
)
492 MtSync_Destruct(&p
->hashSync
);
493 MtSync_Destruct(&p
->btSync
);
494 MatchFinderMt_FreeMem(p
, alloc
);
497 #define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks)
498 #define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks)
500 static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE
HashThreadFunc2(void *p
) { HashThreadFunc((CMatchFinderMt
*)p
); return 0; }
501 static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE
BtThreadFunc2(void *p
)
503 Byte allocaDummy
[0x180];
505 for (i
= 0; i
< 16; i
++)
506 allocaDummy
[i
] = (Byte
)0;
507 if (allocaDummy
[0] == 0)
508 BtThreadFunc((CMatchFinderMt
*)p
);
512 SRes
MatchFinderMt_Create(CMatchFinderMt
*p
, UInt32 historySize
, UInt32 keepAddBufferBefore
,
513 UInt32 matchMaxLen
, UInt32 keepAddBufferAfter
, ISzAllocPtr alloc
)
515 CMatchFinder
*mf
= p
->MatchFinder
;
516 p
->historySize
= historySize
;
517 if (kMtBtBlockSize
<= matchMaxLen
* 4)
518 return SZ_ERROR_PARAM
;
521 p
->hashBuf
= (UInt32
*)ISzAlloc_Alloc(alloc
, (kHashBufferSize
+ kBtBufferSize
) * sizeof(UInt32
));
524 p
->btBuf
= p
->hashBuf
+ kHashBufferSize
;
526 keepAddBufferBefore
+= (kHashBufferSize
+ kBtBufferSize
);
527 keepAddBufferAfter
+= kMtHashBlockSize
;
528 if (!MatchFinder_Create(mf
, historySize
, keepAddBufferBefore
, matchMaxLen
, keepAddBufferAfter
, alloc
))
531 RINOK(MtSync_Create(&p
->hashSync
, HashThreadFunc2
, p
, kMtHashNumBlocks
));
532 RINOK(MtSync_Create(&p
->btSync
, BtThreadFunc2
, p
, kMtBtNumBlocks
));
536 /* Call it after ReleaseStream / SetStream */
537 static void MatchFinderMt_Init(CMatchFinderMt
*p
)
539 CMatchFinder
*mf
= p
->MatchFinder
;
542 p
->btBufPosLimit
= 0;
544 p
->hashBufPosLimit
= 0;
546 /* Init without data reading. We don't want to read data in this thread */
547 MatchFinder_Init_3(mf
, False
);
548 MatchFinder_Init_LowHash(mf
);
550 p
->pointerToCurPos
= Inline_MatchFinder_GetPointerToCurrentPos(mf
);
551 p
->btNumAvailBytes
= 0;
552 p
->lzPos
= p
->historySize
+ 1;
555 p
->fixedHashSize
= mf
->fixedHashSize
;
559 p
->matchMaxLen
= mf
->matchMaxLen
;
560 p
->numHashBytes
= mf
->numHashBytes
;
562 p
->buffer
= mf
->buffer
;
563 p
->cyclicBufferPos
= mf
->cyclicBufferPos
;
564 p
->cyclicBufferSize
= mf
->cyclicBufferSize
;
565 p
->cutValue
= mf
->cutValue
;
568 /* ReleaseStream is required to finish multithreading */
569 void MatchFinderMt_ReleaseStream(CMatchFinderMt
*p
)
571 MtSync_StopWriting(&p
->btSync
);
572 /* p->MatchFinder->ReleaseStream(); */
575 static void MatchFinderMt_Normalize(CMatchFinderMt
*p
)
577 MatchFinder_Normalize3(p
->lzPos
- p
->historySize
- 1, p
->hash
, p
->fixedHashSize
);
578 p
->lzPos
= p
->historySize
+ 1;
581 static void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt
*p
)
584 MtSync_GetNextBlock(&p
->btSync
);
585 blockIndex
= ((p
->btSync
.numProcessedBlocks
- 1) & kMtBtNumBlocksMask
);
586 p
->btBufPosLimit
= p
->btBufPos
= blockIndex
* kMtBtBlockSize
;
587 p
->btBufPosLimit
+= p
->btBuf
[p
->btBufPos
++];
588 p
->btNumAvailBytes
= p
->btBuf
[p
->btBufPos
++];
589 if (p
->lzPos
>= kMtMaxValForNormalize
- kMtBtBlockSize
)
590 MatchFinderMt_Normalize(p
);
593 static const Byte
* MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt
*p
)
595 return p
->pointerToCurPos
;
598 #define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p);
600 static UInt32
MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt
*p
)
602 GET_NEXT_BLOCK_IF_REQUIRED
;
603 return p
->btNumAvailBytes
;
606 static UInt32
* MixMatches2(CMatchFinderMt
*p
, UInt32 matchMinPos
, UInt32
*distances
)
608 UInt32 h2
, curMatch2
;
609 UInt32
*hash
= p
->hash
;
610 const Byte
*cur
= p
->pointerToCurPos
;
611 UInt32 lzPos
= p
->lzPos
;
614 curMatch2
= hash
[h2
];
617 if (curMatch2
>= matchMinPos
)
618 if (cur
[(ptrdiff_t)curMatch2
- lzPos
] == cur
[0])
621 *distances
++ = lzPos
- curMatch2
- 1;
627 static UInt32
* MixMatches3(CMatchFinderMt
*p
, UInt32 matchMinPos
, UInt32
*distances
)
629 UInt32 h2
, h3
, curMatch2
, curMatch3
;
630 UInt32
*hash
= p
->hash
;
631 const Byte
*cur
= p
->pointerToCurPos
;
632 UInt32 lzPos
= p
->lzPos
;
635 curMatch2
= hash
[ h2
];
636 curMatch3
= (hash
+ kFix3HashSize
)[h3
];
639 (hash
+ kFix3HashSize
)[h3
] = lzPos
;
641 if (curMatch2
>= matchMinPos
&& cur
[(ptrdiff_t)curMatch2
- lzPos
] == cur
[0])
643 distances
[1] = lzPos
- curMatch2
- 1;
644 if (cur
[(ptrdiff_t)curMatch2
- lzPos
+ 2] == cur
[2])
647 return distances
+ 2;
653 if (curMatch3
>= matchMinPos
&& cur
[(ptrdiff_t)curMatch3
- lzPos
] == cur
[0])
656 *distances
++ = lzPos
- curMatch3
- 1;
663 static UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
665 UInt32 h2, h3, h4, curMatch2, curMatch3, curMatch4;
666 UInt32 *hash = p->hash;
667 const Byte *cur = p->pointerToCurPos;
668 UInt32 lzPos = p->lzPos;
671 curMatch2 = hash[ h2];
672 curMatch3 = (hash + kFix3HashSize)[h3];
673 curMatch4 = (hash + kFix4HashSize)[h4];
676 (hash + kFix3HashSize)[h3] = lzPos;
677 (hash + kFix4HashSize)[h4] = lzPos;
679 if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
681 distances[1] = lzPos - curMatch2 - 1;
682 if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
684 distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3;
685 return distances + 2;
691 if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
693 distances[1] = lzPos - curMatch3 - 1;
694 if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3])
697 return distances + 2;
703 if (curMatch4 >= matchMinPos)
705 cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] &&
706 cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3]
710 *distances++ = lzPos - curMatch4 - 1;
717 #define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++;
719 static UInt32
MatchFinderMt2_GetMatches(CMatchFinderMt
*p
, UInt32
*distances
)
721 const UInt32
*btBuf
= p
->btBuf
+ p
->btBufPos
;
722 UInt32 len
= *btBuf
++;
723 p
->btBufPos
+= 1 + len
;
724 p
->btNumAvailBytes
--;
727 for (i
= 0; i
< len
; i
+= 2)
729 UInt32 v0
= btBuf
[0];
730 UInt32 v1
= btBuf
[1];
741 static UInt32
MatchFinderMt_GetMatches(CMatchFinderMt
*p
, UInt32
*distances
)
743 const UInt32
*btBuf
= p
->btBuf
+ p
->btBufPos
;
744 UInt32 len
= *btBuf
++;
745 p
->btBufPos
+= 1 + len
;
749 /* change for bt5 ! */
750 if (p
->btNumAvailBytes
-- >= 4)
751 len
= (UInt32
)(p
->MixMatchesFunc(p
, p
->lzPos
- p
->historySize
, distances
) - (distances
));
755 /* Condition: there are matches in btBuf with length < p->numHashBytes */
757 p
->btNumAvailBytes
--;
758 distances2
= p
->MixMatchesFunc(p
, p
->lzPos
- btBuf
[1], distances
);
761 UInt32 v0
= btBuf
[0];
762 UInt32 v1
= btBuf
[1];
768 while ((len
-= 2) != 0);
769 len
= (UInt32
)(distances2
- (distances
));
775 #define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED
776 #define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash;
777 #define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while (--num != 0);
779 static void MatchFinderMt0_Skip(CMatchFinderMt
*p
, UInt32 num
)
781 SKIP_HEADER2_MT
{ p
->btNumAvailBytes
--;
785 static void MatchFinderMt2_Skip(CMatchFinderMt
*p
, UInt32 num
)
794 static void MatchFinderMt3_Skip(CMatchFinderMt
*p
, UInt32 num
)
799 (hash
+ kFix3HashSize
)[h3
] =
806 static void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num)
811 (hash + kFix4HashSize)[h4] =
812 (hash + kFix3HashSize)[h3] =
819 void MatchFinderMt_CreateVTable(CMatchFinderMt
*p
, IMatchFinder
*vTable
)
821 vTable
->Init
= (Mf_Init_Func
)MatchFinderMt_Init
;
822 vTable
->GetNumAvailableBytes
= (Mf_GetNumAvailableBytes_Func
)MatchFinderMt_GetNumAvailableBytes
;
823 vTable
->GetPointerToCurrentPos
= (Mf_GetPointerToCurrentPos_Func
)MatchFinderMt_GetPointerToCurrentPos
;
824 vTable
->GetMatches
= (Mf_GetMatches_Func
)MatchFinderMt_GetMatches
;
826 switch (p
->MatchFinder
->numHashBytes
)
829 p
->GetHeadsFunc
= GetHeads2
;
830 p
->MixMatchesFunc
= (Mf_Mix_Matches
)NULL
;
831 vTable
->Skip
= (Mf_Skip_Func
)MatchFinderMt0_Skip
;
832 vTable
->GetMatches
= (Mf_GetMatches_Func
)MatchFinderMt2_GetMatches
;
835 p
->GetHeadsFunc
= GetHeads3
;
836 p
->MixMatchesFunc
= (Mf_Mix_Matches
)MixMatches2
;
837 vTable
->Skip
= (Mf_Skip_Func
)MatchFinderMt2_Skip
;
841 p
->GetHeadsFunc
= p
->MatchFinder
->bigHash
? GetHeads4b
: GetHeads4
;
842 p
->MixMatchesFunc
= (Mf_Mix_Matches
)MixMatches3
;
843 vTable
->Skip
= (Mf_Skip_Func
)MatchFinderMt3_Skip
;
847 p->GetHeadsFunc = GetHeads5;
848 p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4;
849 vTable->Skip = (Mf_Skip_Func)MatchFinderMt4_Skip;