xref: /freebsd/sys/contrib/zstd/lib/compress/zstd_opt.c (revision 19fcbaf1424b464269f1a7621fab747bb75afc36)
10c16b537SWarner Losh /*
20c16b537SWarner Losh  * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
30c16b537SWarner Losh  * All rights reserved.
40c16b537SWarner Losh  *
50c16b537SWarner Losh  * This source code is licensed under both the BSD-style license (found in the
60c16b537SWarner Losh  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
70c16b537SWarner Losh  * in the COPYING file in the root directory of this source tree).
80c16b537SWarner Losh  * You may select, at your option, one of the above-listed licenses.
90c16b537SWarner Losh  */
100c16b537SWarner Losh 
11052d3c12SConrad Meyer #include "zstd_compress_internal.h"
120c16b537SWarner Losh #include "zstd_opt.h"
130c16b537SWarner Losh 
140c16b537SWarner Losh 
15052d3c12SConrad Meyer #define ZSTD_LITFREQ_ADD    2   /* scaling factor for litFreq, so that frequencies adapt faster to new stats. Also used for matchSum (?) */
16052d3c12SConrad Meyer #define ZSTD_FREQ_DIV       4   /* log factor when using previous stats to init next stats */
170c16b537SWarner Losh #define ZSTD_MAX_PRICE     (1<<30)
180c16b537SWarner Losh 
19052d3c12SConrad Meyer 
200c16b537SWarner Losh /*-*************************************
210c16b537SWarner Losh *  Price functions for optimal parser
220c16b537SWarner Losh ***************************************/
230c16b537SWarner Losh static void ZSTD_setLog2Prices(optState_t* optPtr)
240c16b537SWarner Losh {
250c16b537SWarner Losh     optPtr->log2litSum = ZSTD_highbit32(optPtr->litSum+1);
26052d3c12SConrad Meyer     optPtr->log2litLengthSum = ZSTD_highbit32(optPtr->litLengthSum+1);
27052d3c12SConrad Meyer     optPtr->log2matchLengthSum = ZSTD_highbit32(optPtr->matchLengthSum+1);
280c16b537SWarner Losh     optPtr->log2offCodeSum = ZSTD_highbit32(optPtr->offCodeSum+1);
290c16b537SWarner Losh }
300c16b537SWarner Losh 
310c16b537SWarner Losh 
32052d3c12SConrad Meyer static void ZSTD_rescaleFreqs(optState_t* const optPtr,
33052d3c12SConrad Meyer                               const BYTE* const src, size_t const srcSize)
340c16b537SWarner Losh {
350c16b537SWarner Losh     optPtr->staticPrices = 0;
360c16b537SWarner Losh 
37052d3c12SConrad Meyer     if (optPtr->litLengthSum == 0) {  /* first init */
38052d3c12SConrad Meyer         unsigned u;
390c16b537SWarner Losh         if (srcSize <= 1024) optPtr->staticPrices = 1;
400c16b537SWarner Losh 
410c16b537SWarner Losh         assert(optPtr->litFreq!=NULL);
420c16b537SWarner Losh         for (u=0; u<=MaxLit; u++)
430c16b537SWarner Losh             optPtr->litFreq[u] = 0;
440c16b537SWarner Losh         for (u=0; u<srcSize; u++)
450c16b537SWarner Losh             optPtr->litFreq[src[u]]++;
460c16b537SWarner Losh         optPtr->litSum = 0;
470c16b537SWarner Losh         for (u=0; u<=MaxLit; u++) {
480c16b537SWarner Losh             optPtr->litFreq[u] = 1 + (optPtr->litFreq[u] >> ZSTD_FREQ_DIV);
490c16b537SWarner Losh             optPtr->litSum += optPtr->litFreq[u];
500c16b537SWarner Losh         }
51052d3c12SConrad Meyer 
520c16b537SWarner Losh         for (u=0; u<=MaxLL; u++)
530c16b537SWarner Losh             optPtr->litLengthFreq[u] = 1;
54052d3c12SConrad Meyer         optPtr->litLengthSum = MaxLL+1;
550c16b537SWarner Losh         for (u=0; u<=MaxML; u++)
560c16b537SWarner Losh             optPtr->matchLengthFreq[u] = 1;
57052d3c12SConrad Meyer         optPtr->matchLengthSum = MaxML+1;
580c16b537SWarner Losh         for (u=0; u<=MaxOff; u++)
590c16b537SWarner Losh             optPtr->offCodeFreq[u] = 1;
60052d3c12SConrad Meyer         optPtr->offCodeSum = (MaxOff+1);
610c16b537SWarner Losh 
62052d3c12SConrad Meyer     } else {
63052d3c12SConrad Meyer         unsigned u;
64052d3c12SConrad Meyer 
65052d3c12SConrad Meyer         optPtr->litSum = 0;
660c16b537SWarner Losh         for (u=0; u<=MaxLit; u++) {
670c16b537SWarner Losh             optPtr->litFreq[u] = 1 + (optPtr->litFreq[u] >> (ZSTD_FREQ_DIV+1));
680c16b537SWarner Losh             optPtr->litSum += optPtr->litFreq[u];
690c16b537SWarner Losh         }
70052d3c12SConrad Meyer         optPtr->litLengthSum = 0;
710c16b537SWarner Losh         for (u=0; u<=MaxLL; u++) {
720c16b537SWarner Losh             optPtr->litLengthFreq[u] = 1 + (optPtr->litLengthFreq[u]>>(ZSTD_FREQ_DIV+1));
730c16b537SWarner Losh             optPtr->litLengthSum += optPtr->litLengthFreq[u];
740c16b537SWarner Losh         }
75052d3c12SConrad Meyer         optPtr->matchLengthSum = 0;
760c16b537SWarner Losh         for (u=0; u<=MaxML; u++) {
770c16b537SWarner Losh             optPtr->matchLengthFreq[u] = 1 + (optPtr->matchLengthFreq[u]>>ZSTD_FREQ_DIV);
780c16b537SWarner Losh             optPtr->matchLengthSum += optPtr->matchLengthFreq[u];
790c16b537SWarner Losh         }
80052d3c12SConrad Meyer         optPtr->offCodeSum = 0;
810c16b537SWarner Losh         for (u=0; u<=MaxOff; u++) {
820c16b537SWarner Losh             optPtr->offCodeFreq[u] = 1 + (optPtr->offCodeFreq[u]>>ZSTD_FREQ_DIV);
830c16b537SWarner Losh             optPtr->offCodeSum += optPtr->offCodeFreq[u];
840c16b537SWarner Losh         }
850c16b537SWarner Losh     }
860c16b537SWarner Losh 
870c16b537SWarner Losh     ZSTD_setLog2Prices(optPtr);
880c16b537SWarner Losh }
890c16b537SWarner Losh 
900c16b537SWarner Losh 
91052d3c12SConrad Meyer /* ZSTD_rawLiteralsCost() :
92052d3c12SConrad Meyer  * cost of literals (only) in given segment (which length can be null)
93052d3c12SConrad Meyer  * does not include cost of literalLength symbol */
94052d3c12SConrad Meyer static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength,
95052d3c12SConrad Meyer                                 const optState_t* const optPtr)
960c16b537SWarner Losh {
97052d3c12SConrad Meyer     if (optPtr->staticPrices) return (litLength*6);  /* 6 bit per literal - no statistic used */
98052d3c12SConrad Meyer     if (litLength == 0) return 0;
990c16b537SWarner Losh 
1000c16b537SWarner Losh     /* literals */
101052d3c12SConrad Meyer     {   U32 u;
102052d3c12SConrad Meyer         U32 cost = litLength * optPtr->log2litSum;
1030c16b537SWarner Losh         for (u=0; u < litLength; u++)
104052d3c12SConrad Meyer             cost -= ZSTD_highbit32(optPtr->litFreq[literals[u]]+1);
105052d3c12SConrad Meyer         return cost;
106052d3c12SConrad Meyer     }
107052d3c12SConrad Meyer }
1080c16b537SWarner Losh 
109052d3c12SConrad Meyer /* ZSTD_litLengthPrice() :
110052d3c12SConrad Meyer  * cost of literalLength symbol */
111052d3c12SConrad Meyer static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optPtr)
112052d3c12SConrad Meyer {
113052d3c12SConrad Meyer     if (optPtr->staticPrices) return ZSTD_highbit32((U32)litLength+1);
1140c16b537SWarner Losh 
1150c16b537SWarner Losh     /* literal Length */
116052d3c12SConrad Meyer     {   U32 const llCode = ZSTD_LLcode(litLength);
117052d3c12SConrad Meyer         U32 const price = LL_bits[llCode] + optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[llCode]+1);
1180c16b537SWarner Losh         return price;
1190c16b537SWarner Losh     }
120052d3c12SConrad Meyer }
1210c16b537SWarner Losh 
122052d3c12SConrad Meyer /* ZSTD_litLengthPrice() :
123052d3c12SConrad Meyer  * cost of the literal part of a sequence,
124052d3c12SConrad Meyer  * including literals themselves, and literalLength symbol */
125052d3c12SConrad Meyer static U32 ZSTD_fullLiteralsCost(const BYTE* const literals, U32 const litLength,
126052d3c12SConrad Meyer                                  const optState_t* const optPtr)
1270c16b537SWarner Losh {
128052d3c12SConrad Meyer     return ZSTD_rawLiteralsCost(literals, litLength, optPtr)
129052d3c12SConrad Meyer          + ZSTD_litLengthPrice(litLength, optPtr);
130052d3c12SConrad Meyer }
1310c16b537SWarner Losh 
132052d3c12SConrad Meyer /* ZSTD_litLengthContribution() :
133052d3c12SConrad Meyer  * @return ( cost(litlength) - cost(0) )
134052d3c12SConrad Meyer  * this value can then be added to rawLiteralsCost()
135052d3c12SConrad Meyer  * to provide a cost which is directly comparable to a match ending at same position */
136052d3c12SConrad Meyer static int ZSTD_litLengthContribution(U32 const litLength, const optState_t* const optPtr)
137052d3c12SConrad Meyer {
138052d3c12SConrad Meyer     if (optPtr->staticPrices) return ZSTD_highbit32(litLength+1);
139052d3c12SConrad Meyer 
140052d3c12SConrad Meyer     /* literal Length */
141052d3c12SConrad Meyer     {   U32 const llCode = ZSTD_LLcode(litLength);
142052d3c12SConrad Meyer         int const contribution = LL_bits[llCode]
143052d3c12SConrad Meyer                         + ZSTD_highbit32(optPtr->litLengthFreq[0]+1)
144052d3c12SConrad Meyer                         - ZSTD_highbit32(optPtr->litLengthFreq[llCode]+1);
145052d3c12SConrad Meyer #if 1
146052d3c12SConrad Meyer         return contribution;
147052d3c12SConrad Meyer #else
148052d3c12SConrad Meyer         return MAX(0, contribution); /* sometimes better, sometimes not ... */
149052d3c12SConrad Meyer #endif
150052d3c12SConrad Meyer     }
151052d3c12SConrad Meyer }
152052d3c12SConrad Meyer 
153052d3c12SConrad Meyer /* ZSTD_literalsContribution() :
154052d3c12SConrad Meyer  * creates a fake cost for the literals part of a sequence
155052d3c12SConrad Meyer  * which can be compared to the ending cost of a match
156052d3c12SConrad Meyer  * should a new match start at this position */
157052d3c12SConrad Meyer static int ZSTD_literalsContribution(const BYTE* const literals, U32 const litLength,
158052d3c12SConrad Meyer                                      const optState_t* const optPtr)
159052d3c12SConrad Meyer {
160052d3c12SConrad Meyer     int const contribution = ZSTD_rawLiteralsCost(literals, litLength, optPtr)
161052d3c12SConrad Meyer                            + ZSTD_litLengthContribution(litLength, optPtr);
162052d3c12SConrad Meyer     return contribution;
163052d3c12SConrad Meyer }
164052d3c12SConrad Meyer 
165052d3c12SConrad Meyer /* ZSTD_getMatchPrice() :
166052d3c12SConrad Meyer  * Provides the cost of the match part (offset + matchLength) of a sequence
167052d3c12SConrad Meyer  * Must be combined with ZSTD_fullLiteralsCost() to get the full cost of a sequence.
168052d3c12SConrad Meyer  * optLevel: when <2, favors small offset for decompression speed (improved cache efficiency) */
169052d3c12SConrad Meyer FORCE_INLINE_TEMPLATE U32 ZSTD_getMatchPrice(
170052d3c12SConrad Meyer                                     U32 const offset, U32 const matchLength,
171052d3c12SConrad Meyer                                     const optState_t* const optPtr,
172052d3c12SConrad Meyer                                     int const optLevel)
173052d3c12SConrad Meyer {
174052d3c12SConrad Meyer     U32 price;
175052d3c12SConrad Meyer     U32 const offCode = ZSTD_highbit32(offset+1);
176052d3c12SConrad Meyer     U32 const mlBase = matchLength - MINMATCH;
177052d3c12SConrad Meyer     assert(matchLength >= MINMATCH);
178052d3c12SConrad Meyer 
179052d3c12SConrad Meyer     if (optPtr->staticPrices)  /* fixed scheme, do not use statistics */
180052d3c12SConrad Meyer         return ZSTD_highbit32((U32)mlBase+1) + 16 + offCode;
1810c16b537SWarner Losh 
1820c16b537SWarner Losh     price = offCode + optPtr->log2offCodeSum - ZSTD_highbit32(optPtr->offCodeFreq[offCode]+1);
183052d3c12SConrad Meyer     if ((optLevel<2) /*static*/ && offCode >= 20) price += (offCode-19)*2; /* handicap for long distance offsets, favor decompression speed */
1840c16b537SWarner Losh 
1850c16b537SWarner Losh     /* match Length */
186052d3c12SConrad Meyer     {   U32 const mlCode = ZSTD_MLcode(mlBase);
1870c16b537SWarner Losh         price += ML_bits[mlCode] + optPtr->log2matchLengthSum - ZSTD_highbit32(optPtr->matchLengthFreq[mlCode]+1);
1880c16b537SWarner Losh     }
1890c16b537SWarner Losh 
190052d3c12SConrad Meyer     DEBUGLOG(8, "ZSTD_getMatchPrice(ml:%u) = %u", matchLength, price);
191052d3c12SConrad Meyer     return price;
1920c16b537SWarner Losh }
1930c16b537SWarner Losh 
194052d3c12SConrad Meyer static void ZSTD_updateStats(optState_t* const optPtr,
195052d3c12SConrad Meyer                              U32 litLength, const BYTE* literals,
196052d3c12SConrad Meyer                              U32 offsetCode, U32 matchLength)
1970c16b537SWarner Losh {
1980c16b537SWarner Losh     /* literals */
199052d3c12SConrad Meyer     {   U32 u;
2000c16b537SWarner Losh         for (u=0; u < litLength; u++)
2010c16b537SWarner Losh             optPtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD;
202052d3c12SConrad Meyer         optPtr->litSum += litLength*ZSTD_LITFREQ_ADD;
203052d3c12SConrad Meyer     }
2040c16b537SWarner Losh 
2050c16b537SWarner Losh     /* literal Length */
206052d3c12SConrad Meyer     {   U32 const llCode = ZSTD_LLcode(litLength);
2070c16b537SWarner Losh         optPtr->litLengthFreq[llCode]++;
2080c16b537SWarner Losh         optPtr->litLengthSum++;
2090c16b537SWarner Losh     }
2100c16b537SWarner Losh 
211052d3c12SConrad Meyer     /* match offset code (0-2=>repCode; 3+=>offset+2) */
212052d3c12SConrad Meyer     {   U32 const offCode = ZSTD_highbit32(offsetCode+1);
213052d3c12SConrad Meyer         assert(offCode <= MaxOff);
2140c16b537SWarner Losh         optPtr->offCodeFreq[offCode]++;
215052d3c12SConrad Meyer         optPtr->offCodeSum++;
2160c16b537SWarner Losh     }
2170c16b537SWarner Losh 
2180c16b537SWarner Losh     /* match Length */
219052d3c12SConrad Meyer     {   U32 const mlBase = matchLength - MINMATCH;
220052d3c12SConrad Meyer         U32 const mlCode = ZSTD_MLcode(mlBase);
2210c16b537SWarner Losh         optPtr->matchLengthFreq[mlCode]++;
2220c16b537SWarner Losh         optPtr->matchLengthSum++;
2230c16b537SWarner Losh     }
2240c16b537SWarner Losh }
2250c16b537SWarner Losh 
2260c16b537SWarner Losh 
227052d3c12SConrad Meyer /* ZSTD_readMINMATCH() :
228052d3c12SConrad Meyer  * function safe only for comparisons
229052d3c12SConrad Meyer  * assumption : memPtr must be at least 4 bytes before end of buffer */
230052d3c12SConrad Meyer MEM_STATIC U32 ZSTD_readMINMATCH(const void* memPtr, U32 length)
2310c16b537SWarner Losh {
2320c16b537SWarner Losh     switch (length)
2330c16b537SWarner Losh     {
2340c16b537SWarner Losh     default :
2350c16b537SWarner Losh     case 4 : return MEM_read32(memPtr);
2360c16b537SWarner Losh     case 3 : if (MEM_isLittleEndian())
2370c16b537SWarner Losh                 return MEM_read32(memPtr)<<8;
2380c16b537SWarner Losh              else
2390c16b537SWarner Losh                 return MEM_read32(memPtr)>>8;
2400c16b537SWarner Losh     }
2410c16b537SWarner Losh }
2420c16b537SWarner Losh 
2430c16b537SWarner Losh 
2440c16b537SWarner Losh /* Update hashTable3 up to ip (excluded)
2450c16b537SWarner Losh    Assumption : always within prefix (i.e. not within extDict) */
246*19fcbaf1SConrad Meyer static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_matchState_t* ms, const BYTE* const ip)
2470c16b537SWarner Losh {
248*19fcbaf1SConrad Meyer     U32* const hashTable3 = ms->hashTable3;
249*19fcbaf1SConrad Meyer     U32 const hashLog3 = ms->hashLog3;
250*19fcbaf1SConrad Meyer     const BYTE* const base = ms->window.base;
251*19fcbaf1SConrad Meyer     U32 idx = ms->nextToUpdate3;
252*19fcbaf1SConrad Meyer     U32 const target = ms->nextToUpdate3 = (U32)(ip - base);
253052d3c12SConrad Meyer     size_t const hash3 = ZSTD_hash3Ptr(ip, hashLog3);
254*19fcbaf1SConrad Meyer     assert(hashLog3 > 0);
2550c16b537SWarner Losh 
2560c16b537SWarner Losh     while(idx < target) {
2570c16b537SWarner Losh         hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx;
2580c16b537SWarner Losh         idx++;
2590c16b537SWarner Losh     }
2600c16b537SWarner Losh 
2610c16b537SWarner Losh     return hashTable3[hash3];
2620c16b537SWarner Losh }
2630c16b537SWarner Losh 
2640c16b537SWarner Losh 
2650c16b537SWarner Losh /*-*************************************
2660c16b537SWarner Losh *  Binary Tree search
2670c16b537SWarner Losh ***************************************/
268*19fcbaf1SConrad Meyer /** ZSTD_insertBt1() : add one or multiple positions to tree.
269*19fcbaf1SConrad Meyer  *  ip : assumed <= iend-8 .
270*19fcbaf1SConrad Meyer  * @return : nb of positions added */
271*19fcbaf1SConrad Meyer static U32 ZSTD_insertBt1(
272*19fcbaf1SConrad Meyer                 ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
273*19fcbaf1SConrad Meyer                 const BYTE* const ip, const BYTE* const iend,
274*19fcbaf1SConrad Meyer                 U32 const mls, U32 const extDict)
275*19fcbaf1SConrad Meyer {
276*19fcbaf1SConrad Meyer     U32*   const hashTable = ms->hashTable;
277*19fcbaf1SConrad Meyer     U32    const hashLog = cParams->hashLog;
278*19fcbaf1SConrad Meyer     size_t const h  = ZSTD_hashPtr(ip, hashLog, mls);
279*19fcbaf1SConrad Meyer     U32*   const bt = ms->chainTable;
280*19fcbaf1SConrad Meyer     U32    const btLog  = cParams->chainLog - 1;
281*19fcbaf1SConrad Meyer     U32    const btMask = (1 << btLog) - 1;
282*19fcbaf1SConrad Meyer     U32 matchIndex = hashTable[h];
283*19fcbaf1SConrad Meyer     size_t commonLengthSmaller=0, commonLengthLarger=0;
284*19fcbaf1SConrad Meyer     const BYTE* const base = ms->window.base;
285*19fcbaf1SConrad Meyer     const BYTE* const dictBase = ms->window.dictBase;
286*19fcbaf1SConrad Meyer     const U32 dictLimit = ms->window.dictLimit;
287*19fcbaf1SConrad Meyer     const BYTE* const dictEnd = dictBase + dictLimit;
288*19fcbaf1SConrad Meyer     const BYTE* const prefixStart = base + dictLimit;
289*19fcbaf1SConrad Meyer     const BYTE* match;
290*19fcbaf1SConrad Meyer     const U32 current = (U32)(ip-base);
291*19fcbaf1SConrad Meyer     const U32 btLow = btMask >= current ? 0 : current - btMask;
292*19fcbaf1SConrad Meyer     U32* smallerPtr = bt + 2*(current&btMask);
293*19fcbaf1SConrad Meyer     U32* largerPtr  = smallerPtr + 1;
294*19fcbaf1SConrad Meyer     U32 dummy32;   /* to be nullified at the end */
295*19fcbaf1SConrad Meyer     U32 const windowLow = ms->window.lowLimit;
296*19fcbaf1SConrad Meyer     U32 matchEndIdx = current+8+1;
297*19fcbaf1SConrad Meyer     size_t bestLength = 8;
298*19fcbaf1SConrad Meyer     U32 nbCompares = 1U << cParams->searchLog;
299*19fcbaf1SConrad Meyer #ifdef ZSTD_C_PREDICT
300*19fcbaf1SConrad Meyer     U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
301*19fcbaf1SConrad Meyer     U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
302*19fcbaf1SConrad Meyer     predictedSmall += (predictedSmall>0);
303*19fcbaf1SConrad Meyer     predictedLarge += (predictedLarge>0);
304*19fcbaf1SConrad Meyer #endif /* ZSTD_C_PREDICT */
305*19fcbaf1SConrad Meyer 
306*19fcbaf1SConrad Meyer     DEBUGLOG(8, "ZSTD_insertBt1 (%u)", current);
307*19fcbaf1SConrad Meyer 
308*19fcbaf1SConrad Meyer     assert(ip <= iend-8);   /* required for h calculation */
309*19fcbaf1SConrad Meyer     hashTable[h] = current;   /* Update Hash Table */
310*19fcbaf1SConrad Meyer 
311*19fcbaf1SConrad Meyer     while (nbCompares-- && (matchIndex > windowLow)) {
312*19fcbaf1SConrad Meyer         U32* const nextPtr = bt + 2*(matchIndex & btMask);
313*19fcbaf1SConrad Meyer         size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
314*19fcbaf1SConrad Meyer         assert(matchIndex < current);
315*19fcbaf1SConrad Meyer 
316*19fcbaf1SConrad Meyer #ifdef ZSTD_C_PREDICT   /* note : can create issues when hlog small <= 11 */
317*19fcbaf1SConrad Meyer         const U32* predictPtr = bt + 2*((matchIndex-1) & btMask);   /* written this way, as bt is a roll buffer */
318*19fcbaf1SConrad Meyer         if (matchIndex == predictedSmall) {
319*19fcbaf1SConrad Meyer             /* no need to check length, result known */
320*19fcbaf1SConrad Meyer             *smallerPtr = matchIndex;
321*19fcbaf1SConrad Meyer             if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
322*19fcbaf1SConrad Meyer             smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */
323*19fcbaf1SConrad Meyer             matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */
324*19fcbaf1SConrad Meyer             predictedSmall = predictPtr[1] + (predictPtr[1]>0);
325*19fcbaf1SConrad Meyer             continue;
326*19fcbaf1SConrad Meyer         }
327*19fcbaf1SConrad Meyer         if (matchIndex == predictedLarge) {
328*19fcbaf1SConrad Meyer             *largerPtr = matchIndex;
329*19fcbaf1SConrad Meyer             if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
330*19fcbaf1SConrad Meyer             largerPtr = nextPtr;
331*19fcbaf1SConrad Meyer             matchIndex = nextPtr[0];
332*19fcbaf1SConrad Meyer             predictedLarge = predictPtr[0] + (predictPtr[0]>0);
333*19fcbaf1SConrad Meyer             continue;
334*19fcbaf1SConrad Meyer         }
335*19fcbaf1SConrad Meyer #endif
336*19fcbaf1SConrad Meyer 
337*19fcbaf1SConrad Meyer         if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
338*19fcbaf1SConrad Meyer             assert(matchIndex+matchLength >= dictLimit);   /* might be wrong if extDict is incorrectly set to 0 */
339*19fcbaf1SConrad Meyer             match = base + matchIndex;
340*19fcbaf1SConrad Meyer             matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
341*19fcbaf1SConrad Meyer         } else {
342*19fcbaf1SConrad Meyer             match = dictBase + matchIndex;
343*19fcbaf1SConrad Meyer             matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
344*19fcbaf1SConrad Meyer             if (matchIndex+matchLength >= dictLimit)
345*19fcbaf1SConrad Meyer                 match = base + matchIndex;   /* to prepare for next usage of match[matchLength] */
346*19fcbaf1SConrad Meyer         }
347*19fcbaf1SConrad Meyer 
348*19fcbaf1SConrad Meyer         if (matchLength > bestLength) {
349*19fcbaf1SConrad Meyer             bestLength = matchLength;
350*19fcbaf1SConrad Meyer             if (matchLength > matchEndIdx - matchIndex)
351*19fcbaf1SConrad Meyer                 matchEndIdx = matchIndex + (U32)matchLength;
352*19fcbaf1SConrad Meyer         }
353*19fcbaf1SConrad Meyer 
354*19fcbaf1SConrad Meyer         if (ip+matchLength == iend) {   /* equal : no way to know if inf or sup */
355*19fcbaf1SConrad Meyer             break;   /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */
356*19fcbaf1SConrad Meyer         }
357*19fcbaf1SConrad Meyer 
358*19fcbaf1SConrad Meyer         if (match[matchLength] < ip[matchLength]) {  /* necessarily within buffer */
359*19fcbaf1SConrad Meyer             /* match is smaller than current */
360*19fcbaf1SConrad Meyer             *smallerPtr = matchIndex;             /* update smaller idx */
361*19fcbaf1SConrad Meyer             commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */
362*19fcbaf1SConrad Meyer             if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop searching */
363*19fcbaf1SConrad Meyer             smallerPtr = nextPtr+1;               /* new "candidate" => larger than match, which was smaller than target */
364*19fcbaf1SConrad Meyer             matchIndex = nextPtr[1];              /* new matchIndex, larger than previous and closer to current */
365*19fcbaf1SConrad Meyer         } else {
366*19fcbaf1SConrad Meyer             /* match is larger than current */
367*19fcbaf1SConrad Meyer             *largerPtr = matchIndex;
368*19fcbaf1SConrad Meyer             commonLengthLarger = matchLength;
369*19fcbaf1SConrad Meyer             if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop searching */
370*19fcbaf1SConrad Meyer             largerPtr = nextPtr;
371*19fcbaf1SConrad Meyer             matchIndex = nextPtr[0];
372*19fcbaf1SConrad Meyer     }   }
373*19fcbaf1SConrad Meyer 
374*19fcbaf1SConrad Meyer     *smallerPtr = *largerPtr = 0;
375*19fcbaf1SConrad Meyer     if (bestLength > 384) return MIN(192, (U32)(bestLength - 384));   /* speed optimization */
376*19fcbaf1SConrad Meyer     assert(matchEndIdx > current + 8);
377*19fcbaf1SConrad Meyer     return matchEndIdx - (current + 8);
378*19fcbaf1SConrad Meyer }
379*19fcbaf1SConrad Meyer 
380*19fcbaf1SConrad Meyer FORCE_INLINE_TEMPLATE
381*19fcbaf1SConrad Meyer void ZSTD_updateTree_internal(
382*19fcbaf1SConrad Meyer                 ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
383*19fcbaf1SConrad Meyer                 const BYTE* const ip, const BYTE* const iend,
384*19fcbaf1SConrad Meyer                 const U32 mls, const U32 extDict)
385*19fcbaf1SConrad Meyer {
386*19fcbaf1SConrad Meyer     const BYTE* const base = ms->window.base;
387*19fcbaf1SConrad Meyer     U32 const target = (U32)(ip - base);
388*19fcbaf1SConrad Meyer     U32 idx = ms->nextToUpdate;
389*19fcbaf1SConrad Meyer     DEBUGLOG(7, "ZSTD_updateTree_internal, from %u to %u  (extDict:%u)",
390*19fcbaf1SConrad Meyer                 idx, target, extDict);
391*19fcbaf1SConrad Meyer 
392*19fcbaf1SConrad Meyer     while(idx < target)
393*19fcbaf1SConrad Meyer         idx += ZSTD_insertBt1(ms, cParams, base+idx, iend, mls, extDict);
394*19fcbaf1SConrad Meyer     ms->nextToUpdate = target;
395*19fcbaf1SConrad Meyer }
396*19fcbaf1SConrad Meyer 
397*19fcbaf1SConrad Meyer void ZSTD_updateTree(
398*19fcbaf1SConrad Meyer                 ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
399*19fcbaf1SConrad Meyer                 const BYTE* ip, const BYTE* iend)
400*19fcbaf1SConrad Meyer {
401*19fcbaf1SConrad Meyer     ZSTD_updateTree_internal(ms, cParams, ip, iend, cParams->searchLength, 0 /*extDict*/);
402*19fcbaf1SConrad Meyer }
403*19fcbaf1SConrad Meyer 
404052d3c12SConrad Meyer FORCE_INLINE_TEMPLATE
405052d3c12SConrad Meyer U32 ZSTD_insertBtAndGetAllMatches (
406*19fcbaf1SConrad Meyer                     ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
407052d3c12SConrad Meyer                     const BYTE* const ip, const BYTE* const iLimit, int const extDict,
408052d3c12SConrad Meyer                     U32 rep[ZSTD_REP_NUM], U32 const ll0,
409*19fcbaf1SConrad Meyer                     ZSTD_match_t* matches, const U32 lengthToBeat, U32 const mls /* template */)
4100c16b537SWarner Losh {
411*19fcbaf1SConrad Meyer     U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
412*19fcbaf1SConrad Meyer     const BYTE* const base = ms->window.base;
413052d3c12SConrad Meyer     U32 const current = (U32)(ip-base);
414*19fcbaf1SConrad Meyer     U32 const hashLog = cParams->hashLog;
415052d3c12SConrad Meyer     U32 const minMatch = (mls==3) ? 3 : 4;
416*19fcbaf1SConrad Meyer     U32* const hashTable = ms->hashTable;
417052d3c12SConrad Meyer     size_t const h  = ZSTD_hashPtr(ip, hashLog, mls);
4180c16b537SWarner Losh     U32 matchIndex  = hashTable[h];
419*19fcbaf1SConrad Meyer     U32* const bt   = ms->chainTable;
420*19fcbaf1SConrad Meyer     U32 const btLog = cParams->chainLog - 1;
421052d3c12SConrad Meyer     U32 const btMask= (1U << btLog) - 1;
4220c16b537SWarner Losh     size_t commonLengthSmaller=0, commonLengthLarger=0;
423*19fcbaf1SConrad Meyer     const BYTE* const dictBase = ms->window.dictBase;
424*19fcbaf1SConrad Meyer     U32 const dictLimit = ms->window.dictLimit;
4250c16b537SWarner Losh     const BYTE* const dictEnd = dictBase + dictLimit;
4260c16b537SWarner Losh     const BYTE* const prefixStart = base + dictLimit;
427052d3c12SConrad Meyer     U32 const btLow = btMask >= current ? 0 : current - btMask;
428*19fcbaf1SConrad Meyer     U32 const windowLow = ms->window.lowLimit;
4290c16b537SWarner Losh     U32* smallerPtr = bt + 2*(current&btMask);
4300c16b537SWarner Losh     U32* largerPtr  = bt + 2*(current&btMask) + 1;
431052d3c12SConrad Meyer     U32 matchEndIdx = current+8+1;   /* farthest referenced position of any match => detects repetitive patterns */
4320c16b537SWarner Losh     U32 dummy32;   /* to be nullified at the end */
4330c16b537SWarner Losh     U32 mnum = 0;
434*19fcbaf1SConrad Meyer     U32 nbCompares = 1U << cParams->searchLog;
4350c16b537SWarner Losh 
436052d3c12SConrad Meyer     size_t bestLength = lengthToBeat-1;
437052d3c12SConrad Meyer     DEBUGLOG(7, "ZSTD_insertBtAndGetAllMatches");
4380c16b537SWarner Losh 
439052d3c12SConrad Meyer     /* check repCode */
440052d3c12SConrad Meyer     {   U32 const lastR = ZSTD_REP_NUM + ll0;
441052d3c12SConrad Meyer         U32 repCode;
442052d3c12SConrad Meyer         for (repCode = ll0; repCode < lastR; repCode++) {
443052d3c12SConrad Meyer             U32 const repOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
444052d3c12SConrad Meyer             U32 const repIndex = current - repOffset;
445052d3c12SConrad Meyer             U32 repLen = 0;
446052d3c12SConrad Meyer             assert(current >= dictLimit);
447052d3c12SConrad Meyer             if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < current-dictLimit) {  /* equivalent to `current > repIndex >= dictLimit` */
448052d3c12SConrad Meyer                 if (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repOffset, minMatch)) {
449052d3c12SConrad Meyer                     repLen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repOffset, iLimit) + minMatch;
450052d3c12SConrad Meyer                 }
451052d3c12SConrad Meyer             } else {  /* repIndex < dictLimit || repIndex >= current */
452052d3c12SConrad Meyer                 const BYTE* const repMatch = dictBase + repIndex;
453052d3c12SConrad Meyer                 assert(current >= windowLow);
454052d3c12SConrad Meyer                 if ( extDict /* this case only valid in extDict mode */
455052d3c12SConrad Meyer                   && ( ((repOffset-1) /*intentional overflow*/ < current - windowLow)  /* equivalent to `current > repIndex >= windowLow` */
456052d3c12SConrad Meyer                      & (((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */)
457052d3c12SConrad Meyer                   && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
458052d3c12SConrad Meyer                     repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dictEnd, prefixStart) + minMatch;
459052d3c12SConrad Meyer             }   }
460052d3c12SConrad Meyer             /* save longer solution */
461052d3c12SConrad Meyer             if (repLen > bestLength) {
462052d3c12SConrad Meyer                 DEBUGLOG(8, "found rep-match %u of length %u",
463052d3c12SConrad Meyer                             repCode - ll0, (U32)repLen);
464052d3c12SConrad Meyer                 bestLength = repLen;
465052d3c12SConrad Meyer                 matches[mnum].off = repCode - ll0;
466052d3c12SConrad Meyer                 matches[mnum].len = (U32)repLen;
467052d3c12SConrad Meyer                 mnum++;
468052d3c12SConrad Meyer                 if ( (repLen > sufficient_len)
469052d3c12SConrad Meyer                    | (ip+repLen == iLimit) ) {  /* best possible */
470052d3c12SConrad Meyer                     return mnum;
471052d3c12SConrad Meyer     }   }   }   }
472052d3c12SConrad Meyer 
473052d3c12SConrad Meyer     /* HC3 match finder */
474052d3c12SConrad Meyer     if ((mls == 3) /*static*/ && (bestLength < mls)) {
475*19fcbaf1SConrad Meyer         U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(ms, ip);
476052d3c12SConrad Meyer         if ((matchIndex3 > windowLow)
477052d3c12SConrad Meyer           & (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) {
478052d3c12SConrad Meyer             size_t mlen;
479052d3c12SConrad Meyer             if ((!extDict) /*static*/ || (matchIndex3 >= dictLimit)) {
480052d3c12SConrad Meyer                 const BYTE* const match = base + matchIndex3;
481052d3c12SConrad Meyer                 mlen = ZSTD_count(ip, match, iLimit);
4820c16b537SWarner Losh             } else {
483052d3c12SConrad Meyer                 const BYTE* const match = dictBase + matchIndex3;
484052d3c12SConrad Meyer                 mlen = ZSTD_count_2segments(ip, match, iLimit, dictEnd, prefixStart);
4850c16b537SWarner Losh             }
4860c16b537SWarner Losh 
4870c16b537SWarner Losh             /* save best solution */
488052d3c12SConrad Meyer             if (mlen >= mls /* == 3 > bestLength */) {
489052d3c12SConrad Meyer                 DEBUGLOG(8, "found small match with hlog3, of length %u",
490052d3c12SConrad Meyer                             (U32)mlen);
491052d3c12SConrad Meyer                 bestLength = mlen;
492052d3c12SConrad Meyer                 assert(current > matchIndex3);
493052d3c12SConrad Meyer                 assert(mnum==0);  /* no prior solution */
494052d3c12SConrad Meyer                 matches[0].off = (current - matchIndex3) + ZSTD_REP_MOVE;
495052d3c12SConrad Meyer                 matches[0].len = (U32)mlen;
496052d3c12SConrad Meyer                 mnum = 1;
497052d3c12SConrad Meyer                 if ( (mlen > sufficient_len) |
498052d3c12SConrad Meyer                      (ip+mlen == iLimit) ) {  /* best possible length */
499*19fcbaf1SConrad Meyer                     ms->nextToUpdate = current+1;  /* skip insertion */
500052d3c12SConrad Meyer                     return 1;
501052d3c12SConrad Meyer     }   }   }   }
5020c16b537SWarner Losh 
5030c16b537SWarner Losh     hashTable[h] = current;   /* Update Hash Table */
5040c16b537SWarner Losh 
5050c16b537SWarner Losh     while (nbCompares-- && (matchIndex > windowLow)) {
506052d3c12SConrad Meyer         U32* const nextPtr = bt + 2*(matchIndex & btMask);
5070c16b537SWarner Losh         size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
5080c16b537SWarner Losh         const BYTE* match;
509052d3c12SConrad Meyer         assert(current > matchIndex);
5100c16b537SWarner Losh 
5110c16b537SWarner Losh         if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
512052d3c12SConrad Meyer             assert(matchIndex+matchLength >= dictLimit);  /* ensure the condition is correct when !extDict */
5130c16b537SWarner Losh             match = base + matchIndex;
514052d3c12SConrad Meyer             matchLength += ZSTD_count(ip+matchLength, match+matchLength, iLimit);
5150c16b537SWarner Losh         } else {
5160c16b537SWarner Losh             match = dictBase + matchIndex;
5170c16b537SWarner Losh             matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart);
5180c16b537SWarner Losh             if (matchIndex+matchLength >= dictLimit)
519052d3c12SConrad Meyer                 match = base + matchIndex;   /* prepare for match[matchLength] */
5200c16b537SWarner Losh         }
5210c16b537SWarner Losh 
5220c16b537SWarner Losh         if (matchLength > bestLength) {
523052d3c12SConrad Meyer             DEBUGLOG(8, "found match of length %u at distance %u",
524052d3c12SConrad Meyer                     (U32)matchLength, current - matchIndex);
525052d3c12SConrad Meyer             assert(matchEndIdx > matchIndex);
526052d3c12SConrad Meyer             if (matchLength > matchEndIdx - matchIndex)
527052d3c12SConrad Meyer                 matchEndIdx = matchIndex + (U32)matchLength;
5280c16b537SWarner Losh             bestLength = matchLength;
529052d3c12SConrad Meyer             matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE;
5300c16b537SWarner Losh             matches[mnum].len = (U32)matchLength;
5310c16b537SWarner Losh             mnum++;
5320c16b537SWarner Losh             if (matchLength > ZSTD_OPT_NUM) break;
533052d3c12SConrad Meyer             if (ip+matchLength == iLimit) {  /* equal : no way to know if inf or sup */
534052d3c12SConrad Meyer                 break;   /* drop, to preserve bt consistency (miss a little bit of compression) */
535052d3c12SConrad Meyer             }
5360c16b537SWarner Losh         }
5370c16b537SWarner Losh 
5380c16b537SWarner Losh         if (match[matchLength] < ip[matchLength]) {
539052d3c12SConrad Meyer             /* match smaller than current */
5400c16b537SWarner Losh             *smallerPtr = matchIndex;             /* update smaller idx */
5410c16b537SWarner Losh             commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */
5420c16b537SWarner Losh             if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
543052d3c12SConrad Meyer             smallerPtr = nextPtr+1;               /* new candidate => larger than match, which was smaller than current */
544052d3c12SConrad Meyer             matchIndex = nextPtr[1];              /* new matchIndex, larger than previous, closer to current */
5450c16b537SWarner Losh         } else {
5460c16b537SWarner Losh             *largerPtr = matchIndex;
5470c16b537SWarner Losh             commonLengthLarger = matchLength;
5480c16b537SWarner Losh             if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
5490c16b537SWarner Losh             largerPtr = nextPtr;
5500c16b537SWarner Losh             matchIndex = nextPtr[0];
5510c16b537SWarner Losh     }   }
5520c16b537SWarner Losh 
5530c16b537SWarner Losh     *smallerPtr = *largerPtr = 0;
5540c16b537SWarner Losh 
555052d3c12SConrad Meyer     assert(matchEndIdx > current+8);
556*19fcbaf1SConrad Meyer     ms->nextToUpdate = matchEndIdx - 8;  /* skip repetitive patterns */
5570c16b537SWarner Losh     return mnum;
5580c16b537SWarner Losh }
5590c16b537SWarner Losh 
5600c16b537SWarner Losh 
561052d3c12SConrad Meyer FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches (
562*19fcbaf1SConrad Meyer                         ZSTD_matchState_t* ms, ZSTD_compressionParameters const* cParams,
563052d3c12SConrad Meyer                         const BYTE* ip, const BYTE* const iHighLimit, int const extDict,
564052d3c12SConrad Meyer                         U32 rep[ZSTD_REP_NUM], U32 const ll0,
565052d3c12SConrad Meyer                         ZSTD_match_t* matches, U32 const lengthToBeat)
5660c16b537SWarner Losh {
567*19fcbaf1SConrad Meyer     U32 const matchLengthSearch = cParams->searchLength;
568052d3c12SConrad Meyer     DEBUGLOG(7, "ZSTD_BtGetAllMatches");
569*19fcbaf1SConrad Meyer     if (ip < ms->window.base + ms->nextToUpdate) return 0;   /* skipped area */
570*19fcbaf1SConrad Meyer     ZSTD_updateTree_internal(ms, cParams, ip, iHighLimit, matchLengthSearch, extDict);
5710c16b537SWarner Losh     switch(matchLengthSearch)
5720c16b537SWarner Losh     {
573*19fcbaf1SConrad Meyer     case 3 : return ZSTD_insertBtAndGetAllMatches(ms, cParams, ip, iHighLimit, extDict, rep, ll0, matches, lengthToBeat, 3);
5740c16b537SWarner Losh     default :
575*19fcbaf1SConrad Meyer     case 4 : return ZSTD_insertBtAndGetAllMatches(ms, cParams, ip, iHighLimit, extDict, rep, ll0, matches, lengthToBeat, 4);
576*19fcbaf1SConrad Meyer     case 5 : return ZSTD_insertBtAndGetAllMatches(ms, cParams, ip, iHighLimit, extDict, rep, ll0, matches, lengthToBeat, 5);
5770c16b537SWarner Losh     case 7 :
578*19fcbaf1SConrad Meyer     case 6 : return ZSTD_insertBtAndGetAllMatches(ms, cParams, ip, iHighLimit, extDict, rep, ll0, matches, lengthToBeat, 6);
5790c16b537SWarner Losh     }
5800c16b537SWarner Losh }
5810c16b537SWarner Losh 
5820c16b537SWarner Losh 
5830c16b537SWarner Losh /*-*******************************
5840c16b537SWarner Losh *  Optimal parser
5850c16b537SWarner Losh *********************************/
586052d3c12SConrad Meyer typedef struct repcodes_s {
587052d3c12SConrad Meyer     U32 rep[3];
588052d3c12SConrad Meyer } repcodes_t;
589052d3c12SConrad Meyer 
590052d3c12SConrad Meyer repcodes_t ZSTD_updateRep(U32 const rep[3], U32 const offset, U32 const ll0)
591052d3c12SConrad Meyer {
592052d3c12SConrad Meyer     repcodes_t newReps;
593052d3c12SConrad Meyer     if (offset >= ZSTD_REP_NUM) {  /* full offset */
594052d3c12SConrad Meyer         newReps.rep[2] = rep[1];
595052d3c12SConrad Meyer         newReps.rep[1] = rep[0];
596052d3c12SConrad Meyer         newReps.rep[0] = offset - ZSTD_REP_MOVE;
597052d3c12SConrad Meyer     } else {   /* repcode */
598052d3c12SConrad Meyer         U32 const repCode = offset + ll0;
599052d3c12SConrad Meyer         if (repCode > 0) {  /* note : if repCode==0, no change */
600052d3c12SConrad Meyer             U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
601052d3c12SConrad Meyer             newReps.rep[2] = (repCode >= 2) ? rep[1] : rep[2];
602052d3c12SConrad Meyer             newReps.rep[1] = rep[0];
603052d3c12SConrad Meyer             newReps.rep[0] = currentOffset;
604052d3c12SConrad Meyer         } else {   /* repCode == 0 */
605052d3c12SConrad Meyer             memcpy(&newReps, rep, sizeof(newReps));
606052d3c12SConrad Meyer         }
607052d3c12SConrad Meyer     }
608052d3c12SConrad Meyer     return newReps;
609052d3c12SConrad Meyer }
610052d3c12SConrad Meyer 
611052d3c12SConrad Meyer 
612052d3c12SConrad Meyer typedef struct {
613052d3c12SConrad Meyer     const BYTE* anchor;
614052d3c12SConrad Meyer     U32 litlen;
615052d3c12SConrad Meyer     U32 rawLitCost;
616052d3c12SConrad Meyer } cachedLiteralPrice_t;
617052d3c12SConrad Meyer 
618052d3c12SConrad Meyer static U32 ZSTD_rawLiteralsCost_cached(
619052d3c12SConrad Meyer                             cachedLiteralPrice_t* const cachedLitPrice,
620052d3c12SConrad Meyer                             const BYTE* const anchor, U32 const litlen,
621052d3c12SConrad Meyer                             const optState_t* const optStatePtr)
622052d3c12SConrad Meyer {
623052d3c12SConrad Meyer     U32 startCost;
624052d3c12SConrad Meyer     U32 remainingLength;
625052d3c12SConrad Meyer     const BYTE* startPosition;
626052d3c12SConrad Meyer 
627052d3c12SConrad Meyer     if (anchor == cachedLitPrice->anchor) {
628052d3c12SConrad Meyer         startCost = cachedLitPrice->rawLitCost;
629052d3c12SConrad Meyer         startPosition = anchor + cachedLitPrice->litlen;
630052d3c12SConrad Meyer         assert(litlen >= cachedLitPrice->litlen);
631052d3c12SConrad Meyer         remainingLength = litlen - cachedLitPrice->litlen;
632052d3c12SConrad Meyer     } else {
633052d3c12SConrad Meyer         startCost = 0;
634052d3c12SConrad Meyer         startPosition = anchor;
635052d3c12SConrad Meyer         remainingLength = litlen;
636052d3c12SConrad Meyer     }
637052d3c12SConrad Meyer 
638052d3c12SConrad Meyer     {   U32 const rawLitCost = startCost + ZSTD_rawLiteralsCost(startPosition, remainingLength, optStatePtr);
639052d3c12SConrad Meyer         cachedLitPrice->anchor = anchor;
640052d3c12SConrad Meyer         cachedLitPrice->litlen = litlen;
641052d3c12SConrad Meyer         cachedLitPrice->rawLitCost = rawLitCost;
642052d3c12SConrad Meyer         return rawLitCost;
643052d3c12SConrad Meyer     }
644052d3c12SConrad Meyer }
645052d3c12SConrad Meyer 
646052d3c12SConrad Meyer static U32 ZSTD_fullLiteralsCost_cached(
647052d3c12SConrad Meyer                             cachedLiteralPrice_t* const cachedLitPrice,
648052d3c12SConrad Meyer                             const BYTE* const anchor, U32 const litlen,
649052d3c12SConrad Meyer                             const optState_t* const optStatePtr)
650052d3c12SConrad Meyer {
651052d3c12SConrad Meyer     return ZSTD_rawLiteralsCost_cached(cachedLitPrice, anchor, litlen, optStatePtr)
652052d3c12SConrad Meyer          + ZSTD_litLengthPrice(litlen, optStatePtr);
653052d3c12SConrad Meyer }
654052d3c12SConrad Meyer 
655052d3c12SConrad Meyer static int ZSTD_literalsContribution_cached(
656052d3c12SConrad Meyer                             cachedLiteralPrice_t* const cachedLitPrice,
657052d3c12SConrad Meyer                             const BYTE* const anchor, U32 const litlen,
658052d3c12SConrad Meyer                             const optState_t* const optStatePtr)
659052d3c12SConrad Meyer {
660052d3c12SConrad Meyer     int const contribution = ZSTD_rawLiteralsCost_cached(cachedLitPrice, anchor, litlen, optStatePtr)
661052d3c12SConrad Meyer                            + ZSTD_litLengthContribution(litlen, optStatePtr);
662052d3c12SConrad Meyer     return contribution;
663052d3c12SConrad Meyer }
664052d3c12SConrad Meyer 
6650c16b537SWarner Losh FORCE_INLINE_TEMPLATE
666*19fcbaf1SConrad Meyer size_t ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,seqStore_t* seqStore,
667*19fcbaf1SConrad Meyer                                       U32 rep[ZSTD_REP_NUM],
668*19fcbaf1SConrad Meyer                                       ZSTD_compressionParameters const* cParams,
669052d3c12SConrad Meyer                                       const void* src, size_t srcSize,
670052d3c12SConrad Meyer                                       const int optLevel, const int extDict)
6710c16b537SWarner Losh {
672*19fcbaf1SConrad Meyer     optState_t* const optStatePtr = &ms->opt;
6730c16b537SWarner Losh     const BYTE* const istart = (const BYTE*)src;
6740c16b537SWarner Losh     const BYTE* ip = istart;
6750c16b537SWarner Losh     const BYTE* anchor = istart;
6760c16b537SWarner Losh     const BYTE* const iend = istart + srcSize;
6770c16b537SWarner Losh     const BYTE* const ilimit = iend - 8;
678*19fcbaf1SConrad Meyer     const BYTE* const base = ms->window.base;
679*19fcbaf1SConrad Meyer     const BYTE* const prefixStart = base + ms->window.dictLimit;
6800c16b537SWarner Losh 
681*19fcbaf1SConrad Meyer     U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
682*19fcbaf1SConrad Meyer     U32 const minMatch = (cParams->searchLength == 3) ? 3 : 4;
6830c16b537SWarner Losh 
684052d3c12SConrad Meyer     ZSTD_optimal_t* const opt = optStatePtr->priceTable;
685052d3c12SConrad Meyer     ZSTD_match_t* const matches = optStatePtr->matchTable;
686052d3c12SConrad Meyer     cachedLiteralPrice_t cachedLitPrice;
6870c16b537SWarner Losh 
6880c16b537SWarner Losh     /* init */
689052d3c12SConrad Meyer     DEBUGLOG(5, "ZSTD_compressBlock_opt_generic");
690*19fcbaf1SConrad Meyer     ms->nextToUpdate3 = ms->nextToUpdate;
6910c16b537SWarner Losh     ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
6920c16b537SWarner Losh     ip += (ip==prefixStart);
693052d3c12SConrad Meyer     memset(&cachedLitPrice, 0, sizeof(cachedLitPrice));
6940c16b537SWarner Losh 
6950c16b537SWarner Losh     /* Match Loop */
6960c16b537SWarner Losh     while (ip < ilimit) {
697052d3c12SConrad Meyer         U32 cur, last_pos = 0;
698052d3c12SConrad Meyer         U32 best_mlen, best_off;
6990c16b537SWarner Losh 
700052d3c12SConrad Meyer         /* find first match */
701052d3c12SConrad Meyer         {   U32 const litlen = (U32)(ip - anchor);
702052d3c12SConrad Meyer             U32 const ll0 = !litlen;
703*19fcbaf1SConrad Meyer             U32 const nbMatches = ZSTD_BtGetAllMatches(ms, cParams, ip, iend, extDict, rep, ll0, matches, minMatch);
704052d3c12SConrad Meyer             if (!nbMatches) { ip++; continue; }
7050c16b537SWarner Losh 
7060c16b537SWarner Losh             /* initialize opt[0] */
7070c16b537SWarner Losh             { U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
7080c16b537SWarner Losh             opt[0].mlen = 1;
7090c16b537SWarner Losh             opt[0].litlen = litlen;
7100c16b537SWarner Losh 
711052d3c12SConrad Meyer             /* large match -> immediate encoding */
712052d3c12SConrad Meyer             {   U32 const maxML = matches[nbMatches-1].len;
713052d3c12SConrad Meyer                 DEBUGLOG(7, "found %u matches of maxLength=%u and offset=%u at cPos=%u => start new serie",
714052d3c12SConrad Meyer                             nbMatches, maxML, matches[nbMatches-1].off, (U32)(ip-prefixStart));
7150c16b537SWarner Losh 
716052d3c12SConrad Meyer                 if (maxML > sufficient_len) {
717052d3c12SConrad Meyer                     best_mlen = maxML;
718052d3c12SConrad Meyer                     best_off = matches[nbMatches-1].off;
719052d3c12SConrad Meyer                     DEBUGLOG(7, "large match (%u>%u), immediate encoding",
720052d3c12SConrad Meyer                                 best_mlen, sufficient_len);
721052d3c12SConrad Meyer                     cur = 0;
722052d3c12SConrad Meyer                     last_pos = 1;
723052d3c12SConrad Meyer                     goto _shortestPath;
724052d3c12SConrad Meyer             }   }
725052d3c12SConrad Meyer 
726052d3c12SConrad Meyer             /* set prices for first matches starting position == 0 */
727052d3c12SConrad Meyer             {   U32 const literalsPrice = ZSTD_fullLiteralsCost_cached(&cachedLitPrice, anchor, litlen, optStatePtr);
728052d3c12SConrad Meyer                 U32 pos;
729052d3c12SConrad Meyer                 U32 matchNb;
730052d3c12SConrad Meyer                 for (pos = 0; pos < minMatch; pos++) {
731052d3c12SConrad Meyer                     opt[pos].mlen = 1;
732052d3c12SConrad Meyer                     opt[pos].price = ZSTD_MAX_PRICE;
733052d3c12SConrad Meyer                 }
734052d3c12SConrad Meyer                 for (matchNb = 0; matchNb < nbMatches; matchNb++) {
735052d3c12SConrad Meyer                     U32 const offset = matches[matchNb].off;
736052d3c12SConrad Meyer                     U32 const end = matches[matchNb].len;
737052d3c12SConrad Meyer                     repcodes_t const repHistory = ZSTD_updateRep(rep, offset, ll0);
738052d3c12SConrad Meyer                     for ( ; pos <= end ; pos++ ) {
739052d3c12SConrad Meyer                         U32 const matchPrice = literalsPrice + ZSTD_getMatchPrice(offset, pos, optStatePtr, optLevel);
740052d3c12SConrad Meyer                         DEBUGLOG(7, "rPos:%u => set initial price : %u",
741052d3c12SConrad Meyer                                     pos, matchPrice);
742052d3c12SConrad Meyer                         opt[pos].mlen = pos;
743052d3c12SConrad Meyer                         opt[pos].off = offset;
744052d3c12SConrad Meyer                         opt[pos].litlen = litlen;
745052d3c12SConrad Meyer                         opt[pos].price = matchPrice;
746052d3c12SConrad Meyer                         memcpy(opt[pos].rep, &repHistory, sizeof(repHistory));
747052d3c12SConrad Meyer                 }   }
748052d3c12SConrad Meyer                 last_pos = pos-1;
749052d3c12SConrad Meyer             }
7500c16b537SWarner Losh         }
7510c16b537SWarner Losh 
752052d3c12SConrad Meyer         /* check further positions */
753052d3c12SConrad Meyer         for (cur = 1; cur <= last_pos; cur++) {
754052d3c12SConrad Meyer             const BYTE* const inr = ip + cur;
755052d3c12SConrad Meyer             assert(cur < ZSTD_OPT_NUM);
756052d3c12SConrad Meyer 
757052d3c12SConrad Meyer             /* Fix current position with one literal if cheaper */
758052d3c12SConrad Meyer             {   U32 const litlen = (opt[cur-1].mlen == 1) ? opt[cur-1].litlen + 1 : 1;
759052d3c12SConrad Meyer                 int price;  /* note : contribution can be negative */
760052d3c12SConrad Meyer                 if (cur > litlen) {
761052d3c12SConrad Meyer                     price = opt[cur - litlen].price + ZSTD_literalsContribution(inr-litlen, litlen, optStatePtr);
762052d3c12SConrad Meyer                 } else {
763052d3c12SConrad Meyer                     price = ZSTD_literalsContribution_cached(&cachedLitPrice, anchor, litlen, optStatePtr);
764052d3c12SConrad Meyer                 }
765052d3c12SConrad Meyer                 assert(price < 1000000000); /* overflow check */
766052d3c12SConrad Meyer                 if (price <= opt[cur].price) {
767052d3c12SConrad Meyer                     DEBUGLOG(7, "rPos:%u : better price (%u<%u) using literal",
768052d3c12SConrad Meyer                                 cur, price, opt[cur].price);
769052d3c12SConrad Meyer                     opt[cur].mlen = 1;
770052d3c12SConrad Meyer                     opt[cur].off = 0;
771052d3c12SConrad Meyer                     opt[cur].litlen = litlen;
772052d3c12SConrad Meyer                     opt[cur].price = price;
773052d3c12SConrad Meyer                     memcpy(opt[cur].rep, opt[cur-1].rep, sizeof(opt[cur].rep));
774052d3c12SConrad Meyer             }   }
775052d3c12SConrad Meyer 
776052d3c12SConrad Meyer             /* last match must start at a minimum distance of 8 from oend */
777052d3c12SConrad Meyer             if (inr > ilimit) continue;
7780c16b537SWarner Losh 
7790c16b537SWarner Losh             if (cur == last_pos) break;
7800c16b537SWarner Losh 
781052d3c12SConrad Meyer              if ( (optLevel==0) /*static*/
782052d3c12SConrad Meyer                && (opt[cur+1].price <= opt[cur].price) )
783052d3c12SConrad Meyer                 continue;  /* skip unpromising positions; about ~+6% speed, -0.01 ratio */
7840c16b537SWarner Losh 
785052d3c12SConrad Meyer             {   U32 const ll0 = (opt[cur].mlen != 1);
786052d3c12SConrad Meyer                 U32 const litlen = (opt[cur].mlen == 1) ? opt[cur].litlen : 0;
787052d3c12SConrad Meyer                 U32 const previousPrice = (cur > litlen) ? opt[cur-litlen].price : 0;
788052d3c12SConrad Meyer                 U32 const basePrice = previousPrice + ZSTD_fullLiteralsCost(inr-litlen, litlen, optStatePtr);
789*19fcbaf1SConrad Meyer                 U32 const nbMatches = ZSTD_BtGetAllMatches(ms, cParams, inr, iend, extDict, opt[cur].rep, ll0, matches, minMatch);
790052d3c12SConrad Meyer                 U32 matchNb;
791052d3c12SConrad Meyer                 if (!nbMatches) continue;
7920c16b537SWarner Losh 
793052d3c12SConrad Meyer                 {   U32 const maxML = matches[nbMatches-1].len;
794052d3c12SConrad Meyer                     DEBUGLOG(7, "rPos:%u, found %u matches, of maxLength=%u",
795052d3c12SConrad Meyer                                 cur, nbMatches, maxML);
7960c16b537SWarner Losh 
797052d3c12SConrad Meyer                     if ( (maxML > sufficient_len)
798052d3c12SConrad Meyer                        | (cur + maxML >= ZSTD_OPT_NUM) ) {
799052d3c12SConrad Meyer                         best_mlen = maxML;
800052d3c12SConrad Meyer                         best_off = matches[nbMatches-1].off;
8010c16b537SWarner Losh                         last_pos = cur + 1;
802052d3c12SConrad Meyer                         goto _shortestPath;
803052d3c12SConrad Meyer                     }
8040c16b537SWarner Losh                 }
8050c16b537SWarner Losh 
806052d3c12SConrad Meyer                 /* set prices using matches found at position == cur */
807052d3c12SConrad Meyer                 for (matchNb = 0; matchNb < nbMatches; matchNb++) {
808052d3c12SConrad Meyer                     U32 const offset = matches[matchNb].off;
809052d3c12SConrad Meyer                     repcodes_t const repHistory = ZSTD_updateRep(opt[cur].rep, offset, ll0);
810052d3c12SConrad Meyer                     U32 const lastML = matches[matchNb].len;
811052d3c12SConrad Meyer                     U32 const startML = (matchNb>0) ? matches[matchNb-1].len+1 : minMatch;
812052d3c12SConrad Meyer                     U32 mlen;
8130c16b537SWarner Losh 
814052d3c12SConrad Meyer                     DEBUGLOG(7, "testing match %u => offCode=%u, mlen=%u, llen=%u",
815052d3c12SConrad Meyer                                 matchNb, matches[matchNb].off, lastML, litlen);
816052d3c12SConrad Meyer 
817052d3c12SConrad Meyer                     for (mlen = lastML; mlen >= startML; mlen--) {
818052d3c12SConrad Meyer                         U32 const pos = cur + mlen;
819052d3c12SConrad Meyer                         int const price = basePrice + ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel);
820052d3c12SConrad Meyer 
821052d3c12SConrad Meyer                         if ((pos > last_pos) || (price < opt[pos].price)) {
822052d3c12SConrad Meyer                             DEBUGLOG(7, "rPos:%u => new better price (%u<%u)",
823052d3c12SConrad Meyer                                         pos, price, opt[pos].price);
824052d3c12SConrad Meyer                             while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; }
825052d3c12SConrad Meyer                             opt[pos].mlen = mlen;
826052d3c12SConrad Meyer                             opt[pos].off = offset;
827052d3c12SConrad Meyer                             opt[pos].litlen = litlen;
828052d3c12SConrad Meyer                             opt[pos].price = price;
829052d3c12SConrad Meyer                             memcpy(opt[pos].rep, &repHistory, sizeof(repHistory));
8300c16b537SWarner Losh                         } else {
831052d3c12SConrad Meyer                             if (optLevel==0) break;  /* gets ~+10% speed for about -0.01 ratio loss */
8320c16b537SWarner Losh                         }
8330c16b537SWarner Losh             }   }   }
834052d3c12SConrad Meyer         }  /* for (cur = 1; cur <= last_pos; cur++) */
8350c16b537SWarner Losh 
8360c16b537SWarner Losh         best_mlen = opt[last_pos].mlen;
8370c16b537SWarner Losh         best_off = opt[last_pos].off;
8380c16b537SWarner Losh         cur = last_pos - best_mlen;
8390c16b537SWarner Losh 
840052d3c12SConrad Meyer _shortestPath:   /* cur, last_pos, best_mlen, best_off have to be set */
841052d3c12SConrad Meyer         assert(opt[0].mlen == 1);
8420c16b537SWarner Losh 
843052d3c12SConrad Meyer         /* reverse traversal */
844052d3c12SConrad Meyer         DEBUGLOG(7, "start reverse traversal (last_pos:%u, cur:%u)",
845052d3c12SConrad Meyer                     last_pos, cur);
846052d3c12SConrad Meyer         {   U32 selectedMatchLength = best_mlen;
847052d3c12SConrad Meyer             U32 selectedOffset = best_off;
848052d3c12SConrad Meyer             U32 pos = cur;
8490c16b537SWarner Losh             while (1) {
850052d3c12SConrad Meyer                 U32 const mlen = opt[pos].mlen;
851052d3c12SConrad Meyer                 U32 const off = opt[pos].off;
852052d3c12SConrad Meyer                 opt[pos].mlen = selectedMatchLength;
853052d3c12SConrad Meyer                 opt[pos].off = selectedOffset;
854052d3c12SConrad Meyer                 selectedMatchLength = mlen;
855052d3c12SConrad Meyer                 selectedOffset = off;
856052d3c12SConrad Meyer                 if (mlen > pos) break;
857052d3c12SConrad Meyer                 pos -= mlen;
858052d3c12SConrad Meyer         }   }
8590c16b537SWarner Losh 
860052d3c12SConrad Meyer         /* save sequences */
861052d3c12SConrad Meyer         {   U32 pos;
862052d3c12SConrad Meyer             for (pos=0; pos < last_pos; ) {
863052d3c12SConrad Meyer                 U32 const llen = (U32)(ip - anchor);
864052d3c12SConrad Meyer                 U32 const mlen = opt[pos].mlen;
865052d3c12SConrad Meyer                 U32 const offset = opt[pos].off;
866052d3c12SConrad Meyer                 if (mlen == 1) { ip++; pos++; continue; }  /* literal position => move on */
867052d3c12SConrad Meyer                 pos += mlen; ip += mlen;
8680c16b537SWarner Losh 
869052d3c12SConrad Meyer                 /* repcodes update : like ZSTD_updateRep(), but update in place */
870052d3c12SConrad Meyer                 if (offset >= ZSTD_REP_NUM) {  /* full offset */
8710c16b537SWarner Losh                     rep[2] = rep[1];
8720c16b537SWarner Losh                     rep[1] = rep[0];
873052d3c12SConrad Meyer                     rep[0] = offset - ZSTD_REP_MOVE;
874052d3c12SConrad Meyer                 } else {   /* repcode */
875052d3c12SConrad Meyer                     U32 const repCode = offset + (llen==0);
876052d3c12SConrad Meyer                     if (repCode) {  /* note : if repCode==0, no change */
877052d3c12SConrad Meyer                         U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
878052d3c12SConrad Meyer                         if (repCode >= 2) rep[2] = rep[1];
8790c16b537SWarner Losh                         rep[1] = rep[0];
880052d3c12SConrad Meyer                         rep[0] = currentOffset;
8810c16b537SWarner Losh                     }
8820c16b537SWarner Losh                 }
8830c16b537SWarner Losh 
884052d3c12SConrad Meyer                 ZSTD_updateStats(optStatePtr, llen, anchor, offset, mlen);
885*19fcbaf1SConrad Meyer                 ZSTD_storeSeq(seqStore, llen, anchor, offset, mlen-MINMATCH);
886052d3c12SConrad Meyer                 anchor = ip;
887052d3c12SConrad Meyer         }   }
888052d3c12SConrad Meyer         ZSTD_setLog2Prices(optStatePtr);
889052d3c12SConrad Meyer     }   /* while (ip < ilimit) */
8900c16b537SWarner Losh 
8910c16b537SWarner Losh     /* Return the last literals size */
8920c16b537SWarner Losh     return iend - anchor;
8930c16b537SWarner Losh }
8940c16b537SWarner Losh 
8950c16b537SWarner Losh 
896*19fcbaf1SConrad Meyer size_t ZSTD_compressBlock_btopt(
897*19fcbaf1SConrad Meyer         ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
898*19fcbaf1SConrad Meyer         ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
8990c16b537SWarner Losh {
900052d3c12SConrad Meyer     DEBUGLOG(5, "ZSTD_compressBlock_btopt");
901*19fcbaf1SConrad Meyer     return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 0 /*optLevel*/, 0 /*extDict*/);
9020c16b537SWarner Losh }
9030c16b537SWarner Losh 
904*19fcbaf1SConrad Meyer size_t ZSTD_compressBlock_btultra(
905*19fcbaf1SConrad Meyer         ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
906*19fcbaf1SConrad Meyer         ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
9070c16b537SWarner Losh {
908*19fcbaf1SConrad Meyer     return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 2 /*optLevel*/, 0 /*extDict*/);
9090c16b537SWarner Losh }
9100c16b537SWarner Losh 
911*19fcbaf1SConrad Meyer size_t ZSTD_compressBlock_btopt_extDict(
912*19fcbaf1SConrad Meyer         ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
913*19fcbaf1SConrad Meyer         ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
9140c16b537SWarner Losh {
915*19fcbaf1SConrad Meyer     return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 0 /*optLevel*/, 1 /*extDict*/);
9160c16b537SWarner Losh }
9170c16b537SWarner Losh 
918*19fcbaf1SConrad Meyer size_t ZSTD_compressBlock_btultra_extDict(
919*19fcbaf1SConrad Meyer         ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
920*19fcbaf1SConrad Meyer         ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
9210c16b537SWarner Losh {
922*19fcbaf1SConrad Meyer     return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, cParams, src, srcSize, 2 /*optLevel*/, 1 /*extDict*/);
9230c16b537SWarner Losh }
924