3 #include "../../../../Common/Defs.h"
\r
4 #include "../../../../Common/CRC.h"
\r
5 #include "../../../../Common/Alloc.h"
\r
9 // #include <xmmintrin.h>
\r
10 // It's for prefetch
\r
11 // But prefetch doesn't give big gain in K8.
\r
13 namespace BT_NAMESPACE {
\r
16 static const UInt32 kHash2Size = 1 << 10;
\r
17 #define kNumHashDirectBytes 0
\r
19 static const UInt32 kNumHashBytes = 4;
\r
20 static const UInt32 kHash3Size = 1 << 16;
\r
22 static const UInt32 kNumHashBytes = 3;
\r
24 static const UInt32 kHashSize = 0;
\r
25 static const UInt32 kMinMatchCheck = kNumHashBytes;
\r
26 static const UInt32 kStartMaxLen = 1;
\r
29 #define kNumHashDirectBytes 0
\r
30 static const UInt32 kNumHashBytes = 3;
\r
31 static const UInt32 kHashSize = 1 << 16;
\r
32 static const UInt32 kMinMatchCheck = kNumHashBytes;
\r
33 static const UInt32 kStartMaxLen = 1;
\r
35 #define kNumHashDirectBytes 2
\r
36 static const UInt32 kNumHashBytes = 2;
\r
37 static const UInt32 kHashSize = 1 << (8 * kNumHashBytes);
\r
38 static const UInt32 kMinMatchCheck = kNumHashBytes + 1;
\r
39 static const UInt32 kStartMaxLen = 1;
\r
45 static const UInt32 kHash3Offset = kHash2Size;
\r
49 static const UInt32 kFixHashSize = 0
\r
58 CMatchFinder::CMatchFinder():
\r
63 void CMatchFinder::FreeThisClassMemory()
\r
69 void CMatchFinder::FreeMemory()
\r
71 FreeThisClassMemory();
\r
72 CLZInWindow::Free();
\r
75 CMatchFinder::~CMatchFinder()
\r
80 STDMETHODIMP CMatchFinder::Create(UInt32 historySize, UInt32 keepAddBufferBefore,
\r
81 UInt32 matchMaxLen, UInt32 keepAddBufferAfter)
\r
83 if (historySize > kMaxValForNormalize - 256)
\r
86 return E_INVALIDARG;
\r
90 8 + (matchMaxLen >> 2);
\r
92 16 + (matchMaxLen >> 1);
\r
94 UInt32 sizeReserv = (historySize + keepAddBufferBefore +
\r
95 matchMaxLen + keepAddBufferAfter) / 2 + 256;
\r
96 if (CLZInWindow::Create(historySize + keepAddBufferBefore,
\r
97 matchMaxLen + keepAddBufferAfter, sizeReserv))
\r
99 _matchMaxLen = matchMaxLen;
\r
100 UInt32 newCyclicBufferSize = historySize + 1;
\r
101 if (_hash != 0 && newCyclicBufferSize == _cyclicBufferSize)
\r
103 FreeThisClassMemory();
\r
104 _cyclicBufferSize = newCyclicBufferSize; // don't change it
\r
106 UInt32 hs = kHashSize;
\r
108 #ifdef HASH_ARRAY_2
\r
109 hs = historySize - 1;
\r
116 if (hs > (1 << 24))
\r
118 #ifdef HASH_ARRAY_3
\r
121 hs = (1 << 24) - 1;
\r
127 _hashSizeSum = hs + kFixHashSize;
\r
128 UInt32 numItems = _hashSizeSum + _cyclicBufferSize
\r
129 #ifndef _HASH_CHAIN
\r
133 size_t sizeInBytes = (size_t)numItems * sizeof(CIndex);
\r
134 if (sizeInBytes / sizeof(CIndex) != numItems)
\r
135 return E_OUTOFMEMORY;
\r
136 _hash = (CIndex *)BigAlloc(sizeInBytes);
\r
137 _son = _hash + _hashSizeSum;
\r
142 return E_OUTOFMEMORY;
\r
145 static const UInt32 kEmptyHashValue = 0;
\r
147 STDMETHODIMP CMatchFinder::SetStream(ISequentialInStream *stream)
\r
149 CLZInWindow::SetStream(stream);
\r
153 STDMETHODIMP CMatchFinder::Init()
\r
155 RINOK(CLZInWindow::Init());
\r
156 for(UInt32 i = 0; i < _hashSizeSum; i++)
\r
157 _hash[i] = kEmptyHashValue;
\r
158 _cyclicBufferPos = 0;
\r
163 STDMETHODIMP_(void) CMatchFinder::ReleaseStream()
\r
165 // ReleaseStream();
\r
168 #ifdef HASH_ARRAY_2
\r
169 #ifdef HASH_ARRAY_3
\r
171 #define HASH_CALC { \
\r
172 UInt32 temp = CCRC::Table[cur[0]] ^ cur[1]; \
\r
173 hash2Value = temp & (kHash2Size - 1); \
\r
174 hash3Value = (temp ^ (UInt32(cur[2]) << 8)) & (kHash3Size - 1); \
\r
175 hashValue = (temp ^ (UInt32(cur[2]) << 8) ^ (CCRC::Table[cur[3]] << 5)) & _hashMask; }
\r
177 #else // no HASH_ARRAY_3
\r
178 #define HASH_CALC { \
\r
179 UInt32 temp = CCRC::Table[cur[0]] ^ cur[1]; \
\r
180 hash2Value = temp & (kHash2Size - 1); \
\r
181 hashValue = (temp ^ (UInt32(cur[2]) << 8)) & _hashMask; }
\r
182 #endif // HASH_ARRAY_3
\r
183 #else // no HASH_ARRAY_2
\r
185 inline UInt32 Hash(const Byte *pointer)
\r
187 return ((UInt32(pointer[0]) << 8) ^ CCRC::Table[pointer[1]] ^ pointer[2]) & (kHashSize - 1);
\r
189 #else // no HASH_ZIP
\r
190 inline UInt32 Hash(const Byte *pointer)
\r
192 return pointer[0] ^ (UInt32(pointer[1]) << 8);
\r
195 #endif // HASH_ARRAY_2
\r
197 STDMETHODIMP CMatchFinder::GetMatches(UInt32 *distances)
\r
200 if (_pos + _matchMaxLen <= _streamPos)
\r
201 lenLimit = _matchMaxLen;
\r
204 lenLimit = _streamPos - _pos;
\r
205 if(lenLimit < kMinMatchCheck)
\r
214 UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
\r
215 const Byte *cur = _buffer + _pos;
\r
217 UInt32 maxLen = kStartMaxLen; // to avoid items for len < hashSize;
\r
219 #ifdef HASH_ARRAY_2
\r
221 #ifdef HASH_ARRAY_3
\r
227 UInt32 hashValue = Hash(cur);
\r
230 UInt32 curMatch = _hash[kFixHashSize + hashValue];
\r
231 #ifdef HASH_ARRAY_2
\r
232 UInt32 curMatch2 = _hash[hash2Value];
\r
233 #ifdef HASH_ARRAY_3
\r
234 UInt32 curMatch3 = _hash[kHash3Offset + hash3Value];
\r
236 _hash[hash2Value] = _pos;
\r
237 if(curMatch2 > matchMinPos)
\r
238 if (_buffer[curMatch2] == cur[0])
\r
240 distances[offset++] = maxLen = 2;
\r
241 distances[offset++] = _pos - curMatch2 - 1;
\r
244 #ifdef HASH_ARRAY_3
\r
245 _hash[kHash3Offset + hash3Value] = _pos;
\r
246 if(curMatch3 > matchMinPos)
\r
247 if (_buffer[curMatch3] == cur[0])
\r
249 if (curMatch3 == curMatch2)
\r
251 distances[offset++] = maxLen = 3;
\r
252 distances[offset++] = _pos - curMatch3 - 1;
\r
253 curMatch2 = curMatch3;
\r
256 if (offset != 1 && curMatch2 == curMatch)
\r
259 maxLen = kStartMaxLen;
\r
263 _hash[kFixHashSize + hashValue] = _pos;
\r
265 CIndex *son = _son;
\r
268 son[_cyclicBufferPos] = curMatch;
\r
270 CIndex *ptr0 = son + (_cyclicBufferPos << 1) + 1;
\r
271 CIndex *ptr1 = son + (_cyclicBufferPos << 1);
\r
274 len0 = len1 = kNumHashDirectBytes;
\r
277 #if kNumHashDirectBytes != 0
\r
278 if(curMatch > matchMinPos)
\r
280 if (_buffer[curMatch + kNumHashDirectBytes] != cur[kNumHashDirectBytes])
\r
282 distances[offset++] = maxLen = kNumHashDirectBytes;
\r
283 distances[offset++] = _pos - curMatch - 1;
\r
287 UInt32 count = _cutValue;
\r
290 if(curMatch <= matchMinPos || count-- == 0)
\r
292 #ifndef _HASH_CHAIN
\r
293 *ptr0 = *ptr1 = kEmptyHashValue;
\r
297 UInt32 delta = _pos - curMatch;
\r
298 UInt32 cyclicPos = (delta <= _cyclicBufferPos) ?
\r
299 (_cyclicBufferPos - delta):
\r
300 (_cyclicBufferPos - delta + _cyclicBufferSize);
\r
301 CIndex *pair = son +
\r
308 // _mm_prefetch((const char *)pair, _MM_HINT_T0);
\r
310 const Byte *pb = _buffer + curMatch;
\r
313 kNumHashDirectBytes;
\r
314 if (pb[maxLen] == cur[maxLen])
\r
318 if (pb[len] == cur[len])
\r
320 while(++len != lenLimit)
\r
321 if (pb[len] != cur[len])
\r
325 distances[offset++] = maxLen = len;
\r
326 distances[offset++] = delta - 1;
\r
327 if (len == lenLimit)
\r
329 #ifndef _HASH_CHAIN
\r
340 if (pb[len] < cur[len])
\r
356 distances[0] = offset - 1;
\r
357 if (++_cyclicBufferPos == _cyclicBufferSize)
\r
358 _cyclicBufferPos = 0;
\r
359 RINOK(CLZInWindow::MovePos());
\r
360 if (_pos == kMaxValForNormalize)
\r
365 STDMETHODIMP CMatchFinder::Skip(UInt32 num)
\r
370 if (_streamPos - _pos < kNumHashBytes)
\r
377 if (_pos + _matchMaxLen <= _streamPos)
\r
378 lenLimit = _matchMaxLen;
\r
381 lenLimit = _streamPos - _pos;
\r
382 if(lenLimit < kMinMatchCheck)
\r
388 UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
\r
390 const Byte *cur = _buffer + _pos;
\r
392 #ifdef HASH_ARRAY_2
\r
394 #ifdef HASH_ARRAY_3
\r
398 _hash[kHash3Offset + hash3Value] = _pos;
\r
403 _hash[hash2Value] = _pos;
\r
405 UInt32 hashValue = Hash(cur);
\r
408 UInt32 curMatch = _hash[kFixHashSize + hashValue];
\r
409 _hash[kFixHashSize + hashValue] = _pos;
\r
412 _son[_cyclicBufferPos] = curMatch;
\r
414 CIndex *son = _son;
\r
415 CIndex *ptr0 = son + (_cyclicBufferPos << 1) + 1;
\r
416 CIndex *ptr1 = son + (_cyclicBufferPos << 1);
\r
419 len0 = len1 = kNumHashDirectBytes;
\r
420 UInt32 count = _cutValue;
\r
423 if(curMatch <= matchMinPos || count-- == 0)
\r
425 *ptr0 = *ptr1 = kEmptyHashValue;
\r
429 UInt32 delta = _pos - curMatch;
\r
430 UInt32 cyclicPos = (delta <= _cyclicBufferPos) ?
\r
431 (_cyclicBufferPos - delta):
\r
432 (_cyclicBufferPos - delta + _cyclicBufferSize);
\r
433 CIndex *pair = son + (cyclicPos << 1);
\r
435 // _mm_prefetch((const char *)pair, _MM_HINT_T0);
\r
437 const Byte *pb = _buffer + curMatch;
\r
438 UInt32 len = MyMin(len0, len1);
\r
440 if (pb[len] == cur[len])
\r
442 while(++len != lenLimit)
\r
443 if (pb[len] != cur[len])
\r
445 if (len == lenLimit)
\r
452 if (pb[len] < cur[len])
\r
468 if (++_cyclicBufferPos == _cyclicBufferSize)
\r
469 _cyclicBufferPos = 0;
\r
470 RINOK(CLZInWindow::MovePos());
\r
471 if (_pos == kMaxValForNormalize)
\r
478 void CMatchFinder::Normalize()
\r
480 UInt32 subValue = _pos - _cyclicBufferSize;
\r
481 CIndex *items = _hash;
\r
482 UInt32 numItems = (_hashSizeSum + _cyclicBufferSize
\r
483 #ifndef _HASH_CHAIN
\r
487 for (UInt32 i = 0; i < numItems; i++)
\r
489 UInt32 value = items[i];
\r
490 if (value <= subValue)
\r
491 value = kEmptyHashValue;
\r
496 ReduceOffsets(subValue);
\r
499 HRESULT CMatchFinder::MovePos()
\r
501 if (++_cyclicBufferPos == _cyclicBufferSize)
\r
502 _cyclicBufferPos = 0;
\r
503 RINOK(CLZInWindow::MovePos());
\r
504 if (_pos == kMaxValForNormalize)
\r
509 STDMETHODIMP_(Byte) CMatchFinder::GetIndexByte(Int32 index)
\r
510 { return CLZInWindow::GetIndexByte(index); }
\r
512 STDMETHODIMP_(UInt32) CMatchFinder::GetMatchLen(Int32 index,
\r
513 UInt32 back, UInt32 limit)
\r
514 { return CLZInWindow::GetMatchLen(index, back, limit); }
\r
516 STDMETHODIMP_(UInt32) CMatchFinder::GetNumAvailableBytes()
\r
517 { return CLZInWindow::GetNumAvailableBytes(); }
\r
519 STDMETHODIMP_(const Byte *) CMatchFinder::GetPointerToCurrentPos()
\r
520 { return CLZInWindow::GetPointerToCurrentPos(); }
\r
522 STDMETHODIMP_(Int32) CMatchFinder::NeedChangeBufferPos(UInt32 numCheckBytes)
\r
523 { return CLZInWindow::NeedMove(numCheckBytes) ? 1: 0; }
\r
525 STDMETHODIMP_(void) CMatchFinder::ChangeBufferPos()
\r
526 { CLZInWindow::MoveBlock();}
\r
529 #undef kNumHashDirectBytes
\r