1 /* LzFindMt.c -- multithreaded Match finder for LZ algorithms
2 2015-10-15 : 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
);
39 CriticalSection_Leave(&p
->cs
);
40 p
->csWasEntered
= False
;
41 p
->numProcessedBlocks
++;
42 Semaphore_Release1(&p
->freeSemaphore
);
44 Semaphore_Wait(&p
->filledSemaphore
);
45 CriticalSection_Enter(&p
->cs
);
46 p
->csWasEntered
= True
;
49 /* MtSync_StopWriting must be called if Writing was started */
51 static void MtSync_StopWriting(CMtSync
*p
)
53 UInt32 myNumBlocks
= p
->numProcessedBlocks
;
54 if (!Thread_WasCreated(&p
->thread
) || p
->needStart
)
56 p
->stopWriting
= True
;
59 CriticalSection_Leave(&p
->cs
);
60 p
->csWasEntered
= False
;
62 Semaphore_Release1(&p
->freeSemaphore
);
64 Event_Wait(&p
->wasStopped
);
66 while (myNumBlocks
++ != p
->numProcessedBlocks
)
68 Semaphore_Wait(&p
->filledSemaphore
);
69 Semaphore_Release1(&p
->freeSemaphore
);
74 static void MtSync_Destruct(CMtSync
*p
)
76 if (Thread_WasCreated(&p
->thread
))
78 MtSync_StopWriting(p
);
81 Event_Set(&p
->canStart
);
82 Thread_Wait(&p
->thread
);
83 Thread_Close(&p
->thread
);
85 if (p
->csWasInitialized
)
87 CriticalSection_Delete(&p
->cs
);
88 p
->csWasInitialized
= False
;
91 Event_Close(&p
->canStart
);
92 Event_Close(&p
->wasStarted
);
93 Event_Close(&p
->wasStopped
);
94 Semaphore_Close(&p
->freeSemaphore
);
95 Semaphore_Close(&p
->filledSemaphore
);
97 p
->wasCreated
= False
;
100 #define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; }
102 static SRes
MtSync_Create2(CMtSync
*p
, THREAD_FUNC_TYPE startAddress
, void *obj
, UInt32 numBlocks
)
107 RINOK_THREAD(CriticalSection_Init(&p
->cs
));
108 p
->csWasInitialized
= True
;
110 RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p
->canStart
));
111 RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p
->wasStarted
));
112 RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p
->wasStopped
));
114 RINOK_THREAD(Semaphore_Create(&p
->freeSemaphore
, numBlocks
, numBlocks
));
115 RINOK_THREAD(Semaphore_Create(&p
->filledSemaphore
, 0, numBlocks
));
119 RINOK_THREAD(Thread_Create(&p
->thread
, startAddress
, obj
));
120 p
->wasCreated
= True
;
124 static SRes
MtSync_Create(CMtSync
*p
, THREAD_FUNC_TYPE startAddress
, void *obj
, UInt32 numBlocks
)
126 SRes res
= MtSync_Create2(p
, startAddress
, obj
, numBlocks
);
132 void MtSync_Init(CMtSync
*p
) { p
->needStart
= True
; }
134 #define kMtMaxValForNormalize 0xFFFFFFFF
136 #define DEF_GetHeads2(name, v, action) \
137 static void GetHeads ## name(const Byte *p, UInt32 pos, \
138 UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \
139 { action; for (; numHeads != 0; numHeads--) { \
140 const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } }
142 #define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;)
144 DEF_GetHeads2(2, (p
[0] | ((UInt32
)p
[1] << 8)), UNUSED_VAR(hashMask
); UNUSED_VAR(crc
); )
145 DEF_GetHeads(3, (crc
[p
[0]] ^ p
[1] ^ ((UInt32
)p
[2] << 8)) & hashMask
)
146 DEF_GetHeads(4, (crc
[p
[0]] ^ p
[1] ^ ((UInt32
)p
[2] << 8) ^ (crc
[p
[3]] << 5)) & hashMask
)
147 DEF_GetHeads(4b
, (crc
[p
[0]] ^ p
[1] ^ ((UInt32
)p
[2] << 8) ^ ((UInt32
)p
[3] << 16)) & hashMask
)
148 /* DEF_GetHeads(5, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */
150 static void HashThreadFunc(CMatchFinderMt
*mt
)
152 CMtSync
*p
= &mt
->hashSync
;
155 UInt32 numProcessedBlocks
= 0;
156 Event_Wait(&p
->canStart
);
157 Event_Set(&p
->wasStarted
);
164 p
->numProcessedBlocks
= numProcessedBlocks
;
165 Event_Set(&p
->wasStopped
);
170 CMatchFinder
*mf
= mt
->MatchFinder
;
171 if (MatchFinder_NeedMove(mf
))
173 CriticalSection_Enter(&mt
->btSync
.cs
);
174 CriticalSection_Enter(&mt
->hashSync
.cs
);
176 const Byte
*beforePtr
= Inline_MatchFinder_GetPointerToCurrentPos(mf
);
178 MatchFinder_MoveBlock(mf
);
179 offset
= beforePtr
- Inline_MatchFinder_GetPointerToCurrentPos(mf
);
180 mt
->pointerToCurPos
-= offset
;
181 mt
->buffer
-= offset
;
183 CriticalSection_Leave(&mt
->btSync
.cs
);
184 CriticalSection_Leave(&mt
->hashSync
.cs
);
188 Semaphore_Wait(&p
->freeSemaphore
);
190 MatchFinder_ReadIfRequired(mf
);
191 if (mf
->pos
> (kMtMaxValForNormalize
- kMtHashBlockSize
))
193 UInt32 subValue
= (mf
->pos
- mf
->historySize
- 1);
194 MatchFinder_ReduceOffsets(mf
, subValue
);
195 MatchFinder_Normalize3(subValue
, mf
->hash
+ mf
->fixedHashSize
, (size_t)mf
->hashMask
+ 1);
198 UInt32
*heads
= mt
->hashBuf
+ ((numProcessedBlocks
++) & kMtHashNumBlocksMask
) * kMtHashBlockSize
;
199 UInt32 num
= mf
->streamPos
- mf
->pos
;
202 if (num
>= mf
->numHashBytes
)
204 num
= num
- mf
->numHashBytes
+ 1;
205 if (num
> kMtHashBlockSize
- 2)
206 num
= kMtHashBlockSize
- 2;
207 mt
->GetHeadsFunc(mf
->buffer
, mf
->pos
, mf
->hash
+ mf
->fixedHashSize
, mf
->hashMask
, heads
+ 2, num
, mf
->crc
);
215 Semaphore_Release1(&p
->filledSemaphore
);
220 static void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt
*p
)
222 MtSync_GetNextBlock(&p
->hashSync
);
223 p
->hashBufPosLimit
= p
->hashBufPos
= ((p
->hashSync
.numProcessedBlocks
- 1) & kMtHashNumBlocksMask
) * kMtHashBlockSize
;
224 p
->hashBufPosLimit
+= p
->hashBuf
[p
->hashBufPos
++];
225 p
->hashNumAvail
= p
->hashBuf
[p
->hashBufPos
++];
228 #define kEmptyHashValue 0
230 /* #define MFMT_GM_INLINE */
232 #ifdef MFMT_GM_INLINE
234 #define NO_INLINE MY_FAST_CALL
236 static Int32 NO_INLINE
GetMatchesSpecN(UInt32 lenLimit
, UInt32 pos
, const Byte
*cur
, CLzRef
*son
,
237 UInt32 _cyclicBufferPos
, UInt32 _cyclicBufferSize
, UInt32 _cutValue
,
238 UInt32
*_distances
, UInt32 _maxLen
, const UInt32
*hash
, Int32 limit
, UInt32 size
, UInt32
*posRes
)
242 UInt32
*distances
= _distances
+ 1;
243 UInt32 curMatch
= pos
- *hash
++;
245 CLzRef
*ptr0
= son
+ (_cyclicBufferPos
<< 1) + 1;
246 CLzRef
*ptr1
= son
+ (_cyclicBufferPos
<< 1);
247 UInt32 len0
= 0, len1
= 0;
248 UInt32 cutValue
= _cutValue
;
249 UInt32 maxLen
= _maxLen
;
252 UInt32 delta
= pos
- curMatch
;
253 if (cutValue
-- == 0 || delta
>= _cyclicBufferSize
)
255 *ptr0
= *ptr1
= kEmptyHashValue
;
259 CLzRef
*pair
= son
+ ((_cyclicBufferPos
- delta
+ ((delta
> _cyclicBufferPos
) ? _cyclicBufferSize
: 0)) << 1);
260 const Byte
*pb
= cur
- delta
;
261 UInt32 len
= (len0
< len1
? len0
: len1
);
262 if (pb
[len
] == cur
[len
])
264 if (++len
!= lenLimit
&& pb
[len
] == cur
[len
])
265 while (++len
!= lenLimit
)
266 if (pb
[len
] != cur
[len
])
270 *distances
++ = maxLen
= len
;
271 *distances
++ = delta
- 1;
280 if (pb
[len
] < cur
[len
])
300 UInt32 num
= (UInt32
)(distances
- _distances
);
301 *_distances
= num
- 1;
306 while (limit
> 0 && --size
!= 0);
313 static void BtGetMatches(CMatchFinderMt
*p
, UInt32
*distances
)
315 UInt32 numProcessed
= 0;
317 UInt32 limit
= kMtBtBlockSize
- (p
->matchMaxLen
* 2);
319 distances
[1] = p
->hashNumAvail
;
321 while (curPos
< limit
)
323 if (p
->hashBufPos
== p
->hashBufPosLimit
)
325 MatchFinderMt_GetNextBlock_Hash(p
);
326 distances
[1] = numProcessed
+ p
->hashNumAvail
;
327 if (p
->hashNumAvail
>= p
->numHashBytes
)
329 distances
[0] = curPos
+ p
->hashNumAvail
;
331 for (; p
->hashNumAvail
!= 0; p
->hashNumAvail
--)
336 UInt32 size
= p
->hashBufPosLimit
- p
->hashBufPos
;
337 UInt32 lenLimit
= p
->matchMaxLen
;
339 UInt32 cyclicBufferPos
= p
->cyclicBufferPos
;
340 if (lenLimit
>= p
->hashNumAvail
)
341 lenLimit
= p
->hashNumAvail
;
343 UInt32 size2
= p
->hashNumAvail
- lenLimit
+ 1;
346 size2
= p
->cyclicBufferSize
- cyclicBufferPos
;
351 #ifndef MFMT_GM_INLINE
352 while (curPos
< limit
&& size
-- != 0)
354 UInt32
*startDistances
= distances
+ curPos
;
355 UInt32 num
= (UInt32
)(GetMatchesSpec1(lenLimit
, pos
- p
->hashBuf
[p
->hashBufPos
++],
356 pos
, p
->buffer
, p
->son
, cyclicBufferPos
, p
->cyclicBufferSize
, p
->cutValue
,
357 startDistances
+ 1, p
->numHashBytes
- 1) - startDistances
);
358 *startDistances
= num
- 1;
367 curPos
= limit
- GetMatchesSpecN(lenLimit
, pos
, p
->buffer
, p
->son
, cyclicBufferPos
, p
->cyclicBufferSize
, p
->cutValue
,
368 distances
+ curPos
, p
->numHashBytes
- 1, p
->hashBuf
+ p
->hashBufPos
, (Int32
)(limit
- curPos
), size
, &posRes
);
369 p
->hashBufPos
+= posRes
- pos
;
370 cyclicBufferPos
+= posRes
- pos
;
371 p
->buffer
+= posRes
- pos
;
376 numProcessed
+= pos
- p
->pos
;
377 p
->hashNumAvail
-= pos
- p
->pos
;
379 if (cyclicBufferPos
== p
->cyclicBufferSize
)
381 p
->cyclicBufferPos
= cyclicBufferPos
;
385 distances
[0] = curPos
;
388 static void BtFillBlock(CMatchFinderMt
*p
, UInt32 globalBlockIndex
)
390 CMtSync
*sync
= &p
->hashSync
;
391 if (!sync
->needStart
)
393 CriticalSection_Enter(&sync
->cs
);
394 sync
->csWasEntered
= True
;
397 BtGetMatches(p
, p
->btBuf
+ (globalBlockIndex
& kMtBtNumBlocksMask
) * kMtBtBlockSize
);
399 if (p
->pos
> kMtMaxValForNormalize
- kMtBtBlockSize
)
401 UInt32 subValue
= p
->pos
- p
->cyclicBufferSize
;
402 MatchFinder_Normalize3(subValue
, p
->son
, (size_t)p
->cyclicBufferSize
* 2);
406 if (!sync
->needStart
)
408 CriticalSection_Leave(&sync
->cs
);
409 sync
->csWasEntered
= False
;
413 void BtThreadFunc(CMatchFinderMt
*mt
)
415 CMtSync
*p
= &mt
->btSync
;
418 UInt32 blockIndex
= 0;
419 Event_Wait(&p
->canStart
);
420 Event_Set(&p
->wasStarted
);
427 p
->numProcessedBlocks
= blockIndex
;
428 MtSync_StopWriting(&mt
->hashSync
);
429 Event_Set(&p
->wasStopped
);
432 Semaphore_Wait(&p
->freeSemaphore
);
433 BtFillBlock(mt
, blockIndex
++);
434 Semaphore_Release1(&p
->filledSemaphore
);
439 void MatchFinderMt_Construct(CMatchFinderMt
*p
)
442 MtSync_Construct(&p
->hashSync
);
443 MtSync_Construct(&p
->btSync
);
446 static void MatchFinderMt_FreeMem(CMatchFinderMt
*p
, ISzAlloc
*alloc
)
448 alloc
->Free(alloc
, p
->hashBuf
);
452 void MatchFinderMt_Destruct(CMatchFinderMt
*p
, ISzAlloc
*alloc
)
454 MtSync_Destruct(&p
->hashSync
);
455 MtSync_Destruct(&p
->btSync
);
456 MatchFinderMt_FreeMem(p
, alloc
);
459 #define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks)
460 #define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks)
462 static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE
HashThreadFunc2(void *p
) { HashThreadFunc((CMatchFinderMt
*)p
); return 0; }
463 static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE
BtThreadFunc2(void *p
)
465 Byte allocaDummy
[0x180];
467 for (i
= 0; i
< 16; i
++)
468 allocaDummy
[i
] = (Byte
)0;
469 if (allocaDummy
[0] == 0)
470 BtThreadFunc((CMatchFinderMt
*)p
);
474 SRes
MatchFinderMt_Create(CMatchFinderMt
*p
, UInt32 historySize
, UInt32 keepAddBufferBefore
,
475 UInt32 matchMaxLen
, UInt32 keepAddBufferAfter
, ISzAlloc
*alloc
)
477 CMatchFinder
*mf
= p
->MatchFinder
;
478 p
->historySize
= historySize
;
479 if (kMtBtBlockSize
<= matchMaxLen
* 4)
480 return SZ_ERROR_PARAM
;
483 p
->hashBuf
= (UInt32
*)alloc
->Alloc(alloc
, (kHashBufferSize
+ kBtBufferSize
) * sizeof(UInt32
));
486 p
->btBuf
= p
->hashBuf
+ kHashBufferSize
;
488 keepAddBufferBefore
+= (kHashBufferSize
+ kBtBufferSize
);
489 keepAddBufferAfter
+= kMtHashBlockSize
;
490 if (!MatchFinder_Create(mf
, historySize
, keepAddBufferBefore
, matchMaxLen
, keepAddBufferAfter
, alloc
))
493 RINOK(MtSync_Create(&p
->hashSync
, HashThreadFunc2
, p
, kMtHashNumBlocks
));
494 RINOK(MtSync_Create(&p
->btSync
, BtThreadFunc2
, p
, kMtBtNumBlocks
));
498 /* Call it after ReleaseStream / SetStream */
499 void MatchFinderMt_Init(CMatchFinderMt
*p
)
501 CMatchFinder
*mf
= p
->MatchFinder
;
502 p
->btBufPos
= p
->btBufPosLimit
= 0;
503 p
->hashBufPos
= p
->hashBufPosLimit
= 0;
505 /* Init without data reading. We don't want to read data in this thread */
506 MatchFinder_Init_2(mf
, False
);
508 p
->pointerToCurPos
= Inline_MatchFinder_GetPointerToCurrentPos(mf
);
509 p
->btNumAvailBytes
= 0;
510 p
->lzPos
= p
->historySize
+ 1;
513 p
->fixedHashSize
= mf
->fixedHashSize
;
517 p
->matchMaxLen
= mf
->matchMaxLen
;
518 p
->numHashBytes
= mf
->numHashBytes
;
520 p
->buffer
= mf
->buffer
;
521 p
->cyclicBufferPos
= mf
->cyclicBufferPos
;
522 p
->cyclicBufferSize
= mf
->cyclicBufferSize
;
523 p
->cutValue
= mf
->cutValue
;
526 /* ReleaseStream is required to finish multithreading */
527 void MatchFinderMt_ReleaseStream(CMatchFinderMt
*p
)
529 MtSync_StopWriting(&p
->btSync
);
530 /* p->MatchFinder->ReleaseStream(); */
533 static void MatchFinderMt_Normalize(CMatchFinderMt
*p
)
535 MatchFinder_Normalize3(p
->lzPos
- p
->historySize
- 1, p
->hash
, p
->fixedHashSize
);
536 p
->lzPos
= p
->historySize
+ 1;
539 static void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt
*p
)
542 MtSync_GetNextBlock(&p
->btSync
);
543 blockIndex
= ((p
->btSync
.numProcessedBlocks
- 1) & kMtBtNumBlocksMask
);
544 p
->btBufPosLimit
= p
->btBufPos
= blockIndex
* kMtBtBlockSize
;
545 p
->btBufPosLimit
+= p
->btBuf
[p
->btBufPos
++];
546 p
->btNumAvailBytes
= p
->btBuf
[p
->btBufPos
++];
547 if (p
->lzPos
>= kMtMaxValForNormalize
- kMtBtBlockSize
)
548 MatchFinderMt_Normalize(p
);
551 static const Byte
* MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt
*p
)
553 return p
->pointerToCurPos
;
556 #define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p);
558 static UInt32
MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt
*p
)
560 GET_NEXT_BLOCK_IF_REQUIRED
;
561 return p
->btNumAvailBytes
;
564 static UInt32
* MixMatches2(CMatchFinderMt
*p
, UInt32 matchMinPos
, UInt32
*distances
)
566 UInt32 h2
, curMatch2
;
567 UInt32
*hash
= p
->hash
;
568 const Byte
*cur
= p
->pointerToCurPos
;
569 UInt32 lzPos
= p
->lzPos
;
572 curMatch2
= hash
[h2
];
575 if (curMatch2
>= matchMinPos
)
576 if (cur
[(ptrdiff_t)curMatch2
- lzPos
] == cur
[0])
579 *distances
++ = lzPos
- curMatch2
- 1;
585 static UInt32
* MixMatches3(CMatchFinderMt
*p
, UInt32 matchMinPos
, UInt32
*distances
)
587 UInt32 h2
, h3
, curMatch2
, curMatch3
;
588 UInt32
*hash
= p
->hash
;
589 const Byte
*cur
= p
->pointerToCurPos
;
590 UInt32 lzPos
= p
->lzPos
;
593 curMatch2
= hash
[ h2
];
594 curMatch3
= hash
[kFix3HashSize
+ h3
];
597 hash
[kFix3HashSize
+ h3
] = lzPos
;
599 if (curMatch2
>= matchMinPos
&& cur
[(ptrdiff_t)curMatch2
- lzPos
] == cur
[0])
601 distances
[1] = lzPos
- curMatch2
- 1;
602 if (cur
[(ptrdiff_t)curMatch2
- lzPos
+ 2] == cur
[2])
605 return distances
+ 2;
611 if (curMatch3
>= matchMinPos
&& cur
[(ptrdiff_t)curMatch3
- lzPos
] == cur
[0])
614 *distances
++ = lzPos
- curMatch3
- 1;
621 static UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
623 UInt32 h2, h3, h4, curMatch2, curMatch3, curMatch4;
624 UInt32 *hash = p->hash;
625 const Byte *cur = p->pointerToCurPos;
626 UInt32 lzPos = p->lzPos;
629 curMatch2 = hash[ h2];
630 curMatch3 = hash[kFix3HashSize + h3];
631 curMatch4 = hash[kFix4HashSize + h4];
634 hash[kFix3HashSize + h3] = lzPos;
635 hash[kFix4HashSize + h4] = lzPos;
637 if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
639 distances[1] = lzPos - curMatch2 - 1;
640 if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
642 distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3;
643 return distances + 2;
649 if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
651 distances[1] = lzPos - curMatch3 - 1;
652 if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3])
655 return distances + 2;
661 if (curMatch4 >= matchMinPos)
663 cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] &&
664 cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3]
668 *distances++ = lzPos - curMatch4 - 1;
675 #define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++;
677 static UInt32
MatchFinderMt2_GetMatches(CMatchFinderMt
*p
, UInt32
*distances
)
679 const UInt32
*btBuf
= p
->btBuf
+ p
->btBufPos
;
680 UInt32 len
= *btBuf
++;
681 p
->btBufPos
+= 1 + len
;
682 p
->btNumAvailBytes
--;
685 for (i
= 0; i
< len
; i
+= 2)
687 *distances
++ = *btBuf
++;
688 *distances
++ = *btBuf
++;
695 static UInt32
MatchFinderMt_GetMatches(CMatchFinderMt
*p
, UInt32
*distances
)
697 const UInt32
*btBuf
= p
->btBuf
+ p
->btBufPos
;
698 UInt32 len
= *btBuf
++;
699 p
->btBufPos
+= 1 + len
;
703 /* change for bt5 ! */
704 if (p
->btNumAvailBytes
-- >= 4)
705 len
= (UInt32
)(p
->MixMatchesFunc(p
, p
->lzPos
- p
->historySize
, distances
) - (distances
));
709 /* Condition: there are matches in btBuf with length < p->numHashBytes */
711 p
->btNumAvailBytes
--;
712 distances2
= p
->MixMatchesFunc(p
, p
->lzPos
- btBuf
[1], distances
);
715 *distances2
++ = *btBuf
++;
716 *distances2
++ = *btBuf
++;
718 while ((len
-= 2) != 0);
719 len
= (UInt32
)(distances2
- (distances
));
725 #define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED
726 #define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash;
727 #define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while (--num != 0);
729 static void MatchFinderMt0_Skip(CMatchFinderMt
*p
, UInt32 num
)
731 SKIP_HEADER2_MT
{ p
->btNumAvailBytes
--;
735 static void MatchFinderMt2_Skip(CMatchFinderMt
*p
, UInt32 num
)
744 static void MatchFinderMt3_Skip(CMatchFinderMt
*p
, UInt32 num
)
749 hash
[kFix3HashSize
+ h3
] =
756 static void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num)
761 hash[kFix4HashSize + h4] =
762 hash[kFix3HashSize + h3] =
769 void MatchFinderMt_CreateVTable(CMatchFinderMt
*p
, IMatchFinder
*vTable
)
771 vTable
->Init
= (Mf_Init_Func
)MatchFinderMt_Init
;
772 vTable
->GetNumAvailableBytes
= (Mf_GetNumAvailableBytes_Func
)MatchFinderMt_GetNumAvailableBytes
;
773 vTable
->GetPointerToCurrentPos
= (Mf_GetPointerToCurrentPos_Func
)MatchFinderMt_GetPointerToCurrentPos
;
774 vTable
->GetMatches
= (Mf_GetMatches_Func
)MatchFinderMt_GetMatches
;
776 switch (p
->MatchFinder
->numHashBytes
)
779 p
->GetHeadsFunc
= GetHeads2
;
780 p
->MixMatchesFunc
= (Mf_Mix_Matches
)0;
781 vTable
->Skip
= (Mf_Skip_Func
)MatchFinderMt0_Skip
;
782 vTable
->GetMatches
= (Mf_GetMatches_Func
)MatchFinderMt2_GetMatches
;
785 p
->GetHeadsFunc
= GetHeads3
;
786 p
->MixMatchesFunc
= (Mf_Mix_Matches
)MixMatches2
;
787 vTable
->Skip
= (Mf_Skip_Func
)MatchFinderMt2_Skip
;
791 p
->GetHeadsFunc
= p
->MatchFinder
->bigHash
? GetHeads4b
: GetHeads4
;
792 p
->MixMatchesFunc
= (Mf_Mix_Matches
)MixMatches3
;
793 vTable
->Skip
= (Mf_Skip_Func
)MatchFinderMt3_Skip
;
797 p->GetHeadsFunc = GetHeads5;
798 p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4;
799 vTable->Skip = (Mf_Skip_Func)MatchFinderMt4_Skip;