3 #include "../../../../Common/Defs.h"
4 #include "../../../../Common/CRC.h"
5 #include "../../../../Common/Alloc.h"
7 namespace BT_NAMESPACE
{
10 static const UInt32 kHash2Size
= 1 << 10;
12 static const UInt32 kNumHashDirectBytes
= 0;
13 static const UInt32 kNumHashBytes
= 4;
14 static const UInt32 kHash3Size
= 1 << 18;
16 static const UInt32 kHashSize
= 1 << 23;
18 static const UInt32 kHashSize
= 1 << 20;
21 static const UInt32 kNumHashDirectBytes
= 3;
22 static const UInt32 kNumHashBytes
= 3;
23 static const UInt32 kHashSize
= 1 << (8 * kNumHashBytes
);
27 static const UInt32 kNumHashDirectBytes
= 0;
28 static const UInt32 kNumHashBytes
= 3;
29 static const UInt32 kHashSize
= 1 << 16;
31 #define THERE_ARE_DIRECT_HASH_BYTES
32 static const UInt32 kNumHashDirectBytes
= 2;
33 static const UInt32 kNumHashBytes
= 2;
34 static const UInt32 kHashSize
= 1 << (8 * kNumHashBytes
);
38 static const UInt32 kHashSizeSum
= kHashSize
48 static const UInt32 kHash2Offset
= kHashSize
;
50 static const UInt32 kHash3Offset
= kHashSize
+ kHash2Size
;
54 CMatchFinderBinTree::CMatchFinderBinTree():
60 void CMatchFinderBinTree::FreeThisClassMemory()
66 void CMatchFinderBinTree::FreeMemory()
68 FreeThisClassMemory();
72 CMatchFinderBinTree::~CMatchFinderBinTree()
77 STDMETHODIMP
CMatchFinderBinTree::Create(UInt32 historySize
, UInt32 keepAddBufferBefore
,
78 UInt32 matchMaxLen
, UInt32 keepAddBufferAfter
)
80 UInt32 sizeReserv
= (historySize
+ keepAddBufferBefore
+
81 matchMaxLen
+ keepAddBufferAfter
) / 2 + 256;
82 if (CLZInWindow::Create(historySize
+ keepAddBufferBefore
,
83 matchMaxLen
+ keepAddBufferAfter
, sizeReserv
))
85 if (historySize
+ 256 > kMaxValForNormalize
)
90 _matchMaxLen
= matchMaxLen
;
91 UInt32 newCyclicBufferSize
= historySize
+ 1;
92 if (_hash
!= 0 && newCyclicBufferSize
== _cyclicBufferSize
)
94 FreeThisClassMemory();
95 _cyclicBufferSize
= newCyclicBufferSize
; // don't change it
96 _hash
= (CIndex
*)BigAlloc((kHashSizeSum
+ _cyclicBufferSize
* 2) * sizeof(CIndex
));
101 return E_OUTOFMEMORY
;
104 static const UInt32 kEmptyHashValue
= 0;
106 STDMETHODIMP
CMatchFinderBinTree::Init(ISequentialInStream
*stream
)
108 RINOK(CLZInWindow::Init(stream
));
109 for(UInt32 i
= 0; i
< kHashSizeSum
; i
++)
110 _hash
[i
] = kEmptyHashValue
;
111 _cyclicBufferPos
= 0;
116 STDMETHODIMP_(void) CMatchFinderBinTree::ReleaseStream()
123 inline UInt32
Hash(const Byte
*pointer
, UInt32
&hash2Value
, UInt32
&hash3Value
)
125 UInt32 temp
= CCRC::Table
[pointer
[0]] ^ pointer
[1];
126 hash2Value
= temp
& (kHash2Size
- 1);
127 hash3Value
= (temp
^ (UInt32(pointer
[2]) << 8)) & (kHash3Size
- 1);
128 return (temp
^ (UInt32(pointer
[2]) << 8) ^ (CCRC::Table
[pointer
[3]] << 5)) &
131 #else // no HASH_ARRAY_3
132 inline UInt32
Hash(const Byte
*pointer
, UInt32
&hash2Value
)
134 hash2Value
= (CCRC::Table
[pointer
[0]] ^ pointer
[1]) & (kHash2Size
- 1);
135 return ((UInt32(pointer
[0]) << 16)) | ((UInt32(pointer
[1]) << 8)) | pointer
[2];
137 #endif // HASH_ARRAY_3
138 #else // no HASH_ARRAY_2
140 inline UInt32
Hash(const Byte
*pointer
)
142 return ((UInt32(pointer
[0]) << 8) ^
143 CCRC::Table
[pointer
[1]] ^ pointer
[2]) & (kHashSize
- 1);
146 inline UInt32
Hash(const Byte
*pointer
)
148 return pointer
[0] ^ (UInt32(pointer
[1]) << 8);
151 #endif // HASH_ARRAY_2
153 STDMETHODIMP_(UInt32
) CMatchFinderBinTree::GetLongestMatch(UInt32
*distances
)
156 if (_pos
+ _matchMaxLen
<= _streamPos
)
157 lenLimit
= _matchMaxLen
;
160 lenLimit
= _streamPos
- _pos
;
161 if(lenLimit
< kNumHashBytes
)
165 UInt32 matchMinPos
= (_pos
> _cyclicBufferSize
) ? (_pos
- _cyclicBufferSize
) : 0;
166 Byte
*cur
= _buffer
+ _pos
;
174 UInt32 hashValue
= Hash(cur
, hash2Value
, hash3Value
);
176 UInt32 hashValue
= Hash(cur
, hash2Value
);
179 UInt32 hashValue
= Hash(cur
);
182 UInt32 curMatch
= _hash
[hashValue
];
184 UInt32 curMatch2
= _hash
[kHash2Offset
+ hash2Value
];
186 UInt32 curMatch3
= _hash
[kHash3Offset
+ hash3Value
];
188 _hash
[kHash2Offset
+ hash2Value
] = _pos
;
189 distances
[2] = 0xFFFFFFFF;
190 if(curMatch2
> matchMinPos
)
191 if (_buffer
[curMatch2
] == cur
[0])
193 distances
[2] = _pos
- curMatch2
- 1;
198 _hash
[kHash3Offset
+ hash3Value
] = _pos
;
199 distances
[3] = 0xFFFFFFFF;
200 if(curMatch3
> matchMinPos
)
201 if (_buffer
[curMatch3
] == cur
[0])
203 distances
[3] = _pos
- curMatch3
- 1;
209 _hash
[hashValue
] = _pos
;
211 CIndex
*son
= _hash
+ kHashSizeSum
;
212 CIndex
*ptr0
= son
+ (_cyclicBufferPos
<< 1) + 1;
213 CIndex
*ptr1
= son
+ (_cyclicBufferPos
<< 1);
215 distances
[kNumHashBytes
] = 0xFFFFFFFF;
217 #ifdef THERE_ARE_DIRECT_HASH_BYTES
218 if (lenLimit
== kNumHashDirectBytes
)
220 if(curMatch
> matchMinPos
)
221 while (maxLen
< kNumHashDirectBytes
)
222 distances
[++maxLen
] = _pos
- curMatch
- 1;
223 // We don't need tree in this case
229 len0
= len1
= kNumHashDirectBytes
;
230 UInt32 count
= _cutValue
;
233 if(curMatch
<= matchMinPos
|| count
-- == 0)
235 *ptr0
= kEmptyHashValue
;
236 *ptr1
= kEmptyHashValue
;
239 Byte
*pb
= _buffer
+ curMatch
;
240 UInt32 len
= MyMin(len0
, len1
);
243 if (pb
[len
] != cur
[len
])
246 while(++len
!= lenLimit
);
248 UInt32 delta
= _pos
- curMatch
;
250 distances
[++maxLen
] = delta
- 1;
252 UInt32 cyclicPos
= (delta
<= _cyclicBufferPos
) ?
253 (_cyclicBufferPos
- delta
):
254 (_cyclicBufferPos
- delta
+ _cyclicBufferSize
);
255 CIndex
*pair
= son
+ (cyclicPos
<< 1);
259 if (pb
[len
] < cur
[len
])
284 if (distances
[4] < distances
[3])
285 distances
[3] = distances
[4];
287 if (distances
[3] < distances
[2])
288 distances
[2] = distances
[3];
293 STDMETHODIMP_(void) CMatchFinderBinTree::DummyLongestMatch()
296 if (_pos
+ _matchMaxLen
<= _streamPos
)
297 lenLimit
= _matchMaxLen
;
300 lenLimit
= _streamPos
- _pos
;
301 if(lenLimit
< kNumHashBytes
)
304 UInt32 matchMinPos
= (_pos
> _cyclicBufferSize
) ? (_pos
- _cyclicBufferSize
) : 0;
305 Byte
*cur
= _buffer
+ _pos
;
311 UInt32 hashValue
= Hash(cur
, hash2Value
, hash3Value
);
312 _hash
[kHash3Offset
+ hash3Value
] = _pos
;
314 UInt32 hashValue
= Hash(cur
, hash2Value
);
316 _hash
[kHash2Offset
+ hash2Value
] = _pos
;
318 UInt32 hashValue
= Hash(cur
);
321 UInt32 curMatch
= _hash
[hashValue
];
322 _hash
[hashValue
] = _pos
;
324 CIndex
*son
= _hash
+ kHashSizeSum
;
325 CIndex
*ptr0
= son
+ (_cyclicBufferPos
<< 1) + 1;
326 CIndex
*ptr1
= son
+ (_cyclicBufferPos
<< 1);
328 #ifdef THERE_ARE_DIRECT_HASH_BYTES
329 if (lenLimit
!= kNumHashDirectBytes
)
333 len0
= len1
= kNumHashDirectBytes
;
334 UInt32 count
= _cutValue
;
337 if(curMatch
<= matchMinPos
|| count
-- == 0)
339 Byte
*pb
= _buffer
+ curMatch
;
340 UInt32 len
= MyMin(len0
, len1
);
343 if (pb
[len
] != cur
[len
])
346 while(++len
!= lenLimit
);
348 UInt32 delta
= _pos
- curMatch
;
349 UInt32 cyclicPos
= (delta
<= _cyclicBufferPos
) ?
350 (_cyclicBufferPos
- delta
):
351 (_cyclicBufferPos
- delta
+ _cyclicBufferSize
);
352 CIndex
*pair
= son
+ (cyclicPos
<< 1);
356 if (pb
[len
] < cur
[len
])
379 *ptr0
= kEmptyHashValue
;
380 *ptr1
= kEmptyHashValue
;
383 void CMatchFinderBinTree::Normalize()
385 UInt32 subValue
= _pos
- _cyclicBufferSize
;
386 CIndex
*items
= _hash
;
387 UInt32 numItems
= (kHashSizeSum
+ _cyclicBufferSize
* 2);
388 for (UInt32 i
= 0; i
< numItems
; i
++)
390 UInt32 value
= items
[i
];
391 if (value
<= subValue
)
392 value
= kEmptyHashValue
;
397 ReduceOffsets(subValue
);
400 STDMETHODIMP
CMatchFinderBinTree::MovePos()
402 if (++_cyclicBufferPos
== _cyclicBufferSize
)
403 _cyclicBufferPos
= 0;
404 RINOK(CLZInWindow::MovePos());
405 if (_pos
== kMaxValForNormalize
)
410 STDMETHODIMP_(Byte
) CMatchFinderBinTree::GetIndexByte(Int32 index
)
411 { return CLZInWindow::GetIndexByte(index
); }
413 STDMETHODIMP_(UInt32
) CMatchFinderBinTree::GetMatchLen(Int32 index
,
414 UInt32 back
, UInt32 limit
)
415 { return CLZInWindow::GetMatchLen(index
, back
, limit
); }
417 STDMETHODIMP_(UInt32
) CMatchFinderBinTree::GetNumAvailableBytes()
418 { return CLZInWindow::GetNumAvailableBytes(); }
420 STDMETHODIMP_(const Byte
*) CMatchFinderBinTree::GetPointerToCurrentPos()
421 { return CLZInWindow::GetPointerToCurrentPos(); }
423 // IMatchFinderSetCallback
424 STDMETHODIMP
CMatchFinderBinTree::SetCallback(IMatchFinderCallback
*callback
)
426 m_Callback
= callback
;
430 void CMatchFinderBinTree::BeforeMoveBlock()
433 m_Callback
->BeforeChangingBufferPos();
434 CLZInWindow::BeforeMoveBlock();
437 void CMatchFinderBinTree::AfterMoveBlock()
440 m_Callback
->AfterChangingBufferPos();
441 CLZInWindow::AfterMoveBlock();