📄 bintreemain.h
字号:
// BinTreeMain.h#include "../../../../Common/Defs.h"#include "../../../../Common/CRC.h"#include "../../../../Common/Alloc.h"#include "BinTree.h"// #include <xmmintrin.h>// It's for prefetch// But prefetch doesn't give big gain in K8.namespace BT_NAMESPACE {#ifdef HASH_ARRAY_2 static const UInt32 kHash2Size = 1 << 10; #define kNumHashDirectBytes 0 #ifdef HASH_ARRAY_3 static const UInt32 kNumHashBytes = 4; static const UInt32 kHash3Size = 1 << 16; #else static const UInt32 kNumHashBytes = 3; #endif static const UInt32 kHashSize = 0; static const UInt32 kMinMatchCheck = kNumHashBytes; static const UInt32 kStartMaxLen = 1;#else #ifdef HASH_ZIP #define kNumHashDirectBytes 0 static const UInt32 kNumHashBytes = 3; static const UInt32 kHashSize = 1 << 16; static const UInt32 kMinMatchCheck = kNumHashBytes; static const UInt32 kStartMaxLen = 1; #else #define kNumHashDirectBytes 2 static const UInt32 kNumHashBytes = 2; static const UInt32 kHashSize = 1 << (8 * kNumHashBytes); static const UInt32 kMinMatchCheck = kNumHashBytes + 1; static const UInt32 kStartMaxLen = 1; #endif#endif#ifdef HASH_ARRAY_2#ifdef HASH_ARRAY_3static const UInt32 kHash3Offset = kHash2Size;#endif#endifstatic const UInt32 kFixHashSize = 0 #ifdef HASH_ARRAY_2 + kHash2Size #ifdef HASH_ARRAY_3 + kHash3Size #endif #endif ;CMatchFinder::CMatchFinder(): _hash(0){}void CMatchFinder::FreeThisClassMemory(){ BigFree(_hash); _hash = 0;}void CMatchFinder::FreeMemory(){ FreeThisClassMemory(); CLZInWindow::Free();}CMatchFinder::~CMatchFinder(){ FreeMemory();}STDMETHODIMP CMatchFinder::Create(UInt32 historySize, UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter){ if (historySize > kMaxValForNormalize - 256) { FreeMemory(); return E_INVALIDARG; } _cutValue = #ifdef _HASH_CHAIN 8 + (matchMaxLen >> 2); #else 16 + (matchMaxLen >> 1); #endif UInt32 sizeReserv = (historySize + keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + 256; if (CLZInWindow::Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, sizeReserv)) { _matchMaxLen = matchMaxLen; UInt32 newCyclicBufferSize = historySize + 1; if (_hash != 0 && newCyclicBufferSize == _cyclicBufferSize) return S_OK; FreeThisClassMemory(); _cyclicBufferSize = newCyclicBufferSize; // don't change it UInt32 hs = kHashSize; #ifdef HASH_ARRAY_2 hs = historySize - 1; hs |= (hs >> 1); hs |= (hs >> 2); hs |= (hs >> 4); hs |= (hs >> 8); hs >>= 1; hs |= 0xFFFF; if (hs > (1 << 24)) { #ifdef HASH_ARRAY_3 hs >>= 1; #else hs = (1 << 24) - 1; #endif } _hashMask = hs; hs++; #endif _hashSizeSum = hs + kFixHashSize; UInt32 numItems = _hashSizeSum + _cyclicBufferSize #ifndef _HASH_CHAIN * 2 #endif ; size_t sizeInBytes = (size_t)numItems * sizeof(CIndex); if (sizeInBytes / sizeof(CIndex) != numItems) return E_OUTOFMEMORY; _hash = (CIndex *)BigAlloc(sizeInBytes); _son = _hash + _hashSizeSum; if (_hash != 0) return S_OK; } FreeMemory(); return E_OUTOFMEMORY;}static const UInt32 kEmptyHashValue = 0;STDMETHODIMP CMatchFinder::SetStream(ISequentialInStream *stream){ CLZInWindow::SetStream(stream); return S_OK;}STDMETHODIMP CMatchFinder::Init(){ RINOK(CLZInWindow::Init()); for(UInt32 i = 0; i < _hashSizeSum; i++) _hash[i] = kEmptyHashValue; _cyclicBufferPos = 0; ReduceOffsets(-1); return S_OK;}STDMETHODIMP_(void) CMatchFinder::ReleaseStream(){ // ReleaseStream(); }#ifdef HASH_ARRAY_2#ifdef HASH_ARRAY_3#define HASH_CALC { \ UInt32 temp = CCRC::Table[cur[0]] ^ cur[1]; \ hash2Value = temp & (kHash2Size - 1); \ hash3Value = (temp ^ (UInt32(cur[2]) << 8)) & (kHash3Size - 1); \ hashValue = (temp ^ (UInt32(cur[2]) << 8) ^ (CCRC::Table[cur[3]] << 5)) & _hashMask; } #else // no HASH_ARRAY_3#define HASH_CALC { \ UInt32 temp = CCRC::Table[cur[0]] ^ cur[1]; \ hash2Value = temp & (kHash2Size - 1); \ hashValue = (temp ^ (UInt32(cur[2]) << 8)) & _hashMask; }#endif // HASH_ARRAY_3#else // no HASH_ARRAY_2#ifdef HASH_ZIP inline UInt32 Hash(const Byte *pointer){ return ((UInt32(pointer[0]) << 8) ^ CCRC::Table[pointer[1]] ^ pointer[2]) & (kHashSize - 1);}#else // no HASH_ZIP inline UInt32 Hash(const Byte *pointer){ return pointer[0] ^ (UInt32(pointer[1]) << 8);}#endif // HASH_ZIP#endif // HASH_ARRAY_2STDMETHODIMP CMatchFinder::GetMatches(UInt32 *distances){ UInt32 lenLimit; if (_pos + _matchMaxLen <= _streamPos) lenLimit = _matchMaxLen; else { lenLimit = _streamPos - _pos; if(lenLimit < kMinMatchCheck) { distances[0] = 0; return MovePos(); } } int offset = 1; UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; const Byte *cur = _buffer + _pos; UInt32 maxLen = kStartMaxLen; // to avoid items for len < hashSize; #ifdef HASH_ARRAY_2 UInt32 hash2Value; #ifdef HASH_ARRAY_3 UInt32 hash3Value; #endif UInt32 hashValue; HASH_CALC; #else UInt32 hashValue = Hash(cur); #endif UInt32 curMatch = _hash[kFixHashSize + hashValue]; #ifdef HASH_ARRAY_2 UInt32 curMatch2 = _hash[hash2Value]; #ifdef HASH_ARRAY_3 UInt32 curMatch3 = _hash[kHash3Offset + hash3Value]; #endif _hash[hash2Value] = _pos; if(curMatch2 > matchMinPos) if (_buffer[curMatch2] == cur[0]) { distances[offset++] = maxLen = 2; distances[offset++] = _pos - curMatch2 - 1; } #ifdef HASH_ARRAY_3 _hash[kHash3Offset + hash3Value] = _pos; if(curMatch3 > matchMinPos) if (_buffer[curMatch3] == cur[0]) { if (curMatch3 == curMatch2) offset -= 2; distances[offset++] = maxLen = 3; distances[offset++] = _pos - curMatch3 - 1; curMatch2 = curMatch3; } #endif if (offset != 1 && curMatch2 == curMatch) { offset -= 2; maxLen = kStartMaxLen; } #endif _hash[kFixHashSize + hashValue] = _pos; CIndex *son = _son; #ifdef _HASH_CHAIN son[_cyclicBufferPos] = curMatch; #else CIndex *ptr0 = son + (_cyclicBufferPos << 1) + 1; CIndex *ptr1 = son + (_cyclicBufferPos << 1); UInt32 len0, len1; len0 = len1 = kNumHashDirectBytes; #endif #if kNumHashDirectBytes != 0 if(curMatch > matchMinPos) { if (_buffer[curMatch + kNumHashDirectBytes] != cur[kNumHashDirectBytes]) { distances[offset++] = maxLen = kNumHashDirectBytes; distances[offset++] = _pos - curMatch - 1; } } #endif UInt32 count = _cutValue; while(true) { if(curMatch <= matchMinPos || count-- == 0) { #ifndef _HASH_CHAIN *ptr0 = *ptr1 = kEmptyHashValue; #endif break; } UInt32 delta = _pos - curMatch; UInt32 cyclicPos = (delta <= _cyclicBufferPos) ? (_cyclicBufferPos - delta): (_cyclicBufferPos - delta + _cyclicBufferSize); CIndex *pair = son + #ifdef _HASH_CHAIN cyclicPos; #else (cyclicPos << 1); #endif // _mm_prefetch((const char *)pair, _MM_HINT_T0); const Byte *pb = _buffer + curMatch; UInt32 len = #ifdef _HASH_CHAIN kNumHashDirectBytes; if (pb[maxLen] == cur[maxLen]) #else MyMin(len0, len1); #endif if (pb[len] == cur[len]) { while(++len != lenLimit) if (pb[len] != cur[len]) break; if (maxLen < len) { distances[offset++] = maxLen = len; distances[offset++] = delta - 1; if (len == lenLimit) { #ifndef _HASH_CHAIN *ptr1 = pair[0]; *ptr0 = pair[1]; #endif break; } } } #ifdef _HASH_CHAIN curMatch = *pair; #else if (pb[len] < cur[len]) { *ptr1 = curMatch; ptr1 = pair + 1; curMatch = *ptr1; len1 = len; } else { *ptr0 = curMatch; ptr0 = pair; curMatch = *ptr0; len0 = len; } #endif } distances[0] = offset - 1; if (++_cyclicBufferPos == _cyclicBufferSize) _cyclicBufferPos = 0; RINOK(CLZInWindow::MovePos()); if (_pos == kMaxValForNormalize) Normalize(); return S_OK;}STDMETHODIMP CMatchFinder::Skip(UInt32 num){ do { #ifdef _HASH_CHAIN if (_streamPos - _pos < kNumHashBytes) { RINOK(MovePos()); continue; } #else UInt32 lenLimit; if (_pos + _matchMaxLen <= _streamPos) lenLimit = _matchMaxLen; else { lenLimit = _streamPos - _pos; if(lenLimit < kMinMatchCheck) { RINOK(MovePos()); continue; } } UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; #endif const Byte *cur = _buffer + _pos; #ifdef HASH_ARRAY_2 UInt32 hash2Value; #ifdef HASH_ARRAY_3 UInt32 hash3Value; UInt32 hashValue; HASH_CALC; _hash[kHash3Offset + hash3Value] = _pos; #else UInt32 hashValue; HASH_CALC; #endif _hash[hash2Value] = _pos; #else UInt32 hashValue = Hash(cur); #endif UInt32 curMatch = _hash[kFixHashSize + hashValue]; _hash[kFixHashSize + hashValue] = _pos; #ifdef _HASH_CHAIN _son[_cyclicBufferPos] = curMatch; #else CIndex *son = _son; CIndex *ptr0 = son + (_cyclicBufferPos << 1) + 1; CIndex *ptr1 = son + (_cyclicBufferPos << 1); UInt32 len0, len1; len0 = len1 = kNumHashDirectBytes; UInt32 count = _cutValue; while(true) { if(curMatch <= matchMinPos || count-- == 0) { *ptr0 = *ptr1 = kEmptyHashValue; break; } UInt32 delta = _pos - curMatch; UInt32 cyclicPos = (delta <= _cyclicBufferPos) ? (_cyclicBufferPos - delta): (_cyclicBufferPos - delta + _cyclicBufferSize); CIndex *pair = son + (cyclicPos << 1); // _mm_prefetch((const char *)pair, _MM_HINT_T0); const Byte *pb = _buffer + curMatch; UInt32 len = MyMin(len0, len1); if (pb[len] == cur[len]) { while(++len != lenLimit) if (pb[len] != cur[len]) break; if (len == lenLimit) { *ptr1 = pair[0]; *ptr0 = pair[1]; break; } } if (pb[len] < cur[len]) { *ptr1 = curMatch; ptr1 = pair + 1; curMatch = *ptr1; len1 = len; } else { *ptr0 = curMatch; ptr0 = pair; curMatch = *ptr0; len0 = len; } } #endif if (++_cyclicBufferPos == _cyclicBufferSize) _cyclicBufferPos = 0; RINOK(CLZInWindow::MovePos()); if (_pos == kMaxValForNormalize) Normalize(); } while(--num != 0); return S_OK;}void CMatchFinder::Normalize(){ UInt32 subValue = _pos - _cyclicBufferSize; CIndex *items = _hash; UInt32 numItems = (_hashSizeSum + _cyclicBufferSize #ifndef _HASH_CHAIN * 2 #endif ); for (UInt32 i = 0; i < numItems; i++) { UInt32 value = items[i]; if (value <= subValue) value = kEmptyHashValue; else value -= subValue; items[i] = value; } ReduceOffsets(subValue);}HRESULT CMatchFinder::MovePos(){ if (++_cyclicBufferPos == _cyclicBufferSize) _cyclicBufferPos = 0; RINOK(CLZInWindow::MovePos()); if (_pos == kMaxValForNormalize) Normalize(); return S_OK;}STDMETHODIMP_(Byte) CMatchFinder::GetIndexByte(Int32 index) { return CLZInWindow::GetIndexByte(index); }STDMETHODIMP_(UInt32) CMatchFinder::GetMatchLen(Int32 index, UInt32 back, UInt32 limit) { return CLZInWindow::GetMatchLen(index, back, limit); }STDMETHODIMP_(UInt32) CMatchFinder::GetNumAvailableBytes() { return CLZInWindow::GetNumAvailableBytes(); }STDMETHODIMP_(const Byte *) CMatchFinder::GetPointerToCurrentPos() { return CLZInWindow::GetPointerToCurrentPos(); }STDMETHODIMP_(Int32) CMatchFinder::NeedChangeBufferPos(UInt32 numCheckBytes) { return CLZInWindow::NeedMove(numCheckBytes) ? 1: 0; }STDMETHODIMP_(void) CMatchFinder::ChangeBufferPos() { CLZInWindow::MoveBlock();}#undef HASH_CALC#undef kNumHashDirectBytes }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -