misc/libphysfs/lzma/C/Compress/Lz/MatchFinderMt.c
branchui-scaling
changeset 15283 c4fd2813b127
parent 13390 0135e64c6c66
parent 15279 7ab5cf405686
child 15663 d92eeb468dad
equal deleted inserted replaced
13390:0135e64c6c66 15283:c4fd2813b127
     1 /* MatchFinderMt.c */
       
     2 
       
     3 #ifdef _WIN32
       
     4 #define USE_ALLOCA
       
     5 #endif
       
     6 
       
     7 #ifdef USE_ALLOCA
       
     8 #ifdef _WIN32
       
     9 #include <malloc.h>
       
    10 #else
       
    11 #include <stdlib.h>
       
    12 #endif
       
    13 #endif
       
    14 
       
    15 #include "../../7zCrc.h"
       
    16 #include "LzHash.h"
       
    17 
       
    18 #include "MatchFinderMt.h"
       
    19 
       
    20 void MtSync_Construct(CMtSync *p)
       
    21 {
       
    22   p->wasCreated = False;
       
    23   p->csWasInitialized = False;
       
    24   p->csWasEntered = False;
       
    25   Thread_Construct(&p->thread);
       
    26   Event_Construct(&p->canStart);
       
    27   Event_Construct(&p->wasStarted);
       
    28   Event_Construct(&p->wasStopped);
       
    29   Semaphore_Construct(&p->freeSemaphore);
       
    30   Semaphore_Construct(&p->filledSemaphore);
       
    31 }
       
    32 
       
    33 void MtSync_GetNextBlock(CMtSync *p)
       
    34 {
       
    35   if (p->needStart)
       
    36   {
       
    37     p->numProcessedBlocks = 1;
       
    38     p->needStart = False;
       
    39     p->stopWriting = False;
       
    40     p->exit = False;
       
    41     Event_Reset(&p->wasStarted);
       
    42     Event_Reset(&p->wasStopped);
       
    43 
       
    44     Event_Set(&p->canStart);
       
    45     Event_Wait(&p->wasStarted);
       
    46   }
       
    47   else
       
    48   {
       
    49     CriticalSection_Leave(&p->cs);
       
    50     p->csWasEntered = False;
       
    51     p->numProcessedBlocks++;
       
    52     Semaphore_Release1(&p->freeSemaphore);
       
    53   }
       
    54   Semaphore_Wait(&p->filledSemaphore);
       
    55   CriticalSection_Enter(&p->cs);
       
    56   p->csWasEntered = True;
       
    57 }
       
    58 
       
    59 /* MtSync_StopWriting must be called if Writing was started */
       
    60 
       
    61 void MtSync_StopWriting(CMtSync *p)
       
    62 { 
       
    63   UInt32 myNumBlocks = p->numProcessedBlocks;
       
    64   if (!Thread_WasCreated(&p->thread) || p->needStart)
       
    65     return;
       
    66   p->stopWriting = True;
       
    67   if (p->csWasEntered)
       
    68   {
       
    69     CriticalSection_Leave(&p->cs);
       
    70     p->csWasEntered = False;
       
    71   }
       
    72   Semaphore_Release1(&p->freeSemaphore);
       
    73  
       
    74   Event_Wait(&p->wasStopped);
       
    75 
       
    76   while (myNumBlocks++ != p->numProcessedBlocks)
       
    77   {
       
    78     Semaphore_Wait(&p->filledSemaphore);
       
    79     Semaphore_Release1(&p->freeSemaphore);
       
    80   }
       
    81   p->needStart = True;
       
    82 }
       
    83 
       
    84 void MtSync_Destruct(CMtSync *p)
       
    85 {
       
    86   if (Thread_WasCreated(&p->thread))
       
    87   {
       
    88     MtSync_StopWriting(p);
       
    89     p->exit = True;
       
    90     if (p->needStart)
       
    91       Event_Set(&p->canStart);
       
    92     Thread_Wait(&p->thread);
       
    93     Thread_Close(&p->thread);
       
    94   }
       
    95   if (p->csWasInitialized)
       
    96   {
       
    97     CriticalSection_Delete(&p->cs);
       
    98     p->csWasInitialized = False;
       
    99   }
       
   100 
       
   101   Event_Close(&p->canStart);
       
   102   Event_Close(&p->wasStarted);
       
   103   Event_Close(&p->wasStopped);
       
   104   Semaphore_Close(&p->freeSemaphore);
       
   105   Semaphore_Close(&p->filledSemaphore);
       
   106 
       
   107   p->wasCreated = False;
       
   108 }
       
   109 
       
   110 HRes MtSync_Create2(CMtSync *p, unsigned (StdCall *startAddress)(void *), void *obj, UInt32 numBlocks)
       
   111 {
       
   112   if (p->wasCreated)
       
   113     return SZ_OK;
       
   114 
       
   115   RINOK(CriticalSection_Init(&p->cs));
       
   116   p->csWasInitialized = True;
       
   117 
       
   118   RINOK(AutoResetEvent_CreateNotSignaled(&p->canStart));
       
   119   RINOK(AutoResetEvent_CreateNotSignaled(&p->wasStarted));
       
   120   RINOK(AutoResetEvent_CreateNotSignaled(&p->wasStopped));
       
   121   
       
   122   RINOK(Semaphore_Create(&p->freeSemaphore, numBlocks, numBlocks));
       
   123   RINOK(Semaphore_Create(&p->filledSemaphore, 0, numBlocks));
       
   124 
       
   125   p->needStart = True;
       
   126   
       
   127   RINOK(Thread_Create(&p->thread, startAddress, obj));
       
   128   p->wasCreated = True;
       
   129   return SZ_OK;
       
   130 }
       
   131 
       
   132 HRes MtSync_Create(CMtSync *p, unsigned (StdCall *startAddress)(void *), void *obj, UInt32 numBlocks)
       
   133 {
       
   134   HRes res = MtSync_Create2(p, startAddress, obj, numBlocks);
       
   135   if (res != SZ_OK)
       
   136     MtSync_Destruct(p);
       
   137   return res;
       
   138 }
       
   139 
       
   140 
       
   141 void MtSync_Init(CMtSync *p) { p->needStart = True; }
       
   142 
       
   143 #define kMtMaxValForNormalize 0xFFFFFFFF
       
   144 
       
   145 #define DEF_GetHeads(name, v) \
       
   146 static void GetHeads ## name(const Byte *p, UInt32 pos, \
       
   147 UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads) { \
       
   148 for (; numHeads != 0; numHeads--) { \
       
   149 const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++;  } }
       
   150 
       
   151 DEF_GetHeads(2,  (p[0] | ((UInt32)p[1] << 8)) & hashMask)
       
   152 DEF_GetHeads(3,  (g_CrcTable[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask)
       
   153 DEF_GetHeads(4,  (g_CrcTable[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (g_CrcTable[p[3]] << 5)) & hashMask)
       
   154 DEF_GetHeads(4b, (g_CrcTable[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask)
       
   155 DEF_GetHeads(5,  (g_CrcTable[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (g_CrcTable[p[3]] << 5) ^ (g_CrcTable[p[4]] << 3)) & hashMask)
       
   156 
       
   157 void HashThreadFunc(CMatchFinderMt *mt)
       
   158 {
       
   159   CMtSync *p = &mt->hashSync;
       
   160   for (;;)
       
   161   {
       
   162     UInt32 numProcessedBlocks = 0;
       
   163     Event_Wait(&p->canStart);
       
   164     Event_Set(&p->wasStarted);
       
   165     for (;;)
       
   166     {
       
   167       if (p->exit)
       
   168         return;
       
   169       if (p->stopWriting)
       
   170       {
       
   171         p->numProcessedBlocks = numProcessedBlocks;
       
   172         Event_Set(&p->wasStopped);
       
   173         break;
       
   174       }
       
   175 
       
   176       {
       
   177         CMatchFinder *mf = mt->MatchFinder;
       
   178         if (MatchFinder_NeedMove(mf))
       
   179         {
       
   180           CriticalSection_Enter(&mt->btSync.cs);
       
   181           CriticalSection_Enter(&mt->hashSync.cs);
       
   182           {
       
   183             const Byte *beforePtr = MatchFinder_GetPointerToCurrentPos(mf);
       
   184             const Byte *afterPtr;
       
   185             MatchFinder_MoveBlock(mf);
       
   186             afterPtr = MatchFinder_GetPointerToCurrentPos(mf);
       
   187             mt->pointerToCurPos -= beforePtr - afterPtr;
       
   188             mt->buffer -= beforePtr - afterPtr;
       
   189           }
       
   190           CriticalSection_Leave(&mt->btSync.cs);
       
   191           CriticalSection_Leave(&mt->hashSync.cs);
       
   192           continue;
       
   193         }
       
   194 
       
   195         Semaphore_Wait(&p->freeSemaphore);
       
   196 
       
   197         MatchFinder_ReadIfRequired(mf);
       
   198         if (mf->pos > (kMtMaxValForNormalize - kMtHashBlockSize))
       
   199         {
       
   200           UInt32 subValue = (mf->pos - mf->historySize - 1);
       
   201           MatchFinder_ReduceOffsets(mf, subValue);
       
   202           MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, mf->hashMask + 1);
       
   203         }
       
   204         {
       
   205           UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize;
       
   206           UInt32 num = mf->streamPos - mf->pos;
       
   207           heads[0] = 2;
       
   208           heads[1] = num;
       
   209           if (num >= mf->numHashBytes)
       
   210           {
       
   211             num = num - mf->numHashBytes + 1;
       
   212             if (num > kMtHashBlockSize - 2)
       
   213               num = kMtHashBlockSize - 2;
       
   214             mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num);
       
   215             heads[0] += num;
       
   216           }
       
   217           mf->pos += num;
       
   218           mf->buffer += num;
       
   219         }
       
   220       }
       
   221 
       
   222       Semaphore_Release1(&p->filledSemaphore);
       
   223     }
       
   224   }
       
   225 }
       
   226 
       
   227 void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p)
       
   228 {
       
   229   MtSync_GetNextBlock(&p->hashSync);
       
   230   p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize;
       
   231   p->hashBufPosLimit += p->hashBuf[p->hashBufPos++];
       
   232   p->hashNumAvail = p->hashBuf[p->hashBufPos++];
       
   233 }
       
   234 
       
   235 #define kEmptyHashValue 0
       
   236 
       
   237 /* #define MFMT_GM_INLINE */
       
   238 
       
   239 #ifdef MFMT_GM_INLINE
       
   240 
       
   241 #if _MSC_VER >= 1300
       
   242 #define NO_INLINE __declspec(noinline) __fastcall 
       
   243 #else
       
   244 #ifdef _MSC_VER
       
   245 #define NO_INLINE __fastcall 
       
   246 #endif
       
   247 #endif
       
   248 
       
   249 Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son, 
       
   250     UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, 
       
   251     UInt32 *_distances, UInt32 _maxLen, const UInt32 *hash, Int32 limit, UInt32 size, UInt32 *posRes)
       
   252 {
       
   253   do
       
   254   {
       
   255   UInt32 *distances = _distances + 1;
       
   256   UInt32 curMatch = pos - *hash++;
       
   257 
       
   258   CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
       
   259   CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
       
   260   UInt32 len0 = 0, len1 = 0;
       
   261   UInt32 cutValue = _cutValue;
       
   262   UInt32 maxLen = _maxLen;
       
   263   for (;;)
       
   264   {
       
   265     UInt32 delta = pos - curMatch;
       
   266     if (cutValue-- == 0 || delta >= _cyclicBufferSize)
       
   267     {
       
   268       *ptr0 = *ptr1 = kEmptyHashValue;
       
   269       break;
       
   270     }
       
   271     {
       
   272       CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
       
   273       const Byte *pb = cur - delta;
       
   274       UInt32 len = (len0 < len1 ? len0 : len1);
       
   275       if (pb[len] == cur[len])
       
   276       {
       
   277         if (++len != lenLimit && pb[len] == cur[len])
       
   278           while(++len != lenLimit)
       
   279             if (pb[len] != cur[len])
       
   280               break;
       
   281         if (maxLen < len)
       
   282         {
       
   283           *distances++ = maxLen = len;
       
   284           *distances++ = delta - 1;
       
   285           if (len == lenLimit)
       
   286           {
       
   287             *ptr1 = pair[0];
       
   288             *ptr0 = pair[1];
       
   289             break;
       
   290           }
       
   291         }
       
   292       }
       
   293       if (pb[len] < cur[len])
       
   294       {
       
   295         *ptr1 = curMatch;
       
   296         ptr1 = pair + 1;
       
   297         curMatch = *ptr1;
       
   298         len1 = len;
       
   299       }
       
   300       else
       
   301       {
       
   302         *ptr0 = curMatch;
       
   303         ptr0 = pair;
       
   304         curMatch = *ptr0;
       
   305         len0 = len;
       
   306       }
       
   307     }
       
   308   }
       
   309   pos++;
       
   310   _cyclicBufferPos++;
       
   311   cur++;
       
   312   {
       
   313     UInt32 num = (UInt32)(distances - _distances);
       
   314     *_distances = num - 1;
       
   315     _distances += num;
       
   316     limit -= num;
       
   317   }
       
   318   }
       
   319   while (limit > 0 && --size != 0);
       
   320   *posRes = pos;
       
   321   return limit;
       
   322 }
       
   323 
       
   324 #endif
       
   325 
       
   326 void BtGetMatches(CMatchFinderMt *p, UInt32 *distances)
       
   327 {
       
   328   UInt32 numProcessed = 0;
       
   329   UInt32 curPos = 2;
       
   330   UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2);
       
   331   distances[1] = p->hashNumAvail;
       
   332   while (curPos < limit)
       
   333   {
       
   334     if (p->hashBufPos == p->hashBufPosLimit)
       
   335     {
       
   336       MatchFinderMt_GetNextBlock_Hash(p);
       
   337       distances[1] = numProcessed + p->hashNumAvail;
       
   338       if (p->hashNumAvail >= p->numHashBytes)
       
   339         continue;
       
   340       for (; p->hashNumAvail != 0; p->hashNumAvail--)
       
   341         distances[curPos++] = 0;
       
   342       break;
       
   343     }
       
   344     {
       
   345       UInt32 size = p->hashBufPosLimit - p->hashBufPos;
       
   346       UInt32 lenLimit = p->matchMaxLen;
       
   347       UInt32 pos = p->pos;
       
   348       UInt32 cyclicBufferPos = p->cyclicBufferPos;
       
   349       if (lenLimit >= p->hashNumAvail)
       
   350         lenLimit = p->hashNumAvail;
       
   351       {
       
   352         UInt32 size2 = p->hashNumAvail - lenLimit + 1;
       
   353         if (size2 < size)
       
   354           size = size2;
       
   355         size2 = p->cyclicBufferSize - cyclicBufferPos;
       
   356         if (size2 < size)
       
   357           size = size2;
       
   358       }
       
   359       #ifndef MFMT_GM_INLINE
       
   360       while (curPos < limit && size-- != 0)
       
   361       {
       
   362         UInt32 *startDistances = distances + curPos;
       
   363         UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++], 
       
   364           pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, 
       
   365           startDistances + 1, p->numHashBytes - 1) - startDistances);
       
   366         *startDistances = num - 1;
       
   367         curPos += num;
       
   368         cyclicBufferPos++;
       
   369         pos++;
       
   370         p->buffer++;
       
   371       }
       
   372       #else
       
   373       {
       
   374         UInt32 posRes;
       
   375         curPos = limit - GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, 
       
   376           distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos) , size, &posRes);
       
   377         p->hashBufPos += posRes - pos;
       
   378         cyclicBufferPos += posRes - pos;
       
   379         p->buffer += posRes - pos;
       
   380         pos = posRes;
       
   381       }
       
   382       #endif
       
   383 
       
   384       numProcessed += pos - p->pos;
       
   385       p->hashNumAvail -= pos - p->pos;
       
   386       p->pos = pos;
       
   387       if (cyclicBufferPos == p->cyclicBufferSize)
       
   388         cyclicBufferPos = 0;
       
   389       p->cyclicBufferPos = cyclicBufferPos;
       
   390     }
       
   391   }
       
   392   distances[0] = curPos;
       
   393 }
       
   394 
       
   395 void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex)
       
   396 {
       
   397   CMtSync *sync = &p->hashSync;
       
   398   if (!sync->needStart)
       
   399   {
       
   400     CriticalSection_Enter(&sync->cs);
       
   401     sync->csWasEntered = True;
       
   402   }
       
   403   
       
   404   BtGetMatches(p, p->btBuf + (globalBlockIndex & kMtBtNumBlocksMask) * kMtBtBlockSize);
       
   405 
       
   406   if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize)
       
   407   {
       
   408     UInt32 subValue = p->pos - p->cyclicBufferSize;
       
   409     MatchFinder_Normalize3(subValue, p->son, p->cyclicBufferSize * 2);
       
   410     p->pos -= subValue;
       
   411   }
       
   412 
       
   413   if (!sync->needStart)
       
   414   {
       
   415     CriticalSection_Leave(&sync->cs);
       
   416     sync->csWasEntered = False;
       
   417   }
       
   418 }
       
   419 
       
   420 void BtThreadFunc(CMatchFinderMt *mt)
       
   421 {
       
   422   CMtSync *p = &mt->btSync;
       
   423   for (;;)
       
   424   {
       
   425     UInt32 blockIndex = 0;
       
   426     Event_Wait(&p->canStart);
       
   427     Event_Set(&p->wasStarted);
       
   428     for (;;)
       
   429     {
       
   430       if (p->exit)
       
   431         return;
       
   432       if (p->stopWriting)
       
   433       {
       
   434         p->numProcessedBlocks = blockIndex;
       
   435         MtSync_StopWriting(&mt->hashSync);
       
   436         Event_Set(&p->wasStopped);
       
   437         break;
       
   438       }
       
   439       Semaphore_Wait(&p->freeSemaphore);
       
   440       BtFillBlock(mt, blockIndex++);
       
   441       Semaphore_Release1(&p->filledSemaphore);
       
   442     }
       
   443   }
       
   444 }
       
   445 
       
   446 void MatchFinderMt_Construct(CMatchFinderMt *p)
       
   447 {
       
   448   p->hashBuf = 0;
       
   449   MtSync_Construct(&p->hashSync);
       
   450   MtSync_Construct(&p->btSync);
       
   451 }
       
   452 
       
   453 void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc)
       
   454 {
       
   455   alloc->Free(p->hashBuf);
       
   456   p->hashBuf = 0;
       
   457 }
       
   458 
       
   459 void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc)
       
   460 {
       
   461   MtSync_Destruct(&p->hashSync);
       
   462   MtSync_Destruct(&p->btSync);
       
   463   MatchFinderMt_FreeMem(p, alloc);
       
   464 }
       
   465 
       
   466 #define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks)
       
   467 #define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks)
       
   468 
       
   469 static unsigned StdCall HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p);  return 0; }
       
   470 static unsigned StdCall BtThreadFunc2(void *p) 
       
   471 { 
       
   472   #ifdef USE_ALLOCA
       
   473   alloca(0x180);
       
   474   #endif
       
   475   BtThreadFunc((CMatchFinderMt *)p); 
       
   476   return 0; 
       
   477 }
       
   478 
       
   479 HRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, 
       
   480     UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc)
       
   481 { 
       
   482   CMatchFinder *mf = p->MatchFinder;
       
   483   p->historySize = historySize;
       
   484   if (kMtBtBlockSize <= matchMaxLen * 4)
       
   485     return E_INVALIDARG;
       
   486   if (p->hashBuf == 0)
       
   487   {
       
   488     p->hashBuf = (UInt32 *)alloc->Alloc((kHashBufferSize + kBtBufferSize) * sizeof(UInt32));
       
   489     if (p->hashBuf == 0)
       
   490       return SZE_OUTOFMEMORY;
       
   491     p->btBuf = p->hashBuf + kHashBufferSize;
       
   492   }
       
   493   keepAddBufferBefore += (kHashBufferSize + kBtBufferSize);
       
   494   keepAddBufferAfter += kMtHashBlockSize;
       
   495   if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc))
       
   496     return SZE_OUTOFMEMORY;
       
   497 
       
   498   RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p, kMtHashNumBlocks));
       
   499   RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p, kMtBtNumBlocks));
       
   500   return SZ_OK;
       
   501 }
       
   502 
       
   503 /* Call it after ReleaseStream / SetStream */
       
   504 void MatchFinderMt_Init(CMatchFinderMt *p)
       
   505 { 
       
   506   CMatchFinder *mf = p->MatchFinder;
       
   507   p->btBufPos = p->btBufPosLimit = 0;
       
   508   p->hashBufPos = p->hashBufPosLimit = 0;
       
   509   MatchFinder_Init(mf);
       
   510   p->pointerToCurPos = MatchFinder_GetPointerToCurrentPos(mf);
       
   511   p->btNumAvailBytes = 0;
       
   512   p->lzPos = p->historySize + 1;
       
   513 
       
   514   p->hash = mf->hash;
       
   515   p->fixedHashSize = mf->fixedHashSize;
       
   516 
       
   517   p->son = mf->son;
       
   518   p->matchMaxLen = mf->matchMaxLen;
       
   519   p->numHashBytes = mf->numHashBytes;
       
   520   p->pos = mf->pos;
       
   521   p->buffer = mf->buffer;
       
   522   p->cyclicBufferPos = mf->cyclicBufferPos;
       
   523   p->cyclicBufferSize = mf->cyclicBufferSize;
       
   524   p->cutValue = mf->cutValue;
       
   525 }
       
   526 
       
   527 /* ReleaseStream is required to finish multithreading */
       
   528 void MatchFinderMt_ReleaseStream(CMatchFinderMt *p)
       
   529 { 
       
   530   MtSync_StopWriting(&p->btSync);
       
   531   /* p->MatchFinder->ReleaseStream(); */
       
   532 }
       
   533 
       
   534 void MatchFinderMt_Normalize(CMatchFinderMt *p)
       
   535 {
       
   536   MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize);
       
   537   p->lzPos = p->historySize + 1;
       
   538 }
       
   539 
       
   540 void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p)
       
   541 {
       
   542   UInt32 blockIndex;
       
   543   MtSync_GetNextBlock(&p->btSync);
       
   544   blockIndex = ((p->btSync.numProcessedBlocks - 1) & kMtBtNumBlocksMask);
       
   545   p->btBufPosLimit = p->btBufPos = blockIndex * kMtBtBlockSize;
       
   546   p->btBufPosLimit += p->btBuf[p->btBufPos++];
       
   547   p->btNumAvailBytes = p->btBuf[p->btBufPos++];
       
   548   if (p->lzPos >= kMtMaxValForNormalize - kMtBtBlockSize) 
       
   549     MatchFinderMt_Normalize(p);
       
   550 }
       
   551 
       
   552 const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p)
       
   553 {
       
   554   return p->pointerToCurPos;
       
   555 }
       
   556 
       
   557 #define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p);
       
   558 
       
   559 UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p)
       
   560 { 
       
   561   GET_NEXT_BLOCK_IF_REQUIRED;
       
   562   return p->btNumAvailBytes;
       
   563 }
       
   564 
       
   565 Byte MatchFinderMt_GetIndexByte(CMatchFinderMt *p, Int32 index)
       
   566 { 
       
   567   return p->pointerToCurPos[index]; 
       
   568 }
       
   569 
       
   570 UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
       
   571 {
       
   572   UInt32 hash2Value, curMatch2;
       
   573   UInt32 *hash = p->hash;
       
   574   const Byte *cur = p->pointerToCurPos;
       
   575   UInt32 lzPos = p->lzPos; 
       
   576   MT_HASH2_CALC
       
   577       
       
   578   curMatch2 = hash[hash2Value];
       
   579   hash[hash2Value] = lzPos;
       
   580 
       
   581   if (curMatch2 >= matchMinPos) 
       
   582     if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
       
   583     {
       
   584       *distances++ = 2; 
       
   585       *distances++ = lzPos - curMatch2 - 1;
       
   586     }
       
   587   return distances;
       
   588 }
       
   589 
       
   590 UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
       
   591 {
       
   592   UInt32 hash2Value, hash3Value, curMatch2, curMatch3;
       
   593   UInt32 *hash = p->hash;
       
   594   const Byte *cur = p->pointerToCurPos;
       
   595   UInt32 lzPos = p->lzPos; 
       
   596   MT_HASH3_CALC
       
   597 
       
   598   curMatch2 = hash[                hash2Value];
       
   599   curMatch3 = hash[kFix3HashSize + hash3Value];
       
   600   
       
   601   hash[                hash2Value] = 
       
   602   hash[kFix3HashSize + hash3Value] = 
       
   603     lzPos;
       
   604 
       
   605   if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
       
   606   { 
       
   607     distances[1] = lzPos - curMatch2 - 1;
       
   608     if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
       
   609     {
       
   610       distances[0] = 3;
       
   611       return distances + 2;
       
   612     }
       
   613     distances[0] = 2; 
       
   614     distances += 2;
       
   615   }
       
   616   if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
       
   617   { 
       
   618     *distances++ = 3; 
       
   619     *distances++ = lzPos - curMatch3 - 1; 
       
   620   }
       
   621   return distances;
       
   622 }
       
   623 
       
   624 /*
       
   625 UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
       
   626 {
       
   627   UInt32 hash2Value, hash3Value, hash4Value, curMatch2, curMatch3, curMatch4;
       
   628   UInt32 *hash = p->hash;
       
   629   const Byte *cur = p->pointerToCurPos;
       
   630   UInt32 lzPos = p->lzPos; 
       
   631   MT_HASH4_CALC
       
   632       
       
   633   curMatch2 = hash[                hash2Value];
       
   634   curMatch3 = hash[kFix3HashSize + hash3Value];
       
   635   curMatch4 = hash[kFix4HashSize + hash4Value];
       
   636   
       
   637   hash[                hash2Value] = 
       
   638   hash[kFix3HashSize + hash3Value] = 
       
   639   hash[kFix4HashSize + hash4Value] = 
       
   640     lzPos;
       
   641 
       
   642   if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
       
   643   {
       
   644     distances[1] = lzPos - curMatch2 - 1;
       
   645     if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
       
   646     {
       
   647       distances[0] =  (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3;
       
   648       return distances + 2;
       
   649     }
       
   650     distances[0] = 2;
       
   651     distances += 2;
       
   652   }
       
   653   if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
       
   654   {
       
   655     distances[1] = lzPos - curMatch3 - 1;
       
   656     if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3])
       
   657     {
       
   658       distances[0] = 4;
       
   659       return distances + 2;
       
   660     }
       
   661     distances[0] = 3;
       
   662     distances += 2;
       
   663   }
       
   664 
       
   665   if (curMatch4 >= matchMinPos)
       
   666     if (
       
   667       cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] &&
       
   668       cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3]
       
   669       )
       
   670     {
       
   671       *distances++ = 4;
       
   672       *distances++ = lzPos - curMatch4 - 1;
       
   673     }
       
   674   return distances;
       
   675 }
       
   676 */
       
   677 
       
   678 #define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++;
       
   679 
       
   680 UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances)
       
   681 { 
       
   682   const UInt32 *btBuf = p->btBuf + p->btBufPos;
       
   683   UInt32 len = *btBuf++;
       
   684   p->btBufPos += 1 + len;
       
   685   p->btNumAvailBytes--;
       
   686   {
       
   687     UInt32 i;
       
   688     for (i = 0; i < len; i += 2)
       
   689     {
       
   690       *distances++ = *btBuf++;
       
   691       *distances++ = *btBuf++;
       
   692     }
       
   693   }
       
   694   INCREASE_LZ_POS
       
   695   return len;
       
   696 }
       
   697 
       
   698 UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances)
       
   699 { 
       
   700   const UInt32 *btBuf = p->btBuf + p->btBufPos;
       
   701   UInt32 len = *btBuf++;
       
   702   p->btBufPos += 1 + len;
       
   703 
       
   704   if (len == 0)
       
   705   {
       
   706     if (p->btNumAvailBytes-- >= 4) 
       
   707       len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances));
       
   708   }
       
   709   else
       
   710   {
       
   711     /* Condition: there are matches in btBuf with length < p->numHashBytes */
       
   712     UInt32 *distances2;
       
   713     p->btNumAvailBytes--;
       
   714     distances2 = p->MixMatchesFunc(p, p->lzPos - btBuf[1], distances);
       
   715     do 
       
   716     {
       
   717       *distances2++ = *btBuf++;
       
   718       *distances2++ = *btBuf++;
       
   719     }
       
   720     while ((len -= 2) != 0);
       
   721     len  = (UInt32)(distances2 - (distances));
       
   722   }
       
   723   INCREASE_LZ_POS
       
   724   return len;
       
   725 }
       
   726 
       
   727 #define SKIP_HEADER2  do { GET_NEXT_BLOCK_IF_REQUIRED
       
   728 #define SKIP_HEADER(n) SKIP_HEADER2 if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash;
       
   729 #define SKIP_FOOTER } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while(--num != 0);
       
   730 
       
   731 void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num)
       
   732 { 
       
   733   SKIP_HEADER2 { p->btNumAvailBytes--;
       
   734   SKIP_FOOTER
       
   735 }
       
   736 
       
   737 void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num)
       
   738 { 
       
   739   SKIP_HEADER(2)
       
   740       UInt32 hash2Value;
       
   741       MT_HASH2_CALC
       
   742       hash[hash2Value] = p->lzPos;
       
   743   SKIP_FOOTER
       
   744 }
       
   745 
       
   746 void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num)
       
   747 { 
       
   748   SKIP_HEADER(3)
       
   749       UInt32 hash2Value, hash3Value;
       
   750       MT_HASH3_CALC
       
   751       hash[kFix3HashSize + hash3Value] = 
       
   752       hash[                hash2Value] = 
       
   753         p->lzPos;
       
   754   SKIP_FOOTER
       
   755 }
       
   756 
       
   757 /*
       
   758 void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num)
       
   759 { 
       
   760   SKIP_HEADER(4)
       
   761       UInt32 hash2Value, hash3Value, hash4Value;
       
   762       MT_HASH4_CALC
       
   763       hash[kFix4HashSize + hash4Value] = 
       
   764       hash[kFix3HashSize + hash3Value] = 
       
   765       hash[                hash2Value] = 
       
   766         p->lzPos;
       
   767   SKIP_FOOTER
       
   768 }
       
   769 */
       
   770 
       
   771 void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable)
       
   772 {
       
   773   vTable->Init = (Mf_Init_Func)MatchFinderMt_Init;
       
   774   vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinderMt_GetIndexByte;
       
   775   vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes;
       
   776   vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos;
       
   777   vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches;
       
   778   switch(p->MatchFinder->numHashBytes)
       
   779   {
       
   780     case 2:
       
   781       p->GetHeadsFunc = GetHeads2;
       
   782       p->MixMatchesFunc = (Mf_Mix_Matches)0;
       
   783       vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip;
       
   784       vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches;
       
   785       break;
       
   786     case 3:
       
   787       p->GetHeadsFunc = GetHeads3;
       
   788       p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2;
       
   789       vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip;
       
   790       break;
       
   791     default:
       
   792     /* case 4: */
       
   793       p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4;
       
   794       /* p->GetHeadsFunc = GetHeads4; */
       
   795       p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3;
       
   796       vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip;
       
   797       break;
       
   798     /*
       
   799     default:
       
   800       p->GetHeadsFunc = GetHeads5;
       
   801       p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4;
       
   802       vTable->Skip = (Mf_Skip_Func)MatchFinderMt4_Skip;
       
   803       break;
       
   804     */
       
   805   }
       
   806 }