1
0
mirror of https://github.com/lz4/lz4.git synced 2026-10-24 01:48:57 +03:00

Merge pull request #1928 from lz4/mid_lazy_short_match

level 2 : check ip+1 after any short match
This commit is contained in:
Yann Collet
2026-10-22 15:49:14 -07:00
committed by GitHub
3 changed files with 26 additions and 20 deletions

2
NEWS
View File

@@ -29,7 +29,7 @@ perf : `LZ4_FAST_DEC_LOOP` enabled on aarch64 with clang, including Android (up
perf : `LZ4_FAST_DEC_LOOP` enabled on riscv64 when unaligned accesses are fast (`-mno-strict-align`, or a `-mcpu` with fast unaligned accesses)
perf : faster compression with reused contexts, for blocks >= 1 KB : linked frames (up to +69%), `LZ4_resetStream_fast()` (up to +94%)
perf : faster compression of 2-4 KB blocks with `LZ4_attach_dictionary()` (+3% to +30% on Zen 4)
perf : level 2 compresses slightly better (~0.1-0.5%) and faster (~+1-2%)
perf : level 2 compresses better (~0.2-1.5%), at similar speed (-3% to +1% on Zen 4)
perf : faster levels 11 (~+25%) and 12 (~+10%)
perf : `--favor-decSpeed` : faster decompression (~+2-4% at level 12), with fewer sequences
perf : `lz4` multithreaded compression relies on liblz4, reading files in place (memory-mapped, `--[no-]mmap`) : faster at fast levels

View File

@@ -723,35 +723,30 @@ static int LZ4MID_compress (
LZ4MID_addPosition(hash8Table, h8, ipIndex);
matchLength = LZ4MID_countMatch(ip, ipIndex, pos8, matchlimit, prefixPtr, prefixIdx, dictStart, dictIdx);
matchDistance = ipIndex - pos8;
if (matchLength >= MINMATCH) goto _lz4mid_encode_sequence;
}
/* search short match */
{ U32 const h4 = LZ4MID_hash4Ptr(ip);
if (matchLength < MINMATCH) {
U32 const h4 = LZ4MID_hash4Ptr(ip);
U32 const pos4 = hash4Table[h4];
assert(h4 < LZ4MID_HASHTABLESIZE);
assert(pos4 < ipIndex);
LZ4MID_addPosition(hash4Table, h4, ipIndex);
matchLength = LZ4MID_countMatch(ip, ipIndex, pos4, matchlimit, prefixPtr, prefixIdx, dictStart, dictIdx);
matchDistance = ipIndex - pos4;
if ((matchLength >= MINMATCH) && (pos4 >= prefixIdx)) {
/* short match found in prefix, let's just check ip+1 for longer */
}
if (matchLength >= MINMATCH) {
if ((matchLength < 8) && likely(ip < mflimit)) {
/* short match : check ip+1 for longer, except ip itself */
U32 const h8 = LZ4MID_hash8Ptr(ip+1);
U32 const pos8 = hash8Table[h8];
U32 const m2Distance = ipIndex + 1 - pos8;
if ( m2Distance <= LZ4_DISTANCE_MAX
&& pos8 >= prefixIdx /* only search within prefix */
&& likely(ip < mflimit)
) {
const BYTE* const m2Ptr = prefixPtr + (pos8 - prefixIdx);
unsigned ml2 = LZ4_count(ip+1, m2Ptr, matchlimit);
if (ml2 > matchLength) {
LZ4MID_addPosition(hash8Table, h8, ipIndex+1);
ip++;
matchLength = ml2;
matchDistance = m2Distance;
} }
}
if (matchLength >= MINMATCH) goto _lz4mid_encode_sequence;
unsigned const ml2 = LZ4MID_countMatch(ip+1, ipIndex+1, pos8, matchlimit, prefixPtr, prefixIdx, dictStart, dictIdx);
if ((ml2 > matchLength) && (pos8 != ipIndex)) {
LZ4MID_addPosition(hash8Table, h8, ipIndex+1);
ip++;
matchLength = ml2;
matchDistance = ipIndex + 1 - pos8;
} }
goto _lz4mid_encode_sequence;
}
/* no match found in prefix nor extDict : search into the attached dictionary */
if ( (dict == usingDictCtxHc)

View File

@@ -1734,6 +1734,17 @@ static void FUZ_unitTests(int compressionLevel)
}
DISPLAYLEVEL(3, "OK \n");
DISPLAYLEVEL(3, "level 2 : the match tested at ip+1 must not be ip itself, inside runs : ");
{ char runs[2 + 4096]; /* 0xFF 0x00, then runs of 10 x 0xFF and 10 x 0x00 */
int i;
runs[0] = (char)0xFF; runs[1] = 0;
for (i = 0; i < 4096; i++) runs[2 + i] = (i % 20) < 10 ? (char)0xFF : 0;
result = LZ4_compress_HC(runs, testCompressed, (int)sizeof(runs), (int)testCompressedSize, 2);
/* ~1.6 KB (one literal and one offset 1 per run), instead of < 50 bytes */
FUZ_CHECKTEST(result <= 0 || result > 100, "%i bytes", result);
}
DISPLAYLEVEL(3, "OK \n");
/* saveDictHC test #926 */
DISPLAYLEVEL(3, "saveDictHC test #926 : ");
{ LZ4_streamHC_t* const ctx = LZ4_initStreamHC(&sHC, sizeof(sHC));