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