2 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
5 * This source code is licensed under both the BSD-style license (found in the
6 * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7 * in the COPYING file in the root directory of this source tree).
8 * You may select, at your option, one of the above-listed licenses.
11 #include "zstd_compress_internal.h"
12 #include "zstd_lazy.h"
15 /*-*************************************
17 ***************************************/
18 /** ZSTD_insertBt1() : add one or multiple positions to tree.
19 * ip : assumed <= iend-8 .
20 * @return : nb of positions added */
21 static U32 ZSTD_insertBt1(ZSTD_CCtx* zc,
22 const BYTE* const ip, const BYTE* const iend,
23 U32 nbCompares, U32 const mls, U32 const extDict)
25 U32* const hashTable = zc->hashTable;
26 U32 const hashLog = zc->appliedParams.cParams.hashLog;
27 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
28 U32* const bt = zc->chainTable;
29 U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
30 U32 const btMask = (1 << btLog) - 1;
31 U32 matchIndex = hashTable[h];
32 size_t commonLengthSmaller=0, commonLengthLarger=0;
33 const BYTE* const base = zc->base;
34 const BYTE* const dictBase = zc->dictBase;
35 const U32 dictLimit = zc->dictLimit;
36 const BYTE* const dictEnd = dictBase + dictLimit;
37 const BYTE* const prefixStart = base + dictLimit;
39 const U32 current = (U32)(ip-base);
40 const U32 btLow = btMask >= current ? 0 : current - btMask;
41 U32* smallerPtr = bt + 2*(current&btMask);
42 U32* largerPtr = smallerPtr + 1;
43 U32 dummy32; /* to be nullified at the end */
44 U32 const windowLow = zc->lowLimit;
45 U32 matchEndIdx = current+8+1;
46 size_t bestLength = 8;
48 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
49 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
50 predictedSmall += (predictedSmall>0);
51 predictedLarge += (predictedLarge>0);
52 #endif /* ZSTD_C_PREDICT */
54 DEBUGLOG(8, "ZSTD_insertBt1 (%u)", current);
56 assert(ip <= iend-8); /* required for h calculation */
57 hashTable[h] = current; /* Update Hash Table */
59 while (nbCompares-- && (matchIndex > windowLow)) {
60 U32* const nextPtr = bt + 2*(matchIndex & btMask);
61 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
62 assert(matchIndex < current);
64 #ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
65 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
66 if (matchIndex == predictedSmall) {
67 /* no need to check length, result known */
68 *smallerPtr = matchIndex;
69 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
70 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
71 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
72 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
75 if (matchIndex == predictedLarge) {
76 *largerPtr = matchIndex;
77 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
79 matchIndex = nextPtr[0];
80 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
85 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
86 assert(matchIndex+matchLength >= dictLimit); /* might be wrong if extDict is incorrectly set to 0 */
87 match = base + matchIndex;
88 matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
90 match = dictBase + matchIndex;
91 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
92 if (matchIndex+matchLength >= dictLimit)
93 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
96 if (matchLength > bestLength) {
97 bestLength = matchLength;
98 if (matchLength > matchEndIdx - matchIndex)
99 matchEndIdx = matchIndex + (U32)matchLength;
102 if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */
103 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */
106 if (match[matchLength] < ip[matchLength]) { /* necessarily within buffer */
107 /* match is smaller than current */
108 *smallerPtr = matchIndex; /* update smaller idx */
109 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
110 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop searching */
111 smallerPtr = nextPtr+1; /* new "candidate" => larger than match, which was smaller than target */
112 matchIndex = nextPtr[1]; /* new matchIndex, larger than previous and closer to current */
114 /* match is larger than current */
115 *largerPtr = matchIndex;
116 commonLengthLarger = matchLength;
117 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop searching */
119 matchIndex = nextPtr[0];
122 *smallerPtr = *largerPtr = 0;
123 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
124 assert(matchEndIdx > current + 8);
125 return matchEndIdx - (current + 8);
128 FORCE_INLINE_TEMPLATE
129 void ZSTD_updateTree_internal(ZSTD_CCtx* zc,
130 const BYTE* const ip, const BYTE* const iend,
131 const U32 nbCompares, const U32 mls, const U32 extDict)
133 const BYTE* const base = zc->base;
134 U32 const target = (U32)(ip - base);
135 U32 idx = zc->nextToUpdate;
136 DEBUGLOG(7, "ZSTD_updateTree_internal, from %u to %u (extDict:%u)",
137 idx, target, extDict);
140 idx += ZSTD_insertBt1(zc, base+idx, iend, nbCompares, mls, extDict);
141 zc->nextToUpdate = target;
144 void ZSTD_updateTree(ZSTD_CCtx* zc,
145 const BYTE* const ip, const BYTE* const iend,
146 const U32 nbCompares, const U32 mls)
148 ZSTD_updateTree_internal(zc, ip, iend, nbCompares, mls, 0 /*extDict*/);
151 void ZSTD_updateTree_extDict(ZSTD_CCtx* zc,
152 const BYTE* const ip, const BYTE* const iend,
153 const U32 nbCompares, const U32 mls)
155 ZSTD_updateTree_internal(zc, ip, iend, nbCompares, mls, 1 /*extDict*/);
159 static size_t ZSTD_insertBtAndFindBestMatch (
161 const BYTE* const ip, const BYTE* const iend,
163 U32 nbCompares, const U32 mls,
166 U32* const hashTable = zc->hashTable;
167 U32 const hashLog = zc->appliedParams.cParams.hashLog;
168 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
169 U32* const bt = zc->chainTable;
170 U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
171 U32 const btMask = (1 << btLog) - 1;
172 U32 matchIndex = hashTable[h];
173 size_t commonLengthSmaller=0, commonLengthLarger=0;
174 const BYTE* const base = zc->base;
175 const BYTE* const dictBase = zc->dictBase;
176 const U32 dictLimit = zc->dictLimit;
177 const BYTE* const dictEnd = dictBase + dictLimit;
178 const BYTE* const prefixStart = base + dictLimit;
179 const U32 current = (U32)(ip-base);
180 const U32 btLow = btMask >= current ? 0 : current - btMask;
181 const U32 windowLow = zc->lowLimit;
182 U32* smallerPtr = bt + 2*(current&btMask);
183 U32* largerPtr = bt + 2*(current&btMask) + 1;
184 U32 matchEndIdx = current+8+1;
185 U32 dummy32; /* to be nullified at the end */
186 size_t bestLength = 0;
188 assert(ip <= iend-8); /* required for h calculation */
189 hashTable[h] = current; /* Update Hash Table */
191 while (nbCompares-- && (matchIndex > windowLow)) {
192 U32* const nextPtr = bt + 2*(matchIndex & btMask);
193 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
196 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
197 match = base + matchIndex;
198 matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
200 match = dictBase + matchIndex;
201 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
202 if (matchIndex+matchLength >= dictLimit)
203 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
206 if (matchLength > bestLength) {
207 if (matchLength > matchEndIdx - matchIndex)
208 matchEndIdx = matchIndex + (U32)matchLength;
209 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
210 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
211 if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */
212 break; /* drop, to guarantee consistency (miss a little bit of compression) */
216 if (match[matchLength] < ip[matchLength]) {
217 /* match is smaller than current */
218 *smallerPtr = matchIndex; /* update smaller idx */
219 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
220 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
221 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
222 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
224 /* match is larger than current */
225 *largerPtr = matchIndex;
226 commonLengthLarger = matchLength;
227 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
229 matchIndex = nextPtr[0];
232 *smallerPtr = *largerPtr = 0;
234 assert(matchEndIdx > current+8);
235 zc->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
240 /** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
241 static size_t ZSTD_BtFindBestMatch (
243 const BYTE* const ip, const BYTE* const iLimit,
245 const U32 maxNbAttempts, const U32 mls)
247 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
248 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
249 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
253 static size_t ZSTD_BtFindBestMatch_selectMLS (
254 ZSTD_CCtx* zc, /* Index table will be updated */
255 const BYTE* ip, const BYTE* const iLimit,
257 const U32 maxNbAttempts, const U32 matchLengthSearch)
259 switch(matchLengthSearch)
261 default : /* includes case 3 */
262 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
263 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
265 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
270 /** Tree updater, providing best match */
271 static size_t ZSTD_BtFindBestMatch_extDict (
273 const BYTE* const ip, const BYTE* const iLimit,
275 const U32 maxNbAttempts, const U32 mls)
277 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
278 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
279 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
283 static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
284 ZSTD_CCtx* zc, /* Index table will be updated */
285 const BYTE* ip, const BYTE* const iLimit,
287 const U32 maxNbAttempts, const U32 matchLengthSearch)
289 switch(matchLengthSearch)
291 default : /* includes case 3 */
292 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
293 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
295 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
301 /* *********************************
303 ***********************************/
304 #define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
306 /* Update chains up to ip (excluded)
307 Assumption : always within prefix (i.e. not within extDict) */
308 U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
310 U32* const hashTable = zc->hashTable;
311 const U32 hashLog = zc->appliedParams.cParams.hashLog;
312 U32* const chainTable = zc->chainTable;
313 const U32 chainMask = (1 << zc->appliedParams.cParams.chainLog) - 1;
314 const BYTE* const base = zc->base;
315 const U32 target = (U32)(ip - base);
316 U32 idx = zc->nextToUpdate;
318 while(idx < target) { /* catch up */
319 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
320 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
325 zc->nextToUpdate = target;
326 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
330 /* inlining is important to hardwire a hot branch (template emulation) */
331 FORCE_INLINE_TEMPLATE
332 size_t ZSTD_HcFindBestMatch_generic (
333 ZSTD_CCtx* zc, /* Index table will be updated */
334 const BYTE* const ip, const BYTE* const iLimit,
336 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
338 U32* const chainTable = zc->chainTable;
339 const U32 chainSize = (1 << zc->appliedParams.cParams.chainLog);
340 const U32 chainMask = chainSize-1;
341 const BYTE* const base = zc->base;
342 const BYTE* const dictBase = zc->dictBase;
343 const U32 dictLimit = zc->dictLimit;
344 const BYTE* const prefixStart = base + dictLimit;
345 const BYTE* const dictEnd = dictBase + dictLimit;
346 const U32 lowLimit = zc->lowLimit;
347 const U32 current = (U32)(ip-base);
348 const U32 minChain = current > chainSize ? current - chainSize : 0;
349 int nbAttempts=maxNbAttempts;
352 /* HC4 match finder */
353 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
355 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
357 if ((!extDict) || matchIndex >= dictLimit) {
358 const BYTE* const match = base + matchIndex;
359 if (match[ml] == ip[ml]) /* potentially better */
360 currentMl = ZSTD_count(ip, match, iLimit);
362 const BYTE* const match = dictBase + matchIndex;
363 assert(match+4 <= dictEnd);
364 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
365 currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
368 /* save best solution */
369 if (currentMl > ml) {
371 *offsetPtr = current - matchIndex + ZSTD_REP_MOVE;
372 if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
375 if (matchIndex <= minChain) break;
376 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
383 FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS (
385 const BYTE* ip, const BYTE* const iLimit,
387 const U32 maxNbAttempts, const U32 matchLengthSearch)
389 switch(matchLengthSearch)
391 default : /* includes case 3 */
392 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
393 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
395 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
400 FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
402 const BYTE* ip, const BYTE* const iLimit,
403 size_t* const offsetPtr,
404 U32 const maxNbAttempts, U32 const matchLengthSearch)
406 switch(matchLengthSearch)
408 default : /* includes case 3 */
409 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
410 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
412 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
417 /* *******************************
418 * Common parser - lazy strategy
419 *********************************/
420 FORCE_INLINE_TEMPLATE
421 size_t ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
422 const void* src, size_t srcSize,
423 const U32 searchMethod, const U32 depth)
425 seqStore_t* seqStorePtr = &(ctx->seqStore);
426 const BYTE* const istart = (const BYTE*)src;
427 const BYTE* ip = istart;
428 const BYTE* anchor = istart;
429 const BYTE* const iend = istart + srcSize;
430 const BYTE* const ilimit = iend - 8;
431 const BYTE* const base = ctx->base + ctx->dictLimit;
433 U32 const maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
434 U32 const mls = ctx->appliedParams.cParams.searchLength;
436 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
438 U32 maxNbAttempts, U32 matchLengthSearch);
439 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
440 U32 offset_1 = seqStorePtr->rep[0], offset_2 = seqStorePtr->rep[1], savedOffset=0;
444 ctx->nextToUpdate3 = ctx->nextToUpdate;
445 { U32 const maxRep = (U32)(ip-base);
446 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
447 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
451 while (ip < ilimit) {
452 size_t matchLength=0;
454 const BYTE* start=ip+1;
457 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
458 /* repcode : we take it */
459 matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
460 if (depth==0) goto _storeSequence;
463 /* first search (depth 0) */
464 { size_t offsetFound = 99999999;
465 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
466 if (ml2 > matchLength)
467 matchLength = ml2, start = ip, offset=offsetFound;
470 if (matchLength < 4) {
471 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
475 /* let's try to find a better solution */
479 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
480 size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
481 int const gain2 = (int)(mlRep * 3);
482 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
483 if ((mlRep >= 4) && (gain2 > gain1))
484 matchLength = mlRep, offset = 0, start = ip;
486 { size_t offset2=99999999;
487 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
488 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
489 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
490 if ((ml2 >= 4) && (gain2 > gain1)) {
491 matchLength = ml2, offset = offset2, start = ip;
492 continue; /* search a better one */
495 /* let's find an even better one */
496 if ((depth==2) && (ip<ilimit)) {
498 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
499 size_t const ml2 = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
500 int const gain2 = (int)(ml2 * 4);
501 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
502 if ((ml2 >= 4) && (gain2 > gain1))
503 matchLength = ml2, offset = 0, start = ip;
505 { size_t offset2=99999999;
506 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
507 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
508 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
509 if ((ml2 >= 4) && (gain2 > gain1)) {
510 matchLength = ml2, offset = offset2, start = ip;
513 break; /* nothing found : store previous solution */
517 * start[-offset+ZSTD_REP_MOVE-1] is undefined behavior.
518 * (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which
519 * overflows the pointer, which is undefined behavior.
523 while ( ((start > anchor) & (start - (offset-ZSTD_REP_MOVE) > base))
524 && (start[-1] == (start-(offset-ZSTD_REP_MOVE))[-1]) ) /* only search for offset within prefix */
525 { start--; matchLength++; }
526 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
530 { size_t const litLength = start - anchor;
531 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
532 anchor = ip = start + matchLength;
535 /* check immediate repcode */
536 while ( ((ip <= ilimit) & (offset_2>0))
537 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
539 matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
540 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
541 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
544 continue; /* faster when present ... (?) */
547 /* Save reps for next block */
548 seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
549 seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
551 /* Return the last literals size */
552 return iend - anchor;
556 size_t ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
558 return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
561 size_t ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
563 return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
566 size_t ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
568 return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
571 size_t ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
573 return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
577 FORCE_INLINE_TEMPLATE
578 size_t ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
579 const void* src, size_t srcSize,
580 const U32 searchMethod, const U32 depth)
582 seqStore_t* seqStorePtr = &(ctx->seqStore);
583 const BYTE* const istart = (const BYTE*)src;
584 const BYTE* ip = istart;
585 const BYTE* anchor = istart;
586 const BYTE* const iend = istart + srcSize;
587 const BYTE* const ilimit = iend - 8;
588 const BYTE* const base = ctx->base;
589 const U32 dictLimit = ctx->dictLimit;
590 const U32 lowestIndex = ctx->lowLimit;
591 const BYTE* const prefixStart = base + dictLimit;
592 const BYTE* const dictBase = ctx->dictBase;
593 const BYTE* const dictEnd = dictBase + dictLimit;
594 const BYTE* const dictStart = dictBase + ctx->lowLimit;
596 const U32 maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
597 const U32 mls = ctx->appliedParams.cParams.searchLength;
599 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
601 U32 maxNbAttempts, U32 matchLengthSearch);
602 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
604 U32 offset_1 = seqStorePtr->rep[0], offset_2 = seqStorePtr->rep[1];
607 ctx->nextToUpdate3 = ctx->nextToUpdate;
608 ip += (ip == prefixStart);
611 while (ip < ilimit) {
612 size_t matchLength=0;
614 const BYTE* start=ip+1;
615 U32 current = (U32)(ip-base);
618 { const U32 repIndex = (U32)(current+1 - offset_1);
619 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
620 const BYTE* const repMatch = repBase + repIndex;
621 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
622 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
623 /* repcode detected we should take it */
624 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
625 matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repEnd, prefixStart) + 4;
626 if (depth==0) goto _storeSequence;
629 /* first search (depth 0) */
630 { size_t offsetFound = 99999999;
631 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
632 if (ml2 > matchLength)
633 matchLength = ml2, start = ip, offset=offsetFound;
636 if (matchLength < 4) {
637 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
641 /* let's try to find a better solution */
648 const U32 repIndex = (U32)(current - offset_1);
649 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
650 const BYTE* const repMatch = repBase + repIndex;
651 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
652 if (MEM_read32(ip) == MEM_read32(repMatch)) {
653 /* repcode detected */
654 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
655 size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
656 int const gain2 = (int)(repLength * 3);
657 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
658 if ((repLength >= 4) && (gain2 > gain1))
659 matchLength = repLength, offset = 0, start = ip;
662 /* search match, depth 1 */
663 { size_t offset2=99999999;
664 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
665 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
666 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
667 if ((ml2 >= 4) && (gain2 > gain1)) {
668 matchLength = ml2, offset = offset2, start = ip;
669 continue; /* search a better one */
672 /* let's find an even better one */
673 if ((depth==2) && (ip<ilimit)) {
678 const U32 repIndex = (U32)(current - offset_1);
679 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
680 const BYTE* const repMatch = repBase + repIndex;
681 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
682 if (MEM_read32(ip) == MEM_read32(repMatch)) {
683 /* repcode detected */
684 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
685 size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
686 int const gain2 = (int)(repLength * 4);
687 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
688 if ((repLength >= 4) && (gain2 > gain1))
689 matchLength = repLength, offset = 0, start = ip;
692 /* search match, depth 2 */
693 { size_t offset2=99999999;
694 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
695 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
696 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
697 if ((ml2 >= 4) && (gain2 > gain1)) {
698 matchLength = ml2, offset = offset2, start = ip;
701 break; /* nothing found : store previous solution */
706 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
707 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
708 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
709 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
710 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
715 { size_t const litLength = start - anchor;
716 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
717 anchor = ip = start + matchLength;
720 /* check immediate repcode */
721 while (ip <= ilimit) {
722 const U32 repIndex = (U32)((ip-base) - offset_2);
723 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
724 const BYTE* const repMatch = repBase + repIndex;
725 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
726 if (MEM_read32(ip) == MEM_read32(repMatch)) {
727 /* repcode detected we should take it */
728 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
729 matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
730 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
731 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
734 continue; /* faster when present ... (?) */
739 /* Save reps for next block */
740 seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
742 /* Return the last literals size */
743 return iend - anchor;
747 size_t ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
749 return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
752 size_t ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
754 return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
757 size_t ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
759 return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
762 size_t ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
764 return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);