// PatMain.h #include "../../../../Common/Defs.h" #include "../../../../Common/Alloc.h" namespace PAT_NAMESPACE { STDMETHODIMP CPatricia::SetCallback(IMatchFinderCallback *callback) { m_Callback = callback; return S_OK; } void CPatricia::BeforeMoveBlock() { if (m_Callback) m_Callback->BeforeChangingBufferPos(); CLZInWindow::BeforeMoveBlock(); } void CPatricia::AfterMoveBlock() { if (m_Callback) m_Callback->AfterChangingBufferPos(); CLZInWindow::AfterMoveBlock(); } const UInt32 kMatchStartValue2 = 2; const UInt32 kDescendantEmptyValue2 = kMatchStartValue2 - 1; const UInt32 kDescendantsNotInitilized2 = kDescendantEmptyValue2 - 1; #ifdef __HASH_3 static const UInt32 kNumHashBytes = 3; static const UInt32 kHashSize = 1 << (8 * kNumHashBytes); static const UInt32 kNumHash2Bytes = 2; static const UInt32 kHash2Size = 1 << (8 * kNumHash2Bytes); static const UInt32 kPrevHashSize = kNumHash2Bytes; #else static const UInt32 kNumHashBytes = 2; static const UInt32 kHashSize = 1 << (8 * kNumHashBytes); static const UInt32 kPrevHashSize = 0; #endif CPatricia::CPatricia(): m_HashDescendants(0), #ifdef __HASH_3 m_Hash2Descendants(0), #endif m_Nodes(0), m_TmpBacks(0) { } CPatricia::~CPatricia() { FreeMemory(); } void CPatricia::FreeMemory() { MyFree(m_TmpBacks); m_TmpBacks = 0; ::BigFree(m_Nodes); m_Nodes = 0; ::BigFree(m_HashDescendants); m_HashDescendants = 0; #ifdef __HASH_3 ::BigFree(m_Hash2Descendants); m_Hash2Descendants = 0; CLZInWindow::Free(); #endif } STDMETHODIMP CPatricia::Create(UInt32 historySize, UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter) { FreeMemory(); int kNumBitsInNumSameBits = sizeof(CSameBitsType) * 8; if (kNumBitsInNumSameBits < 32 && ((matchMaxLen * MY_BYTE_SIZE) > ((UInt32)1 << kNumBitsInNumSameBits))) return E_INVALIDARG; const UInt32 kAlignMask = (1 << 16) - 1; UInt32 windowReservSize = historySize; windowReservSize += kAlignMask; windowReservSize &= ~(kAlignMask); const UInt32 kMinReservSize = (1 << 19); if (windowReservSize < kMinReservSize) windowReservSize = kMinReservSize; windowReservSize += 256; if (!CLZInWindow::Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize)) return E_OUTOFMEMORY; _sizeHistory = historySize; _matchMaxLen = matchMaxLen; m_HashDescendants = (CDescendant *)BigAlloc(kHashSize * sizeof(CDescendant)); if (m_HashDescendants == 0) { FreeMemory(); return E_OUTOFMEMORY; } #ifdef __HASH_3 m_Hash2Descendants = (CDescendant *)BigAlloc(kHash2Size * sizeof(CDescendant)); if (m_Hash2Descendants == 0) { FreeMemory(); return E_OUTOFMEMORY; } #endif #ifdef __AUTO_REMOVE #ifdef __HASH_3 m_NumNodes = historySize + _sizeHistory * 4 / 8 + (1 << 19); #else m_NumNodes = historySize + _sizeHistory * 4 / 8 + (1 << 10); #endif #else UInt32 m_NumNodes = historySize; #endif const UInt32 kMaxNumNodes = UInt32(1) << (sizeof(CIndex) * 8 - 1); if (m_NumNodes + 32 > kMaxNumNodes) return E_INVALIDARG; // m_Nodes = (CNode *)::BigAlloc((m_NumNodes + 2) * sizeof(CNode)); m_Nodes = (CNode *)::BigAlloc((m_NumNodes + 12) * sizeof(CNode)); if (m_Nodes == 0) { FreeMemory(); return E_OUTOFMEMORY; } m_TmpBacks = (UInt32 *)MyAlloc((_matchMaxLen + 1) * sizeof(UInt32)); if (m_TmpBacks == 0) { FreeMemory(); return E_OUTOFMEMORY; } return S_OK; } STDMETHODIMP CPatricia::Init(ISequentialInStream *aStream) { RINOK(CLZInWindow::Init(aStream)); // memset(m_HashDescendants, 0xFF, kHashSize * sizeof(m_HashDescendants[0])); #ifdef __HASH_3 for (UInt32 i = 0; i < kHash2Size; i++) m_Hash2Descendants[i].MatchPointer = kDescendantsNotInitilized2; #else for (UInt32 i = 0; i < kHashSize; i++) m_HashDescendants[i].MakeEmpty(); #endif m_Nodes[0].NextFreeNode = 1; m_FreeNode = 0; m_FreeNodeMax = 0; #ifdef __AUTO_REMOVE m_NumUsedNodes = 0; #else m_SpecialRemoveMode = false; #endif m_SpecialMode = false; return S_OK; } STDMETHODIMP_(void) CPatricia::ReleaseStream() { // CLZInWindow::ReleaseStream(); } // pos = _pos + kNumHashBytes // fullCurrentLimit = currentLimit + kNumHashBytes // fullMatchLen = matchLen + kNumHashBytes void CPatricia::ChangeLastMatch(UInt32 hashValue) { UInt32 pos = _pos + kNumHashBytes - 1; UInt32 descendantIndex; const Byte *currentBytePointer = _buffer + pos; UInt32 numLoadedBits = 0; Byte curByte = 0; // = 0 to disable warning of GCC CNodePointer node = &m_Nodes[m_HashDescendants[hashValue].NodePointer]; while(true) { UInt32 numSameBits = node->NumSameBits; if(numSameBits > 0) { if (numLoadedBits < numSameBits) { numSameBits -= numLoadedBits; currentBytePointer += (numSameBits / MY_BYTE_SIZE); numSameBits %= MY_BYTE_SIZE; curByte = *currentBytePointer++; numLoadedBits = MY_BYTE_SIZE; } curByte >>= numSameBits; numLoadedBits -= numSameBits; } if(numLoadedBits == 0) { curByte = *currentBytePointer++; numLoadedBits = MY_BYTE_SIZE; } descendantIndex = (curByte & kSubNodesMask); node->LastMatch = pos; numLoadedBits -= kNumSubBits; curByte >>= kNumSubBits; if(node->Descendants[descendantIndex].IsNode()) node = &m_Nodes[node->Descendants[descendantIndex].NodePointer]; else break; } node->Descendants[descendantIndex].MatchPointer = pos + kMatchStartValue; } UInt32 CPatricia::GetLongestMatch(UInt32 *distances) { UInt32 fullCurrentLimit; if (_pos + _matchMaxLen <= _streamPos) fullCurrentLimit = _matchMaxLen; else { fullCurrentLimit = _streamPos - _pos; if(fullCurrentLimit < kNumHashBytes) return 0; } UInt32 pos = _pos + kNumHashBytes; #ifdef __HASH_3 UInt32 hash2Value = ((UInt32(_buffer[_pos])) << 8) | _buffer[_pos + 1]; UInt32 hashValue = (hash2Value << 8) | _buffer[_pos + 2]; CDescendant &hash2Descendant = m_Hash2Descendants[hash2Value]; CDescendant &hashDescendant = m_HashDescendants[hashValue]; if(hash2Descendant.MatchPointer <= kDescendantEmptyValue2) { if(hash2Descendant.MatchPointer == kDescendantsNotInitilized2) { UInt32 base = hashValue & 0xFFFF00; for (UInt32 i = 0; i < 0x100; i++) m_HashDescendants[base + i].MakeEmpty(); } hash2Descendant.MatchPointer = pos + kMatchStartValue2; hashDescendant.MatchPointer = pos + kMatchStartValue; return 0; } distances[kNumHash2Bytes] = pos - (hash2Descendant.MatchPointer - kMatchStartValue2) - 1; hash2Descendant.MatchPointer = pos + kMatchStartValue2; #ifdef __AUTO_REMOVE if (distances[kNumHash2Bytes] >= _sizeHistory) { if (hashDescendant.IsNode()) RemoveNode(hashDescendant.NodePointer); hashDescendant.MatchPointer = pos + kMatchStartValue; return 0; } #endif if (fullCurrentLimit == kNumHash2Bytes) return kNumHash2Bytes; #else UInt32 hashValue = UInt32(GetIndexByte(1)) | (UInt32(GetIndexByte(0)) << 8); CDescendant &hashDescendant = m_HashDescendants[hashValue]; #endif if(m_SpecialMode) { if(hashDescendant.IsMatch()) m_NumNotChangedCycles = 0; if(m_NumNotChangedCycles >= _sizeHistory - 1) { ChangeLastMatch(hashValue); m_NumNotChangedCycles = 0; } if(GetIndexByte(fullCurrentLimit - 1) == GetIndexByte(fullCurrentLimit - 2)) { if(hashDescendant.IsMatch()) hashDescendant.MatchPointer = pos + kMatchStartValue; else m_NumNotChangedCycles++; for(UInt32 i = kNumHashBytes; i <= fullCurrentLimit; i++) distances[i] = 0; return fullCurrentLimit; } else if(m_NumNotChangedCycles > 0) ChangeLastMatch(hashValue); m_SpecialMode = false; } if(hashDescendant.IsEmpty()) { hashDescendant.MatchPointer = pos + kMatchStartValue; return kPrevHashSize; } UInt32 currentLimit = fullCurrentLimit - kNumHashBytes; if(hashDescendant.IsMatch()) { CMatchPointer matchPointer = hashDescendant.MatchPointer; UInt32 backReal = pos - (matchPointer - kMatchStartValue); UInt32 back = backReal - 1; #ifdef __AUTO_REMOVE if (back >= _sizeHistory) { hashDescendant.MatchPointer = pos + kMatchStartValue; return kPrevHashSize; } #endif UInt32 matchLen; distances += kNumHashBytes; Byte *buffer = _buffer + pos; for(matchLen = 0; true; matchLen++) { *distances++ = back; if (matchLen == currentLimit) { hashDescendant.MatchPointer = pos + kMatchStartValue; return kNumHashBytes + matchLen; } if (buffer[matchLen] != buffer[(size_t)matchLen - backReal]) break; } // UInt32 matchLen = GetMatchLen(kNumHashBytes, back, currentLimit); UInt32 fullMatchLen = matchLen + kNumHashBytes; hashDescendant.NodePointer = m_FreeNode; CNodePointer node = &m_Nodes[m_FreeNode]; m_FreeNode = node->NextFreeNode; #ifdef __AUTO_REMOVE m_NumUsedNodes++; #endif if (m_FreeNode > m_FreeNodeMax) { m_FreeNodeMax = m_FreeNode; m_Nodes[m_FreeNode].NextFreeNode = m_FreeNode + 1; } for (UInt32 i = 0; i < kNumSubNodes; i++) node->Descendants[i].NodePointer = kDescendantEmptyValue; node->LastMatch = pos; Byte byteNew = GetIndexByte(fullMatchLen); Byte byteOld = GetIndexByte(fullMatchLen - backReal); Byte bitsNew, bitsOld; UInt32 numSameBits = matchLen * MY_BYTE_SIZE; while (true) { bitsNew = (byteNew & kSubNodesMask); bitsOld = (byteOld & kSubNodesMask); if(bitsNew != bitsOld) break; byteNew >>= kNumSubBits; byteOld >>= kNumSubBits; numSameBits += kNumSubBits; } node->NumSameBits = CSameBitsType(numSameBits); node->Descendants[bitsNew].MatchPointer = pos + kMatchStartValue; node->Descendants[bitsOld].MatchPointer = matchPointer; return fullMatchLen; } const Byte *baseCurrentBytePointer = _buffer + pos; const Byte *currentBytePointer = baseCurrentBytePointer; UInt32 numLoadedBits = 0; Byte curByte = 0; CIndex *nodePointerPointer = &hashDescendant.NodePointer; CNodePointer node = &m_Nodes[*nodePointerPointer]; distances += kNumHashBytes; const Byte *bytePointerLimit = baseCurrentBytePointer + currentLimit; const Byte *currentAddingOffset = _buffer; #ifdef __AUTO_REMOVE UInt32 lowPos; if (pos > _sizeHistory) lowPos = pos - _sizeHistory; else lowPos = 0; #endif while(true) { #ifdef __AUTO_REMOVE if (node->LastMatch < lowPos) { RemoveNode(*nodePointerPointer); *nodePointerPointer = pos + kMatchStartValue; if (currentBytePointer == baseCurrentBytePointer) return kPrevHashSize; return kNumHashBytes + (UInt32)(currentBytePointer - baseCurrentBytePointer - 1); } #endif if(numLoadedBits == 0) { *distances++ = pos - node->LastMatch - 1; if(currentBytePointer >= bytePointerLimit) { for (UInt32 i = 0; i < kNumSubNodes; i++) node->Descendants[i].MatchPointer = pos + kMatchStartValue; node->LastMatch = pos; node->NumSameBits = 0; return fullCurrentLimit; } curByte = (*currentBytePointer++); currentAddingOffset++; numLoadedBits = MY_BYTE_SIZE; } UInt32 numSameBits = node->NumSameBits; if(numSameBits > 0) { Byte byteXOR = ((*(currentAddingOffset + node->LastMatch -1)) >> (MY_BYTE_SIZE - numLoadedBits)) ^ curByte; while(numLoadedBits <= numSameBits) { if(byteXOR != 0) { AddInternalNode(node, nodePointerPointer, curByte, byteXOR, numSameBits, pos); return kNumHashBytes + (UInt32)(currentBytePointer - baseCurrentBytePointer - 1); } *distances++ = pos - node->LastMatch - 1; numSameBits -= numLoadedBits; if(currentBytePointer >= bytePointerLimit) { for (UInt32 i = 0; i < kNumSubNodes; i++) node->Descendants[i].MatchPointer = pos + kMatchStartValue; node->LastMatch = pos; node->NumSameBits = CSameBitsType(node->NumSameBits - numSameBits); return fullCurrentLimit; } numLoadedBits = MY_BYTE_SIZE; curByte = (*currentBytePointer++); byteXOR = curByte ^ (*(currentAddingOffset + node->LastMatch)); currentAddingOffset++; } if((byteXOR & ((1 << numSameBits) - 1)) != 0) { AddInternalNode(node, nodePointerPointer, curByte, byteXOR, numSameBits, pos); return kNumHashBytes + (UInt32)(currentBytePointer - baseCurrentBytePointer - 1); } curByte >>= numSameBits; numLoadedBits -= numSameBits; } UInt32 descendantIndex = (curByte & kSubNodesMask); numLoadedBits -= kNumSubBits; nodePointerPointer = &node->Descendants[descendantIndex].NodePointer; UInt32 nextNodeIndex = *nodePointerPointer; node->LastMatch = pos; if (nextNodeIndex < kDescendantEmptyValue) { curByte >>= kNumSubBits; node = &m_Nodes[nextNodeIndex]; } else if (nextNodeIndex == kDescendantEmptyValue) { node->Descendants[descendantIndex].MatchPointer = pos + kMatchStartValue; return kNumHashBytes + (UInt32)(currentBytePointer - baseCurrentBytePointer - 1); } else break; } UInt32 descendantIndex = (curByte & kSubNodesMask); curByte >>= kNumSubBits; CMatchPointer matchPointer = node->Descendants[descendantIndex].MatchPointer; CMatchPointer realMatchPointer; realMatchPointer = matchPointer - kMatchStartValue; #ifdef __AUTO_REMOVE if (realMatchPointer < lowPos) { node->Descendants[descendantIndex].MatchPointer = pos + kMatchStartValue; return kNumHashBytes + (UInt32)(currentBytePointer - baseCurrentBytePointer - 1); } #endif Byte byteXOR; UInt32 numSameBits = 0; if(numLoadedBits != 0) { Byte matchByte = *(currentAddingOffset + realMatchPointer -1); matchByte >>= (MY_BYTE_SIZE - numLoadedBits); byteXOR = matchByte ^ curByte; if(byteXOR != 0) { AddLeafNode(node, curByte, byteXOR, numSameBits, pos, descendantIndex); return kNumHashBytes + (UInt32)(currentBytePointer - baseCurrentBytePointer - 1); } numSameBits += numLoadedBits; } const Byte *matchBytePointer = _buffer + realMatchPointer + (currentBytePointer - baseCurrentBytePointer); for(; currentBytePointer < bytePointerLimit; numSameBits += MY_BYTE_SIZE) { curByte = (*currentBytePointer++); *distances++ = pos - realMatchPointer - 1; byteXOR = curByte ^ (*matchBytePointer++); if(byteXOR != 0) { AddLeafNode(node, curByte, byteXOR, numSameBits, pos, descendantIndex); return kNumHashBytes + (UInt32)(currentBytePointer - baseCurrentBytePointer - 1); } } *distances = pos - realMatchPointer - 1; node->Descendants[descendantIndex].MatchPointer = pos + kMatchStartValue; if(*distances == 0) { m_SpecialMode = true; m_NumNotChangedCycles = 0; } return fullCurrentLimit; } STDMETHODIMP_(void) CPatricia::DummyLongestMatch() { GetLongestMatch(m_TmpBacks); } // ------------------------------------ // Remove Match typedef Byte CRemoveDataWord; static const int kSizeRemoveDataWordInBits = MY_BYTE_SIZE * sizeof(CRemoveDataWord); #ifndef __AUTO_REMOVE void CPatricia::RemoveMatch() { if(m_SpecialRemoveMode) { if(GetIndexByte(_matchMaxLen - 1 - _sizeHistory) == GetIndexByte(_matchMaxLen - _sizeHistory)) return; m_SpecialRemoveMode = false; } UInt32 pos = _pos + kNumHashBytes - _sizeHistory; #ifdef __HASH_3 const Byte *pp = _buffer + _pos - _sizeHistory; UInt32 hash2Value = ((UInt32(pp[0])) << 8) | pp[1]; UInt32 hashValue = (hash2Value << 8) | pp[2]; CDescendant &hashDescendant = m_HashDescendants[hashValue]; CDescendant &hash2Descendant = m_Hash2Descendants[hash2Value]; if (hash2Descendant >= kMatchStartValue2) if(hash2Descendant.MatchPointer == pos + kMatchStartValue2) hash2Descendant.MatchPointer = kDescendantEmptyValue2; #else UInt32 hashValue = UInt32(GetIndexByte(1 - _sizeHistory)) | (UInt32(GetIndexByte(0 - _sizeHistory)) << 8); CDescendant &hashDescendant = m_HashDescendants[hashValue]; #endif if(hashDescendant.IsEmpty()) return; if(hashDescendant.IsMatch()) { if(hashDescendant.MatchPointer == pos + kMatchStartValue) hashDescendant.MakeEmpty(); return; } UInt32 descendantIndex; const CRemoveDataWord *currentPointer = (const CRemoveDataWord *)(_buffer + pos); UInt32 numLoadedBits = 0; CRemoveDataWord curWord = 0; // = 0 to disable GCC warning CIndex *nodePointerPointer = &hashDescendant.NodePointer; CNodePointer node = &m_Nodes[hashDescendant.NodePointer]; while(true) { if(numLoadedBits == 0) { curWord = *currentPointer++; numLoadedBits = kSizeRemoveDataWordInBits; } UInt32 numSameBits = node->NumSameBits; if(numSameBits > 0) { if (numLoadedBits <= numSameBits) { numSameBits -= numLoadedBits; currentPointer += (numSameBits / kSizeRemoveDataWordInBits); numSameBits %= kSizeRemoveDataWordInBits; curWord = *currentPointer++; numLoadedBits = kSizeRemoveDataWordInBits; } curWord >>= numSameBits; numLoadedBits -= numSameBits; } descendantIndex = (curWord & kSubNodesMask); numLoadedBits -= kNumSubBits; curWord >>= kNumSubBits; UInt32 nextNodeIndex = node->Descendants[descendantIndex].NodePointer; if (nextNodeIndex < kDescendantEmptyValue) { nodePointerPointer = &node->Descendants[descendantIndex].NodePointer; node = &m_Nodes[nextNodeIndex]; } else break; } if (node->Descendants[descendantIndex].MatchPointer != pos + kMatchStartValue) { const Byte *currentBytePointer = _buffer + _pos - _sizeHistory; const Byte *currentBytePointerLimit = currentBytePointer + _matchMaxLen; for(;currentBytePointer < currentBytePointerLimit; currentBytePointer++) if(*currentBytePointer != *(currentBytePointer+1)) return; m_SpecialRemoveMode = true; return; } UInt32 numNodes = 0, numMatches = 0; UInt32 i; for (i = 0; i < kNumSubNodes; i++) { UInt32 nodeIndex = node->Descendants[i].NodePointer; if (nodeIndex < kDescendantEmptyValue) numNodes++; else if (nodeIndex > kDescendantEmptyValue) numMatches++; } numMatches -= 1; if (numNodes + numMatches > 1) { node->Descendants[descendantIndex].MakeEmpty(); return; } if(numNodes == 1) { UInt32 i; for (i = 0; i < kNumSubNodes; i++) if (node->Descendants[i].IsNode()) break; UInt32 nextNodeIndex = node->Descendants[i].NodePointer; CNodePointer nextNode = &m_Nodes[nextNodeIndex]; nextNode->NumSameBits += node->NumSameBits + kNumSubBits; *node = *nextNode; nextNode->NextFreeNode = m_FreeNode; m_FreeNode = nextNodeIndex; return; } UInt32 matchPointer = 0; // = 0 to disable GCC warning for (i = 0; i < kNumSubNodes; i++) if (node->Descendants[i].IsMatch() && i != descendantIndex) { matchPointer = node->Descendants[i].MatchPointer; break; } node->NextFreeNode = m_FreeNode; m_FreeNode = *nodePointerPointer; *nodePointerPointer = matchPointer; } #endif // Commented code is more correct, but it gives warning // on GCC: (1 << 32) // So we use kMatchStartValue twice: // kMatchStartValue = UInt32(1) << (kNumBitsInIndex - 1); // must be defined in Pat.h /* const UInt32 kNormalizeStartPos = (UInt32(1) << (kNumBitsInIndex)) - kMatchStartValue - kNumHashBytes - 1; */ const UInt32 kNormalizeStartPos = kMatchStartValue - kNumHashBytes - 1; STDMETHODIMP CPatricia::MovePos() { #ifndef __AUTO_REMOVE if(_pos >= _sizeHistory) RemoveMatch(); #endif RINOK(CLZInWindow::MovePos()); #ifdef __AUTO_REMOVE if (m_NumUsedNodes >= m_NumNodes) TestRemoveNodes(); #endif if (_pos >= kNormalizeStartPos) { #ifdef __AUTO_REMOVE TestRemoveNodesAndNormalize(); #else Normalize(); #endif } return S_OK; } #ifndef __AUTO_REMOVE void CPatricia::NormalizeDescendant(CDescendant &descendant, UInt32 subValue) { if (descendant.IsEmpty()) return; if (descendant.IsMatch()) descendant.MatchPointer = descendant.MatchPointer - subValue; else { CNode &node = m_Nodes[descendant.NodePointer]; node.LastMatch = node.LastMatch - subValue; for (UInt32 i = 0; i < kNumSubNodes; i++) NormalizeDescendant(node.Descendants[i], subValue); } } void CPatricia::Normalize() { UInt32 subValue = _pos - _sizeHistory; CLZInWindow::ReduceOffsets(subValue); #ifdef __HASH_3 for(UInt32 hash = 0; hash < kHash2Size; hash++) { CDescendant &descendant = m_Hash2Descendants[hash]; if (descendant.MatchPointer != kDescendantsNotInitilized2) { UInt32 base = hash << 8; for (UInt32 i = 0; i < 0x100; i++) NormalizeDescendant(m_HashDescendants[base + i], subValue); } if (descendant.MatchPointer < kMatchStartValue2) continue; descendant.MatchPointer = descendant.MatchPointer - subValue; } #else for(UInt32 hash = 0; hash < kHashSize; hash++) NormalizeDescendant(m_HashDescendants[hash], subValue); #endif } #else void CPatricia::TestRemoveDescendant(CDescendant &descendant, UInt32 limitPos) { CNode &node = m_Nodes[descendant.NodePointer]; UInt32 numChilds = 0; UInt32 childIndex = 0; // = 0 to disable GCC warning for (UInt32 i = 0; i < kNumSubNodes; i++) { CDescendant &descendant2 = node.Descendants[i]; if (descendant2.IsEmpty()) continue; if (descendant2.IsMatch()) { if (descendant2.MatchPointer < limitPos) descendant2.MakeEmpty(); else { numChilds++; childIndex = i; } } else { TestRemoveDescendant(descendant2, limitPos); if (!descendant2.IsEmpty()) { numChilds++; childIndex = i; } } } if (numChilds > 1) return; CIndex nodePointerTemp = descendant.NodePointer; if (numChilds == 1) { const CDescendant &descendant2 = node.Descendants[childIndex]; if (descendant2.IsNode()) m_Nodes[descendant2.NodePointer].NumSameBits += node.NumSameBits + kNumSubBits; descendant = descendant2; } else descendant.MakeEmpty(); node.NextFreeNode = m_FreeNode; m_FreeNode = nodePointerTemp; m_NumUsedNodes--; } void CPatricia::RemoveNode(UInt32 index) { CNode &node = m_Nodes[index]; for (UInt32 i = 0; i < kNumSubNodes; i++) { CDescendant &descendant2 = node.Descendants[i]; if (descendant2.IsNode()) RemoveNode(descendant2.NodePointer); } node.NextFreeNode = m_FreeNode; m_FreeNode = index; m_NumUsedNodes--; } void CPatricia::TestRemoveNodes() { UInt32 limitPos = kMatchStartValue + _pos - _sizeHistory + kNumHashBytes; #ifdef __HASH_3 UInt32 limitPos2 = kMatchStartValue2 + _pos - _sizeHistory + kNumHashBytes; for(UInt32 hash = 0; hash < kHash2Size; hash++) { CDescendant &descendant = m_Hash2Descendants[hash]; if (descendant.MatchPointer != kDescendantsNotInitilized2) { UInt32 base = hash << 8; for (UInt32 i = 0; i < 0x100; i++) { CDescendant &descendant = m_HashDescendants[base + i]; if (descendant.IsEmpty()) continue; if (descendant.IsMatch()) { if (descendant.MatchPointer < limitPos) descendant.MakeEmpty(); } else TestRemoveDescendant(descendant, limitPos); } } if (descendant.MatchPointer < kMatchStartValue2) continue; if (descendant.MatchPointer < limitPos2) descendant.MatchPointer = kDescendantEmptyValue2; } #else for(UInt32 hash = 0; hash < kHashSize; hash++) { CDescendant &descendant = m_HashDescendants[hash]; if (descendant.IsEmpty()) continue; if (descendant.IsMatch()) { if (descendant.MatchPointer < limitPos) descendant.MakeEmpty(); } else TestRemoveDescendant(descendant, limitPos); } #endif } void CPatricia::TestRemoveAndNormalizeDescendant(CDescendant &descendant, UInt32 limitPos, UInt32 subValue) { if (descendant.IsEmpty()) return; if (descendant.IsMatch()) { if (descendant.MatchPointer < limitPos) descendant.MakeEmpty(); else descendant.MatchPointer = descendant.MatchPointer - subValue; return; } CNode &node = m_Nodes[descendant.NodePointer]; UInt32 numChilds = 0; UInt32 childIndex = 0; // = 0 to disable GCC warning for (UInt32 i = 0; i < kNumSubNodes; i++) { CDescendant &descendant2 = node.Descendants[i]; TestRemoveAndNormalizeDescendant(descendant2, limitPos, subValue); if (!descendant2.IsEmpty()) { numChilds++; childIndex = i; } } if (numChilds > 1) { node.LastMatch = node.LastMatch - subValue; return; } CIndex nodePointerTemp = descendant.NodePointer; if (numChilds == 1) { const CDescendant &descendant2 = node.Descendants[childIndex]; if (descendant2.IsNode()) m_Nodes[descendant2.NodePointer].NumSameBits += node.NumSameBits + kNumSubBits; descendant = descendant2; } else descendant.MakeEmpty(); node.NextFreeNode = m_FreeNode; m_FreeNode = nodePointerTemp; m_NumUsedNodes--; } void CPatricia::TestRemoveNodesAndNormalize() { UInt32 subValue = _pos - _sizeHistory; UInt32 limitPos = kMatchStartValue + _pos - _sizeHistory + kNumHashBytes; CLZInWindow::ReduceOffsets(subValue); #ifdef __HASH_3 UInt32 limitPos2 = kMatchStartValue2 + _pos - _sizeHistory + kNumHashBytes; for(UInt32 hash = 0; hash < kHash2Size; hash++) { CDescendant &descendant = m_Hash2Descendants[hash]; if (descendant.MatchPointer != kDescendantsNotInitilized2) { UInt32 base = hash << 8; for (UInt32 i = 0; i < 0x100; i++) TestRemoveAndNormalizeDescendant(m_HashDescendants[base + i], limitPos, subValue); } if (descendant.MatchPointer < kMatchStartValue2) continue; if (descendant.MatchPointer < limitPos2) descendant.MatchPointer = kDescendantEmptyValue2; else descendant.MatchPointer = descendant.MatchPointer - subValue; } #else for(UInt32 hash = 0; hash < kHashSize; hash++) TestRemoveAndNormalizeDescendant(m_HashDescendants[hash], limitPos, subValue); #endif } #endif STDMETHODIMP_(Byte) CPatricia::GetIndexByte(Int32 index) { return CLZInWindow::GetIndexByte(index); } STDMETHODIMP_(UInt32) CPatricia::GetMatchLen(Int32 index, UInt32 back, UInt32 limit) { return CLZInWindow::GetMatchLen(index, back, limit); } STDMETHODIMP_(UInt32) CPatricia::GetNumAvailableBytes() { return CLZInWindow::GetNumAvailableBytes(); } STDMETHODIMP_(const Byte *) CPatricia::GetPointerToCurrentPos() { return CLZInWindow::GetPointerToCurrentPos(); } }