xref: /freebsd/sys/contrib/zstd/lib/compress/zstd_opt.c (revision 0c16b53773565120a8f80a31a0af2ef56ccd368e)
1*0c16b537SWarner Losh /*
2*0c16b537SWarner Losh  * Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.
3*0c16b537SWarner Losh  * All rights reserved.
4*0c16b537SWarner Losh  *
5*0c16b537SWarner Losh  * This source code is licensed under both the BSD-style license (found in the
6*0c16b537SWarner Losh  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7*0c16b537SWarner Losh  * in the COPYING file in the root directory of this source tree).
8*0c16b537SWarner Losh  * You may select, at your option, one of the above-listed licenses.
9*0c16b537SWarner Losh  */
10*0c16b537SWarner Losh 
11*0c16b537SWarner Losh #include "zstd_opt.h"
12*0c16b537SWarner Losh #include "zstd_lazy.h"
13*0c16b537SWarner Losh 
14*0c16b537SWarner Losh 
15*0c16b537SWarner Losh #define ZSTD_LITFREQ_ADD    2
16*0c16b537SWarner Losh #define ZSTD_FREQ_DIV       4
17*0c16b537SWarner Losh #define ZSTD_MAX_PRICE      (1<<30)
18*0c16b537SWarner Losh 
19*0c16b537SWarner Losh /*-*************************************
20*0c16b537SWarner Losh *  Price functions for optimal parser
21*0c16b537SWarner Losh ***************************************/
22*0c16b537SWarner Losh static void ZSTD_setLog2Prices(optState_t* optPtr)
23*0c16b537SWarner Losh {
24*0c16b537SWarner Losh     optPtr->log2matchLengthSum = ZSTD_highbit32(optPtr->matchLengthSum+1);
25*0c16b537SWarner Losh     optPtr->log2litLengthSum = ZSTD_highbit32(optPtr->litLengthSum+1);
26*0c16b537SWarner Losh     optPtr->log2litSum = ZSTD_highbit32(optPtr->litSum+1);
27*0c16b537SWarner Losh     optPtr->log2offCodeSum = ZSTD_highbit32(optPtr->offCodeSum+1);
28*0c16b537SWarner Losh     optPtr->factor = 1 + ((optPtr->litSum>>5) / optPtr->litLengthSum) + ((optPtr->litSum<<1) / (optPtr->litSum + optPtr->matchSum));
29*0c16b537SWarner Losh }
30*0c16b537SWarner Losh 
31*0c16b537SWarner Losh 
32*0c16b537SWarner Losh static void ZSTD_rescaleFreqs(optState_t* optPtr, const BYTE* src, size_t srcSize)
33*0c16b537SWarner Losh {
34*0c16b537SWarner Losh     unsigned u;
35*0c16b537SWarner Losh 
36*0c16b537SWarner Losh     optPtr->cachedLiterals = NULL;
37*0c16b537SWarner Losh     optPtr->cachedPrice = optPtr->cachedLitLength = 0;
38*0c16b537SWarner Losh     optPtr->staticPrices = 0;
39*0c16b537SWarner Losh 
40*0c16b537SWarner Losh     if (optPtr->litLengthSum == 0) {
41*0c16b537SWarner Losh         if (srcSize <= 1024) optPtr->staticPrices = 1;
42*0c16b537SWarner Losh 
43*0c16b537SWarner Losh         assert(optPtr->litFreq!=NULL);
44*0c16b537SWarner Losh         for (u=0; u<=MaxLit; u++)
45*0c16b537SWarner Losh             optPtr->litFreq[u] = 0;
46*0c16b537SWarner Losh         for (u=0; u<srcSize; u++)
47*0c16b537SWarner Losh             optPtr->litFreq[src[u]]++;
48*0c16b537SWarner Losh 
49*0c16b537SWarner Losh         optPtr->litSum = 0;
50*0c16b537SWarner Losh         optPtr->litLengthSum = MaxLL+1;
51*0c16b537SWarner Losh         optPtr->matchLengthSum = MaxML+1;
52*0c16b537SWarner Losh         optPtr->offCodeSum = (MaxOff+1);
53*0c16b537SWarner Losh         optPtr->matchSum = (ZSTD_LITFREQ_ADD<<Litbits);
54*0c16b537SWarner Losh 
55*0c16b537SWarner Losh         for (u=0; u<=MaxLit; u++) {
56*0c16b537SWarner Losh             optPtr->litFreq[u] = 1 + (optPtr->litFreq[u]>>ZSTD_FREQ_DIV);
57*0c16b537SWarner Losh             optPtr->litSum += optPtr->litFreq[u];
58*0c16b537SWarner Losh         }
59*0c16b537SWarner Losh         for (u=0; u<=MaxLL; u++)
60*0c16b537SWarner Losh             optPtr->litLengthFreq[u] = 1;
61*0c16b537SWarner Losh         for (u=0; u<=MaxML; u++)
62*0c16b537SWarner Losh             optPtr->matchLengthFreq[u] = 1;
63*0c16b537SWarner Losh         for (u=0; u<=MaxOff; u++)
64*0c16b537SWarner Losh             optPtr->offCodeFreq[u] = 1;
65*0c16b537SWarner Losh     } else {
66*0c16b537SWarner Losh         optPtr->matchLengthSum = 0;
67*0c16b537SWarner Losh         optPtr->litLengthSum = 0;
68*0c16b537SWarner Losh         optPtr->offCodeSum = 0;
69*0c16b537SWarner Losh         optPtr->matchSum = 0;
70*0c16b537SWarner Losh         optPtr->litSum = 0;
71*0c16b537SWarner Losh 
72*0c16b537SWarner Losh         for (u=0; u<=MaxLit; u++) {
73*0c16b537SWarner Losh             optPtr->litFreq[u] = 1 + (optPtr->litFreq[u]>>(ZSTD_FREQ_DIV+1));
74*0c16b537SWarner Losh             optPtr->litSum += optPtr->litFreq[u];
75*0c16b537SWarner Losh         }
76*0c16b537SWarner Losh         for (u=0; u<=MaxLL; u++) {
77*0c16b537SWarner Losh             optPtr->litLengthFreq[u] = 1 + (optPtr->litLengthFreq[u]>>(ZSTD_FREQ_DIV+1));
78*0c16b537SWarner Losh             optPtr->litLengthSum += optPtr->litLengthFreq[u];
79*0c16b537SWarner Losh         }
80*0c16b537SWarner Losh         for (u=0; u<=MaxML; u++) {
81*0c16b537SWarner Losh             optPtr->matchLengthFreq[u] = 1 + (optPtr->matchLengthFreq[u]>>ZSTD_FREQ_DIV);
82*0c16b537SWarner Losh             optPtr->matchLengthSum += optPtr->matchLengthFreq[u];
83*0c16b537SWarner Losh             optPtr->matchSum += optPtr->matchLengthFreq[u] * (u + 3);
84*0c16b537SWarner Losh         }
85*0c16b537SWarner Losh         optPtr->matchSum *= ZSTD_LITFREQ_ADD;
86*0c16b537SWarner Losh         for (u=0; u<=MaxOff; u++) {
87*0c16b537SWarner Losh             optPtr->offCodeFreq[u] = 1 + (optPtr->offCodeFreq[u]>>ZSTD_FREQ_DIV);
88*0c16b537SWarner Losh             optPtr->offCodeSum += optPtr->offCodeFreq[u];
89*0c16b537SWarner Losh         }
90*0c16b537SWarner Losh     }
91*0c16b537SWarner Losh 
92*0c16b537SWarner Losh     ZSTD_setLog2Prices(optPtr);
93*0c16b537SWarner Losh }
94*0c16b537SWarner Losh 
95*0c16b537SWarner Losh 
96*0c16b537SWarner Losh static U32 ZSTD_getLiteralPrice(optState_t* optPtr, U32 litLength, const BYTE* literals)
97*0c16b537SWarner Losh {
98*0c16b537SWarner Losh     U32 price, u;
99*0c16b537SWarner Losh 
100*0c16b537SWarner Losh     if (optPtr->staticPrices)
101*0c16b537SWarner Losh         return ZSTD_highbit32((U32)litLength+1) + (litLength*6);
102*0c16b537SWarner Losh 
103*0c16b537SWarner Losh     if (litLength == 0)
104*0c16b537SWarner Losh         return optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[0]+1);
105*0c16b537SWarner Losh 
106*0c16b537SWarner Losh     /* literals */
107*0c16b537SWarner Losh     if (optPtr->cachedLiterals == literals) {
108*0c16b537SWarner Losh         U32 const additional = litLength - optPtr->cachedLitLength;
109*0c16b537SWarner Losh         const BYTE* literals2 = optPtr->cachedLiterals + optPtr->cachedLitLength;
110*0c16b537SWarner Losh         price = optPtr->cachedPrice + additional * optPtr->log2litSum;
111*0c16b537SWarner Losh         for (u=0; u < additional; u++)
112*0c16b537SWarner Losh             price -= ZSTD_highbit32(optPtr->litFreq[literals2[u]]+1);
113*0c16b537SWarner Losh         optPtr->cachedPrice = price;
114*0c16b537SWarner Losh         optPtr->cachedLitLength = litLength;
115*0c16b537SWarner Losh     } else {
116*0c16b537SWarner Losh         price = litLength * optPtr->log2litSum;
117*0c16b537SWarner Losh         for (u=0; u < litLength; u++)
118*0c16b537SWarner Losh             price -= ZSTD_highbit32(optPtr->litFreq[literals[u]]+1);
119*0c16b537SWarner Losh 
120*0c16b537SWarner Losh         if (litLength >= 12) {
121*0c16b537SWarner Losh             optPtr->cachedLiterals = literals;
122*0c16b537SWarner Losh             optPtr->cachedPrice = price;
123*0c16b537SWarner Losh             optPtr->cachedLitLength = litLength;
124*0c16b537SWarner Losh         }
125*0c16b537SWarner Losh     }
126*0c16b537SWarner Losh 
127*0c16b537SWarner Losh     /* literal Length */
128*0c16b537SWarner Losh     {   const BYTE LL_deltaCode = 19;
129*0c16b537SWarner Losh         const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
130*0c16b537SWarner Losh         price += LL_bits[llCode] + optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[llCode]+1);
131*0c16b537SWarner Losh     }
132*0c16b537SWarner Losh 
133*0c16b537SWarner Losh     return price;
134*0c16b537SWarner Losh }
135*0c16b537SWarner Losh 
136*0c16b537SWarner Losh 
137*0c16b537SWarner Losh FORCE_INLINE_TEMPLATE U32 ZSTD_getPrice(optState_t* optPtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength, const int ultra)
138*0c16b537SWarner Losh {
139*0c16b537SWarner Losh     /* offset */
140*0c16b537SWarner Losh     U32 price;
141*0c16b537SWarner Losh     BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1);
142*0c16b537SWarner Losh 
143*0c16b537SWarner Losh     if (optPtr->staticPrices)
144*0c16b537SWarner Losh         return ZSTD_getLiteralPrice(optPtr, litLength, literals) + ZSTD_highbit32((U32)matchLength+1) + 16 + offCode;
145*0c16b537SWarner Losh 
146*0c16b537SWarner Losh     price = offCode + optPtr->log2offCodeSum - ZSTD_highbit32(optPtr->offCodeFreq[offCode]+1);
147*0c16b537SWarner Losh     if (!ultra && offCode >= 20) price += (offCode-19)*2;
148*0c16b537SWarner Losh 
149*0c16b537SWarner Losh     /* match Length */
150*0c16b537SWarner Losh     {   const BYTE ML_deltaCode = 36;
151*0c16b537SWarner Losh         const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
152*0c16b537SWarner Losh         price += ML_bits[mlCode] + optPtr->log2matchLengthSum - ZSTD_highbit32(optPtr->matchLengthFreq[mlCode]+1);
153*0c16b537SWarner Losh     }
154*0c16b537SWarner Losh 
155*0c16b537SWarner Losh     return price + ZSTD_getLiteralPrice(optPtr, litLength, literals) + optPtr->factor;
156*0c16b537SWarner Losh }
157*0c16b537SWarner Losh 
158*0c16b537SWarner Losh 
159*0c16b537SWarner Losh static void ZSTD_updatePrice(optState_t* optPtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength)
160*0c16b537SWarner Losh {
161*0c16b537SWarner Losh     U32 u;
162*0c16b537SWarner Losh 
163*0c16b537SWarner Losh     /* literals */
164*0c16b537SWarner Losh     optPtr->litSum += litLength*ZSTD_LITFREQ_ADD;
165*0c16b537SWarner Losh     for (u=0; u < litLength; u++)
166*0c16b537SWarner Losh         optPtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD;
167*0c16b537SWarner Losh 
168*0c16b537SWarner Losh     /* literal Length */
169*0c16b537SWarner Losh     {   const BYTE LL_deltaCode = 19;
170*0c16b537SWarner Losh         const BYTE llCode = (litLength>63) ? (BYTE)ZSTD_highbit32(litLength) + LL_deltaCode : LL_Code[litLength];
171*0c16b537SWarner Losh         optPtr->litLengthFreq[llCode]++;
172*0c16b537SWarner Losh         optPtr->litLengthSum++;
173*0c16b537SWarner Losh     }
174*0c16b537SWarner Losh 
175*0c16b537SWarner Losh     /* match offset */
176*0c16b537SWarner Losh     {   BYTE const offCode = (BYTE)ZSTD_highbit32(offset+1);
177*0c16b537SWarner Losh         optPtr->offCodeSum++;
178*0c16b537SWarner Losh         optPtr->offCodeFreq[offCode]++;
179*0c16b537SWarner Losh     }
180*0c16b537SWarner Losh 
181*0c16b537SWarner Losh     /* match Length */
182*0c16b537SWarner Losh     {   const BYTE ML_deltaCode = 36;
183*0c16b537SWarner Losh         const BYTE mlCode = (matchLength>127) ? (BYTE)ZSTD_highbit32(matchLength) + ML_deltaCode : ML_Code[matchLength];
184*0c16b537SWarner Losh         optPtr->matchLengthFreq[mlCode]++;
185*0c16b537SWarner Losh         optPtr->matchLengthSum++;
186*0c16b537SWarner Losh     }
187*0c16b537SWarner Losh 
188*0c16b537SWarner Losh     ZSTD_setLog2Prices(optPtr);
189*0c16b537SWarner Losh }
190*0c16b537SWarner Losh 
191*0c16b537SWarner Losh 
192*0c16b537SWarner Losh #define SET_PRICE(pos, mlen_, offset_, litlen_, price_)   \
193*0c16b537SWarner Losh     {                                                 \
194*0c16b537SWarner Losh         while (last_pos < pos)  { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } \
195*0c16b537SWarner Losh         opt[pos].mlen = mlen_;                         \
196*0c16b537SWarner Losh         opt[pos].off = offset_;                        \
197*0c16b537SWarner Losh         opt[pos].litlen = litlen_;                     \
198*0c16b537SWarner Losh         opt[pos].price = price_;                       \
199*0c16b537SWarner Losh     }
200*0c16b537SWarner Losh 
201*0c16b537SWarner Losh 
202*0c16b537SWarner Losh /* function safe only for comparisons */
203*0c16b537SWarner Losh static U32 ZSTD_readMINMATCH(const void* memPtr, U32 length)
204*0c16b537SWarner Losh {
205*0c16b537SWarner Losh     switch (length)
206*0c16b537SWarner Losh     {
207*0c16b537SWarner Losh     default :
208*0c16b537SWarner Losh     case 4 : return MEM_read32(memPtr);
209*0c16b537SWarner Losh     case 3 : if (MEM_isLittleEndian())
210*0c16b537SWarner Losh                 return MEM_read32(memPtr)<<8;
211*0c16b537SWarner Losh              else
212*0c16b537SWarner Losh                 return MEM_read32(memPtr)>>8;
213*0c16b537SWarner Losh     }
214*0c16b537SWarner Losh }
215*0c16b537SWarner Losh 
216*0c16b537SWarner Losh 
217*0c16b537SWarner Losh /* Update hashTable3 up to ip (excluded)
218*0c16b537SWarner Losh    Assumption : always within prefix (i.e. not within extDict) */
219*0c16b537SWarner Losh static
220*0c16b537SWarner Losh U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_CCtx* zc, const BYTE* ip)
221*0c16b537SWarner Losh {
222*0c16b537SWarner Losh     U32* const hashTable3  = zc->hashTable3;
223*0c16b537SWarner Losh     U32 const hashLog3  = zc->hashLog3;
224*0c16b537SWarner Losh     const BYTE* const base = zc->base;
225*0c16b537SWarner Losh     U32 idx = zc->nextToUpdate3;
226*0c16b537SWarner Losh     const U32 target = zc->nextToUpdate3 = (U32)(ip - base);
227*0c16b537SWarner Losh     const size_t hash3 = ZSTD_hash3Ptr(ip, hashLog3);
228*0c16b537SWarner Losh 
229*0c16b537SWarner Losh     while(idx < target) {
230*0c16b537SWarner Losh         hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx;
231*0c16b537SWarner Losh         idx++;
232*0c16b537SWarner Losh     }
233*0c16b537SWarner Losh 
234*0c16b537SWarner Losh     return hashTable3[hash3];
235*0c16b537SWarner Losh }
236*0c16b537SWarner Losh 
237*0c16b537SWarner Losh 
238*0c16b537SWarner Losh /*-*************************************
239*0c16b537SWarner Losh *  Binary Tree search
240*0c16b537SWarner Losh ***************************************/
241*0c16b537SWarner Losh static U32 ZSTD_insertBtAndGetAllMatches (
242*0c16b537SWarner Losh                         ZSTD_CCtx* zc,
243*0c16b537SWarner Losh                         const BYTE* const ip, const BYTE* const iLimit,
244*0c16b537SWarner Losh                         U32 nbCompares, const U32 mls,
245*0c16b537SWarner Losh                         U32 extDict, ZSTD_match_t* matches, const U32 minMatchLen)
246*0c16b537SWarner Losh {
247*0c16b537SWarner Losh     const BYTE* const base = zc->base;
248*0c16b537SWarner Losh     const U32 current = (U32)(ip-base);
249*0c16b537SWarner Losh     const U32 hashLog = zc->appliedParams.cParams.hashLog;
250*0c16b537SWarner Losh     const size_t h  = ZSTD_hashPtr(ip, hashLog, mls);
251*0c16b537SWarner Losh     U32* const hashTable = zc->hashTable;
252*0c16b537SWarner Losh     U32 matchIndex  = hashTable[h];
253*0c16b537SWarner Losh     U32* const bt   = zc->chainTable;
254*0c16b537SWarner Losh     const U32 btLog = zc->appliedParams.cParams.chainLog - 1;
255*0c16b537SWarner Losh     const U32 btMask= (1U << btLog) - 1;
256*0c16b537SWarner Losh     size_t commonLengthSmaller=0, commonLengthLarger=0;
257*0c16b537SWarner Losh     const BYTE* const dictBase = zc->dictBase;
258*0c16b537SWarner Losh     const U32 dictLimit = zc->dictLimit;
259*0c16b537SWarner Losh     const BYTE* const dictEnd = dictBase + dictLimit;
260*0c16b537SWarner Losh     const BYTE* const prefixStart = base + dictLimit;
261*0c16b537SWarner Losh     const U32 btLow = btMask >= current ? 0 : current - btMask;
262*0c16b537SWarner Losh     const U32 windowLow = zc->lowLimit;
263*0c16b537SWarner Losh     U32* smallerPtr = bt + 2*(current&btMask);
264*0c16b537SWarner Losh     U32* largerPtr  = bt + 2*(current&btMask) + 1;
265*0c16b537SWarner Losh     U32 matchEndIdx = current+8;
266*0c16b537SWarner Losh     U32 dummy32;   /* to be nullified at the end */
267*0c16b537SWarner Losh     U32 mnum = 0;
268*0c16b537SWarner Losh 
269*0c16b537SWarner Losh     const U32 minMatch = (mls == 3) ? 3 : 4;
270*0c16b537SWarner Losh     size_t bestLength = minMatchLen-1;
271*0c16b537SWarner Losh 
272*0c16b537SWarner Losh     if (minMatch == 3) { /* HC3 match finder */
273*0c16b537SWarner Losh         U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3 (zc, ip);
274*0c16b537SWarner Losh         if (matchIndex3>windowLow && (current - matchIndex3 < (1<<18))) {
275*0c16b537SWarner Losh             const BYTE* match;
276*0c16b537SWarner Losh             size_t currentMl=0;
277*0c16b537SWarner Losh             if ((!extDict) || matchIndex3 >= dictLimit) {
278*0c16b537SWarner Losh                 match = base + matchIndex3;
279*0c16b537SWarner Losh                 if (match[bestLength] == ip[bestLength]) currentMl = ZSTD_count(ip, match, iLimit);
280*0c16b537SWarner Losh             } else {
281*0c16b537SWarner Losh                 match = dictBase + matchIndex3;
282*0c16b537SWarner Losh                 if (ZSTD_readMINMATCH(match, MINMATCH) == ZSTD_readMINMATCH(ip, MINMATCH))    /* assumption : matchIndex3 <= dictLimit-4 (by table construction) */
283*0c16b537SWarner Losh                     currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
284*0c16b537SWarner Losh             }
285*0c16b537SWarner Losh 
286*0c16b537SWarner Losh             /* save best solution */
287*0c16b537SWarner Losh             if (currentMl > bestLength) {
288*0c16b537SWarner Losh                 bestLength = currentMl;
289*0c16b537SWarner Losh                 matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex3;
290*0c16b537SWarner Losh                 matches[mnum].len = (U32)currentMl;
291*0c16b537SWarner Losh                 mnum++;
292*0c16b537SWarner Losh                 if (currentMl > ZSTD_OPT_NUM) goto update;
293*0c16b537SWarner Losh                 if (ip+currentMl == iLimit) goto update; /* best possible, and avoid read overflow*/
294*0c16b537SWarner Losh             }
295*0c16b537SWarner Losh         }
296*0c16b537SWarner Losh     }
297*0c16b537SWarner Losh 
298*0c16b537SWarner Losh     hashTable[h] = current;   /* Update Hash Table */
299*0c16b537SWarner Losh 
300*0c16b537SWarner Losh     while (nbCompares-- && (matchIndex > windowLow)) {
301*0c16b537SWarner Losh         U32* nextPtr = bt + 2*(matchIndex & btMask);
302*0c16b537SWarner Losh         size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
303*0c16b537SWarner Losh         const BYTE* match;
304*0c16b537SWarner Losh 
305*0c16b537SWarner Losh         if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
306*0c16b537SWarner Losh             match = base + matchIndex;
307*0c16b537SWarner Losh             if (match[matchLength] == ip[matchLength]) {
308*0c16b537SWarner Losh                 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iLimit) +1;
309*0c16b537SWarner Losh             }
310*0c16b537SWarner Losh         } else {
311*0c16b537SWarner Losh             match = dictBase + matchIndex;
312*0c16b537SWarner Losh             matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart);
313*0c16b537SWarner Losh             if (matchIndex+matchLength >= dictLimit)
314*0c16b537SWarner Losh                 match = base + matchIndex;   /* to prepare for next usage of match[matchLength] */
315*0c16b537SWarner Losh         }
316*0c16b537SWarner Losh 
317*0c16b537SWarner Losh         if (matchLength > bestLength) {
318*0c16b537SWarner Losh             if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength;
319*0c16b537SWarner Losh             bestLength = matchLength;
320*0c16b537SWarner Losh             matches[mnum].off = ZSTD_REP_MOVE_OPT + current - matchIndex;
321*0c16b537SWarner Losh             matches[mnum].len = (U32)matchLength;
322*0c16b537SWarner Losh             mnum++;
323*0c16b537SWarner Losh             if (matchLength > ZSTD_OPT_NUM) break;
324*0c16b537SWarner Losh             if (ip+matchLength == iLimit)   /* equal : no way to know if inf or sup */
325*0c16b537SWarner Losh                 break;   /* drop, to guarantee consistency (miss a little bit of compression) */
326*0c16b537SWarner Losh         }
327*0c16b537SWarner Losh 
328*0c16b537SWarner Losh         if (match[matchLength] < ip[matchLength]) {
329*0c16b537SWarner Losh             /* match is smaller than current */
330*0c16b537SWarner Losh             *smallerPtr = matchIndex;             /* update smaller idx */
331*0c16b537SWarner Losh             commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */
332*0c16b537SWarner Losh             if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
333*0c16b537SWarner Losh             smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */
334*0c16b537SWarner Losh             matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */
335*0c16b537SWarner Losh         } else {
336*0c16b537SWarner Losh             /* match is larger than current */
337*0c16b537SWarner Losh             *largerPtr = matchIndex;
338*0c16b537SWarner Losh             commonLengthLarger = matchLength;
339*0c16b537SWarner Losh             if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
340*0c16b537SWarner Losh             largerPtr = nextPtr;
341*0c16b537SWarner Losh             matchIndex = nextPtr[0];
342*0c16b537SWarner Losh     }   }
343*0c16b537SWarner Losh 
344*0c16b537SWarner Losh     *smallerPtr = *largerPtr = 0;
345*0c16b537SWarner Losh 
346*0c16b537SWarner Losh update:
347*0c16b537SWarner Losh     zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
348*0c16b537SWarner Losh     return mnum;
349*0c16b537SWarner Losh }
350*0c16b537SWarner Losh 
351*0c16b537SWarner Losh 
352*0c16b537SWarner Losh /** Tree updater, providing best match */
353*0c16b537SWarner Losh static U32 ZSTD_BtGetAllMatches (
354*0c16b537SWarner Losh                         ZSTD_CCtx* zc,
355*0c16b537SWarner Losh                         const BYTE* const ip, const BYTE* const iLimit,
356*0c16b537SWarner Losh                         const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen)
357*0c16b537SWarner Losh {
358*0c16b537SWarner Losh     if (ip < zc->base + zc->nextToUpdate) return 0;   /* skipped area */
359*0c16b537SWarner Losh     ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
360*0c16b537SWarner Losh     return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 0, matches, minMatchLen);
361*0c16b537SWarner Losh }
362*0c16b537SWarner Losh 
363*0c16b537SWarner Losh 
364*0c16b537SWarner Losh static U32 ZSTD_BtGetAllMatches_selectMLS (
365*0c16b537SWarner Losh                         ZSTD_CCtx* zc,   /* Index table will be updated */
366*0c16b537SWarner Losh                         const BYTE* ip, const BYTE* const iHighLimit,
367*0c16b537SWarner Losh                         const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen)
368*0c16b537SWarner Losh {
369*0c16b537SWarner Losh     switch(matchLengthSearch)
370*0c16b537SWarner Losh     {
371*0c16b537SWarner Losh     case 3 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
372*0c16b537SWarner Losh     default :
373*0c16b537SWarner Losh     case 4 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
374*0c16b537SWarner Losh     case 5 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
375*0c16b537SWarner Losh     case 7 :
376*0c16b537SWarner Losh     case 6 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
377*0c16b537SWarner Losh     }
378*0c16b537SWarner Losh }
379*0c16b537SWarner Losh 
380*0c16b537SWarner Losh /** Tree updater, providing best match */
381*0c16b537SWarner Losh static U32 ZSTD_BtGetAllMatches_extDict (
382*0c16b537SWarner Losh                         ZSTD_CCtx* zc,
383*0c16b537SWarner Losh                         const BYTE* const ip, const BYTE* const iLimit,
384*0c16b537SWarner Losh                         const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, const U32 minMatchLen)
385*0c16b537SWarner Losh {
386*0c16b537SWarner Losh     if (ip < zc->base + zc->nextToUpdate) return 0;   /* skipped area */
387*0c16b537SWarner Losh     ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
388*0c16b537SWarner Losh     return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 1, matches, minMatchLen);
389*0c16b537SWarner Losh }
390*0c16b537SWarner Losh 
391*0c16b537SWarner Losh 
392*0c16b537SWarner Losh static U32 ZSTD_BtGetAllMatches_selectMLS_extDict (
393*0c16b537SWarner Losh                         ZSTD_CCtx* zc,   /* Index table will be updated */
394*0c16b537SWarner Losh                         const BYTE* ip, const BYTE* const iHighLimit,
395*0c16b537SWarner Losh                         const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, const U32 minMatchLen)
396*0c16b537SWarner Losh {
397*0c16b537SWarner Losh     switch(matchLengthSearch)
398*0c16b537SWarner Losh     {
399*0c16b537SWarner Losh     case 3 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 3, matches, minMatchLen);
400*0c16b537SWarner Losh     default :
401*0c16b537SWarner Losh     case 4 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minMatchLen);
402*0c16b537SWarner Losh     case 5 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minMatchLen);
403*0c16b537SWarner Losh     case 7 :
404*0c16b537SWarner Losh     case 6 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minMatchLen);
405*0c16b537SWarner Losh     }
406*0c16b537SWarner Losh }
407*0c16b537SWarner Losh 
408*0c16b537SWarner Losh 
409*0c16b537SWarner Losh /*-*******************************
410*0c16b537SWarner Losh *  Optimal parser
411*0c16b537SWarner Losh *********************************/
412*0c16b537SWarner Losh FORCE_INLINE_TEMPLATE
413*0c16b537SWarner Losh size_t ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
414*0c16b537SWarner Losh                                       const void* src, size_t srcSize, const int ultra)
415*0c16b537SWarner Losh {
416*0c16b537SWarner Losh     seqStore_t* seqStorePtr = &(ctx->seqStore);
417*0c16b537SWarner Losh     optState_t* optStatePtr = &(ctx->optState);
418*0c16b537SWarner Losh     const BYTE* const istart = (const BYTE*)src;
419*0c16b537SWarner Losh     const BYTE* ip = istart;
420*0c16b537SWarner Losh     const BYTE* anchor = istart;
421*0c16b537SWarner Losh     const BYTE* const iend = istart + srcSize;
422*0c16b537SWarner Losh     const BYTE* const ilimit = iend - 8;
423*0c16b537SWarner Losh     const BYTE* const base = ctx->base;
424*0c16b537SWarner Losh     const BYTE* const prefixStart = base + ctx->dictLimit;
425*0c16b537SWarner Losh 
426*0c16b537SWarner Losh     const U32 maxSearches = 1U << ctx->appliedParams.cParams.searchLog;
427*0c16b537SWarner Losh     const U32 sufficient_len = ctx->appliedParams.cParams.targetLength;
428*0c16b537SWarner Losh     const U32 mls = ctx->appliedParams.cParams.searchLength;
429*0c16b537SWarner Losh     const U32 minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4;
430*0c16b537SWarner Losh 
431*0c16b537SWarner Losh     ZSTD_optimal_t* opt = optStatePtr->priceTable;
432*0c16b537SWarner Losh     ZSTD_match_t* matches = optStatePtr->matchTable;
433*0c16b537SWarner Losh     const BYTE* inr;
434*0c16b537SWarner Losh     U32 offset, rep[ZSTD_REP_NUM];
435*0c16b537SWarner Losh 
436*0c16b537SWarner Losh     /* init */
437*0c16b537SWarner Losh     ctx->nextToUpdate3 = ctx->nextToUpdate;
438*0c16b537SWarner Losh     ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
439*0c16b537SWarner Losh     ip += (ip==prefixStart);
440*0c16b537SWarner Losh     { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) rep[i]=seqStorePtr->rep[i]; }
441*0c16b537SWarner Losh 
442*0c16b537SWarner Losh     /* Match Loop */
443*0c16b537SWarner Losh     while (ip < ilimit) {
444*0c16b537SWarner Losh         U32 cur, match_num, last_pos, litlen, price;
445*0c16b537SWarner Losh         U32 u, mlen, best_mlen, best_off, litLength;
446*0c16b537SWarner Losh         memset(opt, 0, sizeof(ZSTD_optimal_t));
447*0c16b537SWarner Losh         last_pos = 0;
448*0c16b537SWarner Losh         litlen = (U32)(ip - anchor);
449*0c16b537SWarner Losh 
450*0c16b537SWarner Losh         /* check repCode */
451*0c16b537SWarner Losh         {   U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor);
452*0c16b537SWarner Losh             for (i=(ip == anchor); i<last_i; i++) {
453*0c16b537SWarner Losh                 const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i];
454*0c16b537SWarner Losh                 if ( (repCur > 0) && (repCur < (S32)(ip-prefixStart))
455*0c16b537SWarner Losh                     && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repCur, minMatch))) {
456*0c16b537SWarner Losh                     mlen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repCur, iend) + minMatch;
457*0c16b537SWarner Losh                     if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) {
458*0c16b537SWarner Losh                         best_mlen = mlen; best_off = i; cur = 0; last_pos = 1;
459*0c16b537SWarner Losh                         goto _storeSequence;
460*0c16b537SWarner Losh                     }
461*0c16b537SWarner Losh                     best_off = i - (ip == anchor);
462*0c16b537SWarner Losh                     do {
463*0c16b537SWarner Losh                         price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
464*0c16b537SWarner Losh                         if (mlen > last_pos || price < opt[mlen].price)
465*0c16b537SWarner Losh                             SET_PRICE(mlen, mlen, i, litlen, price);   /* note : macro modifies last_pos */
466*0c16b537SWarner Losh                         mlen--;
467*0c16b537SWarner Losh                     } while (mlen >= minMatch);
468*0c16b537SWarner Losh         }   }   }
469*0c16b537SWarner Losh 
470*0c16b537SWarner Losh         match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, ip, iend, maxSearches, mls, matches, minMatch);
471*0c16b537SWarner Losh 
472*0c16b537SWarner Losh         if (!last_pos && !match_num) { ip++; continue; }
473*0c16b537SWarner Losh 
474*0c16b537SWarner Losh         if (match_num && (matches[match_num-1].len > sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) {
475*0c16b537SWarner Losh             best_mlen = matches[match_num-1].len;
476*0c16b537SWarner Losh             best_off = matches[match_num-1].off;
477*0c16b537SWarner Losh             cur = 0;
478*0c16b537SWarner Losh             last_pos = 1;
479*0c16b537SWarner Losh             goto _storeSequence;
480*0c16b537SWarner Losh         }
481*0c16b537SWarner Losh 
482*0c16b537SWarner Losh         /* set prices using matches at position = 0 */
483*0c16b537SWarner Losh         best_mlen = (last_pos) ? last_pos : minMatch;
484*0c16b537SWarner Losh         for (u = 0; u < match_num; u++) {
485*0c16b537SWarner Losh             mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
486*0c16b537SWarner Losh             best_mlen = matches[u].len;
487*0c16b537SWarner Losh             while (mlen <= best_mlen) {
488*0c16b537SWarner Losh                 price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
489*0c16b537SWarner Losh                 if (mlen > last_pos || price < opt[mlen].price)
490*0c16b537SWarner Losh                     SET_PRICE(mlen, mlen, matches[u].off, litlen, price);   /* note : macro modifies last_pos */
491*0c16b537SWarner Losh                 mlen++;
492*0c16b537SWarner Losh         }   }
493*0c16b537SWarner Losh 
494*0c16b537SWarner Losh         if (last_pos < minMatch) { ip++; continue; }
495*0c16b537SWarner Losh 
496*0c16b537SWarner Losh         /* initialize opt[0] */
497*0c16b537SWarner Losh         { U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
498*0c16b537SWarner Losh         opt[0].mlen = 1;
499*0c16b537SWarner Losh         opt[0].litlen = litlen;
500*0c16b537SWarner Losh 
501*0c16b537SWarner Losh          /* check further positions */
502*0c16b537SWarner Losh         for (cur = 1; cur <= last_pos; cur++) {
503*0c16b537SWarner Losh            inr = ip + cur;
504*0c16b537SWarner Losh 
505*0c16b537SWarner Losh            if (opt[cur-1].mlen == 1) {
506*0c16b537SWarner Losh                 litlen = opt[cur-1].litlen + 1;
507*0c16b537SWarner Losh                 if (cur > litlen) {
508*0c16b537SWarner Losh                     price = opt[cur - litlen].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-litlen);
509*0c16b537SWarner Losh                 } else
510*0c16b537SWarner Losh                     price = ZSTD_getLiteralPrice(optStatePtr, litlen, anchor);
511*0c16b537SWarner Losh            } else {
512*0c16b537SWarner Losh                 litlen = 1;
513*0c16b537SWarner Losh                 price = opt[cur - 1].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-1);
514*0c16b537SWarner Losh            }
515*0c16b537SWarner Losh 
516*0c16b537SWarner Losh            if (cur > last_pos || price <= opt[cur].price)
517*0c16b537SWarner Losh                 SET_PRICE(cur, 1, 0, litlen, price);
518*0c16b537SWarner Losh 
519*0c16b537SWarner Losh            if (cur == last_pos) break;
520*0c16b537SWarner Losh 
521*0c16b537SWarner Losh            if (inr > ilimit)  /* last match must start at a minimum distance of 8 from oend */
522*0c16b537SWarner Losh                continue;
523*0c16b537SWarner Losh 
524*0c16b537SWarner Losh            mlen = opt[cur].mlen;
525*0c16b537SWarner Losh            if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
526*0c16b537SWarner Losh                 opt[cur].rep[2] = opt[cur-mlen].rep[1];
527*0c16b537SWarner Losh                 opt[cur].rep[1] = opt[cur-mlen].rep[0];
528*0c16b537SWarner Losh                 opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT;
529*0c16b537SWarner Losh            } else {
530*0c16b537SWarner Losh                 opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2];
531*0c16b537SWarner Losh                 opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1];
532*0c16b537SWarner Losh                 /* If opt[cur].off == ZSTD_REP_MOVE_OPT, then mlen != 1.
533*0c16b537SWarner Losh                  * offset ZSTD_REP_MOVE_OPT is used for the special case
534*0c16b537SWarner Losh                  * litLength == 0, where offset 0 means something special.
535*0c16b537SWarner Losh                  * mlen == 1 means the previous byte was stored as a literal,
536*0c16b537SWarner Losh                  * so they are mutually exclusive.
537*0c16b537SWarner Losh                  */
538*0c16b537SWarner Losh                 assert(!(opt[cur].off == ZSTD_REP_MOVE_OPT && mlen == 1));
539*0c16b537SWarner Losh                 opt[cur].rep[0] = (opt[cur].off == ZSTD_REP_MOVE_OPT) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
540*0c16b537SWarner Losh            }
541*0c16b537SWarner Losh 
542*0c16b537SWarner Losh             best_mlen = minMatch;
543*0c16b537SWarner Losh             {   U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
544*0c16b537SWarner Losh                 for (i=(opt[cur].mlen != 1); i<last_i; i++) {  /* check rep */
545*0c16b537SWarner Losh                     const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i];
546*0c16b537SWarner Losh                     if ( (repCur > 0) && (repCur < (S32)(inr-prefixStart))
547*0c16b537SWarner Losh                        && (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(inr - repCur, minMatch))) {
548*0c16b537SWarner Losh                        mlen = (U32)ZSTD_count(inr+minMatch, inr+minMatch - repCur, iend) + minMatch;
549*0c16b537SWarner Losh 
550*0c16b537SWarner Losh                        if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
551*0c16b537SWarner Losh                             best_mlen = mlen; best_off = i; last_pos = cur + 1;
552*0c16b537SWarner Losh                             goto _storeSequence;
553*0c16b537SWarner Losh                        }
554*0c16b537SWarner Losh 
555*0c16b537SWarner Losh                        best_off = i - (opt[cur].mlen != 1);
556*0c16b537SWarner Losh                        if (mlen > best_mlen) best_mlen = mlen;
557*0c16b537SWarner Losh 
558*0c16b537SWarner Losh                        do {
559*0c16b537SWarner Losh                            if (opt[cur].mlen == 1) {
560*0c16b537SWarner Losh                                 litlen = opt[cur].litlen;
561*0c16b537SWarner Losh                                 if (cur > litlen) {
562*0c16b537SWarner Losh                                     price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra);
563*0c16b537SWarner Losh                                 } else
564*0c16b537SWarner Losh                                     price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
565*0c16b537SWarner Losh                             } else {
566*0c16b537SWarner Losh                                 litlen = 0;
567*0c16b537SWarner Losh                                 price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, best_off, mlen - MINMATCH, ultra);
568*0c16b537SWarner Losh                             }
569*0c16b537SWarner Losh 
570*0c16b537SWarner Losh                             if (cur + mlen > last_pos || price <= opt[cur + mlen].price)
571*0c16b537SWarner Losh                                 SET_PRICE(cur + mlen, mlen, i, litlen, price);
572*0c16b537SWarner Losh                             mlen--;
573*0c16b537SWarner Losh                         } while (mlen >= minMatch);
574*0c16b537SWarner Losh             }   }   }
575*0c16b537SWarner Losh 
576*0c16b537SWarner Losh             match_num = ZSTD_BtGetAllMatches_selectMLS(ctx, inr, iend, maxSearches, mls, matches, best_mlen);
577*0c16b537SWarner Losh 
578*0c16b537SWarner Losh             if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) {
579*0c16b537SWarner Losh                 best_mlen = matches[match_num-1].len;
580*0c16b537SWarner Losh                 best_off = matches[match_num-1].off;
581*0c16b537SWarner Losh                 last_pos = cur + 1;
582*0c16b537SWarner Losh                 goto _storeSequence;
583*0c16b537SWarner Losh             }
584*0c16b537SWarner Losh 
585*0c16b537SWarner Losh             /* set prices using matches at position = cur */
586*0c16b537SWarner Losh             for (u = 0; u < match_num; u++) {
587*0c16b537SWarner Losh                 mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
588*0c16b537SWarner Losh                 best_mlen = matches[u].len;
589*0c16b537SWarner Losh 
590*0c16b537SWarner Losh                 while (mlen <= best_mlen) {
591*0c16b537SWarner Losh                     if (opt[cur].mlen == 1) {
592*0c16b537SWarner Losh                         litlen = opt[cur].litlen;
593*0c16b537SWarner Losh                         if (cur > litlen)
594*0c16b537SWarner Losh                             price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra);
595*0c16b537SWarner Losh                         else
596*0c16b537SWarner Losh                             price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
597*0c16b537SWarner Losh                     } else {
598*0c16b537SWarner Losh                         litlen = 0;
599*0c16b537SWarner Losh                         price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra);
600*0c16b537SWarner Losh                     }
601*0c16b537SWarner Losh 
602*0c16b537SWarner Losh                     if (cur + mlen > last_pos || (price < opt[cur + mlen].price))
603*0c16b537SWarner Losh                         SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price);
604*0c16b537SWarner Losh 
605*0c16b537SWarner Losh                     mlen++;
606*0c16b537SWarner Losh         }   }   }
607*0c16b537SWarner Losh 
608*0c16b537SWarner Losh         best_mlen = opt[last_pos].mlen;
609*0c16b537SWarner Losh         best_off = opt[last_pos].off;
610*0c16b537SWarner Losh         cur = last_pos - best_mlen;
611*0c16b537SWarner Losh 
612*0c16b537SWarner Losh         /* store sequence */
613*0c16b537SWarner Losh _storeSequence:   /* cur, last_pos, best_mlen, best_off have to be set */
614*0c16b537SWarner Losh         opt[0].mlen = 1;
615*0c16b537SWarner Losh 
616*0c16b537SWarner Losh         while (1) {
617*0c16b537SWarner Losh             mlen = opt[cur].mlen;
618*0c16b537SWarner Losh             offset = opt[cur].off;
619*0c16b537SWarner Losh             opt[cur].mlen = best_mlen;
620*0c16b537SWarner Losh             opt[cur].off = best_off;
621*0c16b537SWarner Losh             best_mlen = mlen;
622*0c16b537SWarner Losh             best_off = offset;
623*0c16b537SWarner Losh             if (mlen > cur) break;
624*0c16b537SWarner Losh             cur -= mlen;
625*0c16b537SWarner Losh         }
626*0c16b537SWarner Losh 
627*0c16b537SWarner Losh         for (u = 0; u <= last_pos;) {
628*0c16b537SWarner Losh             u += opt[u].mlen;
629*0c16b537SWarner Losh         }
630*0c16b537SWarner Losh 
631*0c16b537SWarner Losh         for (cur=0; cur < last_pos; ) {
632*0c16b537SWarner Losh             mlen = opt[cur].mlen;
633*0c16b537SWarner Losh             if (mlen == 1) { ip++; cur++; continue; }
634*0c16b537SWarner Losh             offset = opt[cur].off;
635*0c16b537SWarner Losh             cur += mlen;
636*0c16b537SWarner Losh             litLength = (U32)(ip - anchor);
637*0c16b537SWarner Losh 
638*0c16b537SWarner Losh             if (offset > ZSTD_REP_MOVE_OPT) {
639*0c16b537SWarner Losh                 rep[2] = rep[1];
640*0c16b537SWarner Losh                 rep[1] = rep[0];
641*0c16b537SWarner Losh                 rep[0] = offset - ZSTD_REP_MOVE_OPT;
642*0c16b537SWarner Losh                 offset--;
643*0c16b537SWarner Losh             } else {
644*0c16b537SWarner Losh                 if (offset != 0) {
645*0c16b537SWarner Losh                     best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
646*0c16b537SWarner Losh                     if (offset != 1) rep[2] = rep[1];
647*0c16b537SWarner Losh                     rep[1] = rep[0];
648*0c16b537SWarner Losh                     rep[0] = best_off;
649*0c16b537SWarner Losh                 }
650*0c16b537SWarner Losh                 if (litLength==0) offset--;
651*0c16b537SWarner Losh             }
652*0c16b537SWarner Losh 
653*0c16b537SWarner Losh             ZSTD_updatePrice(optStatePtr, litLength, anchor, offset, mlen-MINMATCH);
654*0c16b537SWarner Losh             ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
655*0c16b537SWarner Losh             anchor = ip = ip + mlen;
656*0c16b537SWarner Losh     }    }   /* for (cur=0; cur < last_pos; ) */
657*0c16b537SWarner Losh 
658*0c16b537SWarner Losh     /* Save reps for next block */
659*0c16b537SWarner Losh     { int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->repToConfirm[i] = rep[i]; }
660*0c16b537SWarner Losh 
661*0c16b537SWarner Losh     /* Return the last literals size */
662*0c16b537SWarner Losh     return iend - anchor;
663*0c16b537SWarner Losh }
664*0c16b537SWarner Losh 
665*0c16b537SWarner Losh 
666*0c16b537SWarner Losh size_t ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
667*0c16b537SWarner Losh {
668*0c16b537SWarner Losh     return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
669*0c16b537SWarner Losh }
670*0c16b537SWarner Losh 
671*0c16b537SWarner Losh size_t ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
672*0c16b537SWarner Losh {
673*0c16b537SWarner Losh     return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
674*0c16b537SWarner Losh }
675*0c16b537SWarner Losh 
676*0c16b537SWarner Losh 
677*0c16b537SWarner Losh FORCE_INLINE_TEMPLATE
678*0c16b537SWarner Losh size_t ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx,
679*0c16b537SWarner Losh                                      const void* src, size_t srcSize, const int ultra)
680*0c16b537SWarner Losh {
681*0c16b537SWarner Losh     seqStore_t* seqStorePtr = &(ctx->seqStore);
682*0c16b537SWarner Losh     optState_t* optStatePtr = &(ctx->optState);
683*0c16b537SWarner Losh     const BYTE* const istart = (const BYTE*)src;
684*0c16b537SWarner Losh     const BYTE* ip = istart;
685*0c16b537SWarner Losh     const BYTE* anchor = istart;
686*0c16b537SWarner Losh     const BYTE* const iend = istart + srcSize;
687*0c16b537SWarner Losh     const BYTE* const ilimit = iend - 8;
688*0c16b537SWarner Losh     const BYTE* const base = ctx->base;
689*0c16b537SWarner Losh     const U32 lowestIndex = ctx->lowLimit;
690*0c16b537SWarner Losh     const U32 dictLimit = ctx->dictLimit;
691*0c16b537SWarner Losh     const BYTE* const prefixStart = base + dictLimit;
692*0c16b537SWarner Losh     const BYTE* const dictBase = ctx->dictBase;
693*0c16b537SWarner Losh     const BYTE* const dictEnd  = dictBase + dictLimit;
694*0c16b537SWarner Losh 
695*0c16b537SWarner Losh     const U32 maxSearches = 1U << ctx->appliedParams.cParams.searchLog;
696*0c16b537SWarner Losh     const U32 sufficient_len = ctx->appliedParams.cParams.targetLength;
697*0c16b537SWarner Losh     const U32 mls = ctx->appliedParams.cParams.searchLength;
698*0c16b537SWarner Losh     const U32 minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4;
699*0c16b537SWarner Losh 
700*0c16b537SWarner Losh     ZSTD_optimal_t* opt = optStatePtr->priceTable;
701*0c16b537SWarner Losh     ZSTD_match_t* matches = optStatePtr->matchTable;
702*0c16b537SWarner Losh     const BYTE* inr;
703*0c16b537SWarner Losh 
704*0c16b537SWarner Losh     /* init */
705*0c16b537SWarner Losh     U32 offset, rep[ZSTD_REP_NUM];
706*0c16b537SWarner Losh     { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) rep[i]=seqStorePtr->rep[i]; }
707*0c16b537SWarner Losh 
708*0c16b537SWarner Losh     ctx->nextToUpdate3 = ctx->nextToUpdate;
709*0c16b537SWarner Losh     ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
710*0c16b537SWarner Losh     ip += (ip==prefixStart);
711*0c16b537SWarner Losh 
712*0c16b537SWarner Losh     /* Match Loop */
713*0c16b537SWarner Losh     while (ip < ilimit) {
714*0c16b537SWarner Losh         U32 cur, match_num, last_pos, litlen, price;
715*0c16b537SWarner Losh         U32 u, mlen, best_mlen, best_off, litLength;
716*0c16b537SWarner Losh         U32 current = (U32)(ip-base);
717*0c16b537SWarner Losh         memset(opt, 0, sizeof(ZSTD_optimal_t));
718*0c16b537SWarner Losh         last_pos = 0;
719*0c16b537SWarner Losh         opt[0].litlen = (U32)(ip - anchor);
720*0c16b537SWarner Losh 
721*0c16b537SWarner Losh         /* check repCode */
722*0c16b537SWarner Losh         {   U32 i, last_i = ZSTD_REP_CHECK + (ip==anchor);
723*0c16b537SWarner Losh             for (i = (ip==anchor); i<last_i; i++) {
724*0c16b537SWarner Losh                 const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : rep[i];
725*0c16b537SWarner Losh                 const U32 repIndex = (U32)(current - repCur);
726*0c16b537SWarner Losh                 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
727*0c16b537SWarner Losh                 const BYTE* const repMatch = repBase + repIndex;
728*0c16b537SWarner Losh                 if ( (repCur > 0 && repCur <= (S32)current)
729*0c16b537SWarner Losh                    && (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex))  /* intentional overflow */
730*0c16b537SWarner Losh                    && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
731*0c16b537SWarner Losh                     /* repcode detected we should take it */
732*0c16b537SWarner Losh                     const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
733*0c16b537SWarner Losh                     mlen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch;
734*0c16b537SWarner Losh 
735*0c16b537SWarner Losh                     if (mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) {
736*0c16b537SWarner Losh                         best_mlen = mlen; best_off = i; cur = 0; last_pos = 1;
737*0c16b537SWarner Losh                         goto _storeSequence;
738*0c16b537SWarner Losh                     }
739*0c16b537SWarner Losh 
740*0c16b537SWarner Losh                     best_off = i - (ip==anchor);
741*0c16b537SWarner Losh                     litlen = opt[0].litlen;
742*0c16b537SWarner Losh                     do {
743*0c16b537SWarner Losh                         price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
744*0c16b537SWarner Losh                         if (mlen > last_pos || price < opt[mlen].price)
745*0c16b537SWarner Losh                             SET_PRICE(mlen, mlen, i, litlen, price);   /* note : macro modifies last_pos */
746*0c16b537SWarner Losh                         mlen--;
747*0c16b537SWarner Losh                     } while (mlen >= minMatch);
748*0c16b537SWarner Losh         }   }   }
749*0c16b537SWarner Losh 
750*0c16b537SWarner Losh         match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, ip, iend, maxSearches, mls, matches, minMatch);  /* first search (depth 0) */
751*0c16b537SWarner Losh 
752*0c16b537SWarner Losh         if (!last_pos && !match_num) { ip++; continue; }
753*0c16b537SWarner Losh 
754*0c16b537SWarner Losh         { U32 i; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
755*0c16b537SWarner Losh         opt[0].mlen = 1;
756*0c16b537SWarner Losh 
757*0c16b537SWarner Losh         if (match_num && (matches[match_num-1].len > sufficient_len || matches[match_num-1].len >= ZSTD_OPT_NUM)) {
758*0c16b537SWarner Losh             best_mlen = matches[match_num-1].len;
759*0c16b537SWarner Losh             best_off = matches[match_num-1].off;
760*0c16b537SWarner Losh             cur = 0;
761*0c16b537SWarner Losh             last_pos = 1;
762*0c16b537SWarner Losh             goto _storeSequence;
763*0c16b537SWarner Losh         }
764*0c16b537SWarner Losh 
765*0c16b537SWarner Losh         best_mlen = (last_pos) ? last_pos : minMatch;
766*0c16b537SWarner Losh 
767*0c16b537SWarner Losh         /* set prices using matches at position = 0 */
768*0c16b537SWarner Losh         for (u = 0; u < match_num; u++) {
769*0c16b537SWarner Losh             mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
770*0c16b537SWarner Losh             best_mlen = matches[u].len;
771*0c16b537SWarner Losh             litlen = opt[0].litlen;
772*0c16b537SWarner Losh             while (mlen <= best_mlen) {
773*0c16b537SWarner Losh                 price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
774*0c16b537SWarner Losh                 if (mlen > last_pos || price < opt[mlen].price)
775*0c16b537SWarner Losh                     SET_PRICE(mlen, mlen, matches[u].off, litlen, price);
776*0c16b537SWarner Losh                 mlen++;
777*0c16b537SWarner Losh         }   }
778*0c16b537SWarner Losh 
779*0c16b537SWarner Losh         if (last_pos < minMatch) {
780*0c16b537SWarner Losh             ip++; continue;
781*0c16b537SWarner Losh         }
782*0c16b537SWarner Losh 
783*0c16b537SWarner Losh         /* check further positions */
784*0c16b537SWarner Losh         for (cur = 1; cur <= last_pos; cur++) {
785*0c16b537SWarner Losh             inr = ip + cur;
786*0c16b537SWarner Losh 
787*0c16b537SWarner Losh             if (opt[cur-1].mlen == 1) {
788*0c16b537SWarner Losh                 litlen = opt[cur-1].litlen + 1;
789*0c16b537SWarner Losh                 if (cur > litlen) {
790*0c16b537SWarner Losh                     price = opt[cur - litlen].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-litlen);
791*0c16b537SWarner Losh                 } else
792*0c16b537SWarner Losh                     price = ZSTD_getLiteralPrice(optStatePtr, litlen, anchor);
793*0c16b537SWarner Losh             } else {
794*0c16b537SWarner Losh                 litlen = 1;
795*0c16b537SWarner Losh                 price = opt[cur - 1].price + ZSTD_getLiteralPrice(optStatePtr, litlen, inr-1);
796*0c16b537SWarner Losh             }
797*0c16b537SWarner Losh 
798*0c16b537SWarner Losh             if (cur > last_pos || price <= opt[cur].price)
799*0c16b537SWarner Losh                 SET_PRICE(cur, 1, 0, litlen, price);
800*0c16b537SWarner Losh 
801*0c16b537SWarner Losh             if (cur == last_pos) break;
802*0c16b537SWarner Losh 
803*0c16b537SWarner Losh             if (inr > ilimit)  /* last match must start at a minimum distance of 8 from oend */
804*0c16b537SWarner Losh                 continue;
805*0c16b537SWarner Losh 
806*0c16b537SWarner Losh             mlen = opt[cur].mlen;
807*0c16b537SWarner Losh             if (opt[cur].off > ZSTD_REP_MOVE_OPT) {
808*0c16b537SWarner Losh                 opt[cur].rep[2] = opt[cur-mlen].rep[1];
809*0c16b537SWarner Losh                 opt[cur].rep[1] = opt[cur-mlen].rep[0];
810*0c16b537SWarner Losh                 opt[cur].rep[0] = opt[cur].off - ZSTD_REP_MOVE_OPT;
811*0c16b537SWarner Losh             } else {
812*0c16b537SWarner Losh                 opt[cur].rep[2] = (opt[cur].off > 1) ? opt[cur-mlen].rep[1] : opt[cur-mlen].rep[2];
813*0c16b537SWarner Losh                 opt[cur].rep[1] = (opt[cur].off > 0) ? opt[cur-mlen].rep[0] : opt[cur-mlen].rep[1];
814*0c16b537SWarner Losh                 assert(!(opt[cur].off == ZSTD_REP_MOVE_OPT && mlen == 1));
815*0c16b537SWarner Losh                 opt[cur].rep[0] = (opt[cur].off == ZSTD_REP_MOVE_OPT) ? (opt[cur-mlen].rep[0] - 1) : (opt[cur-mlen].rep[opt[cur].off]);
816*0c16b537SWarner Losh             }
817*0c16b537SWarner Losh 
818*0c16b537SWarner Losh             best_mlen = minMatch;
819*0c16b537SWarner Losh             {   U32 i, last_i = ZSTD_REP_CHECK + (mlen != 1);
820*0c16b537SWarner Losh                 for (i = (mlen != 1); i<last_i; i++) {
821*0c16b537SWarner Losh                     const S32 repCur = (i==ZSTD_REP_MOVE_OPT) ? (opt[cur].rep[0] - 1) : opt[cur].rep[i];
822*0c16b537SWarner Losh                     const U32 repIndex = (U32)(current+cur - repCur);
823*0c16b537SWarner Losh                     const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
824*0c16b537SWarner Losh                     const BYTE* const repMatch = repBase + repIndex;
825*0c16b537SWarner Losh                     if ( (repCur > 0 && repCur <= (S32)(current+cur))
826*0c16b537SWarner Losh                       && (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex>lowestIndex))  /* intentional overflow */
827*0c16b537SWarner Losh                       && (ZSTD_readMINMATCH(inr, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
828*0c16b537SWarner Losh                         /* repcode detected */
829*0c16b537SWarner Losh                         const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
830*0c16b537SWarner Losh                         mlen = (U32)ZSTD_count_2segments(inr+minMatch, repMatch+minMatch, iend, repEnd, prefixStart) + minMatch;
831*0c16b537SWarner Losh 
832*0c16b537SWarner Losh                         if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) {
833*0c16b537SWarner Losh                             best_mlen = mlen; best_off = i; last_pos = cur + 1;
834*0c16b537SWarner Losh                             goto _storeSequence;
835*0c16b537SWarner Losh                         }
836*0c16b537SWarner Losh 
837*0c16b537SWarner Losh                         best_off = i - (opt[cur].mlen != 1);
838*0c16b537SWarner Losh                         if (mlen > best_mlen) best_mlen = mlen;
839*0c16b537SWarner Losh 
840*0c16b537SWarner Losh                         do {
841*0c16b537SWarner Losh                             if (opt[cur].mlen == 1) {
842*0c16b537SWarner Losh                                 litlen = opt[cur].litlen;
843*0c16b537SWarner Losh                                 if (cur > litlen) {
844*0c16b537SWarner Losh                                     price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, inr-litlen, best_off, mlen - MINMATCH, ultra);
845*0c16b537SWarner Losh                                 } else
846*0c16b537SWarner Losh                                     price = ZSTD_getPrice(optStatePtr, litlen, anchor, best_off, mlen - MINMATCH, ultra);
847*0c16b537SWarner Losh                             } else {
848*0c16b537SWarner Losh                                 litlen = 0;
849*0c16b537SWarner Losh                                 price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, best_off, mlen - MINMATCH, ultra);
850*0c16b537SWarner Losh                             }
851*0c16b537SWarner Losh 
852*0c16b537SWarner Losh                             if (cur + mlen > last_pos || price <= opt[cur + mlen].price)
853*0c16b537SWarner Losh                                 SET_PRICE(cur + mlen, mlen, i, litlen, price);
854*0c16b537SWarner Losh                             mlen--;
855*0c16b537SWarner Losh                         } while (mlen >= minMatch);
856*0c16b537SWarner Losh             }   }   }
857*0c16b537SWarner Losh 
858*0c16b537SWarner Losh             match_num = ZSTD_BtGetAllMatches_selectMLS_extDict(ctx, inr, iend, maxSearches, mls, matches, minMatch);
859*0c16b537SWarner Losh 
860*0c16b537SWarner Losh             if (match_num > 0 && (matches[match_num-1].len > sufficient_len || cur + matches[match_num-1].len >= ZSTD_OPT_NUM)) {
861*0c16b537SWarner Losh                 best_mlen = matches[match_num-1].len;
862*0c16b537SWarner Losh                 best_off = matches[match_num-1].off;
863*0c16b537SWarner Losh                 last_pos = cur + 1;
864*0c16b537SWarner Losh                 goto _storeSequence;
865*0c16b537SWarner Losh             }
866*0c16b537SWarner Losh 
867*0c16b537SWarner Losh             /* set prices using matches at position = cur */
868*0c16b537SWarner Losh             for (u = 0; u < match_num; u++) {
869*0c16b537SWarner Losh                 mlen = (u>0) ? matches[u-1].len+1 : best_mlen;
870*0c16b537SWarner Losh                 best_mlen = matches[u].len;
871*0c16b537SWarner Losh 
872*0c16b537SWarner Losh                 while (mlen <= best_mlen) {
873*0c16b537SWarner Losh                     if (opt[cur].mlen == 1) {
874*0c16b537SWarner Losh                         litlen = opt[cur].litlen;
875*0c16b537SWarner Losh                         if (cur > litlen)
876*0c16b537SWarner Losh                             price = opt[cur - litlen].price + ZSTD_getPrice(optStatePtr, litlen, ip+cur-litlen, matches[u].off-1, mlen - MINMATCH, ultra);
877*0c16b537SWarner Losh                         else
878*0c16b537SWarner Losh                             price = ZSTD_getPrice(optStatePtr, litlen, anchor, matches[u].off-1, mlen - MINMATCH, ultra);
879*0c16b537SWarner Losh                     } else {
880*0c16b537SWarner Losh                         litlen = 0;
881*0c16b537SWarner Losh                         price = opt[cur].price + ZSTD_getPrice(optStatePtr, 0, NULL, matches[u].off-1, mlen - MINMATCH, ultra);
882*0c16b537SWarner Losh                     }
883*0c16b537SWarner Losh 
884*0c16b537SWarner Losh                     if (cur + mlen > last_pos || (price < opt[cur + mlen].price))
885*0c16b537SWarner Losh                         SET_PRICE(cur + mlen, mlen, matches[u].off, litlen, price);
886*0c16b537SWarner Losh 
887*0c16b537SWarner Losh                     mlen++;
888*0c16b537SWarner Losh         }   }   }   /* for (cur = 1; cur <= last_pos; cur++) */
889*0c16b537SWarner Losh 
890*0c16b537SWarner Losh         best_mlen = opt[last_pos].mlen;
891*0c16b537SWarner Losh         best_off = opt[last_pos].off;
892*0c16b537SWarner Losh         cur = last_pos - best_mlen;
893*0c16b537SWarner Losh 
894*0c16b537SWarner Losh         /* store sequence */
895*0c16b537SWarner Losh _storeSequence:   /* cur, last_pos, best_mlen, best_off have to be set */
896*0c16b537SWarner Losh         opt[0].mlen = 1;
897*0c16b537SWarner Losh 
898*0c16b537SWarner Losh         while (1) {
899*0c16b537SWarner Losh             mlen = opt[cur].mlen;
900*0c16b537SWarner Losh             offset = opt[cur].off;
901*0c16b537SWarner Losh             opt[cur].mlen = best_mlen;
902*0c16b537SWarner Losh             opt[cur].off = best_off;
903*0c16b537SWarner Losh             best_mlen = mlen;
904*0c16b537SWarner Losh             best_off = offset;
905*0c16b537SWarner Losh             if (mlen > cur) break;
906*0c16b537SWarner Losh             cur -= mlen;
907*0c16b537SWarner Losh         }
908*0c16b537SWarner Losh 
909*0c16b537SWarner Losh         for (u = 0; u <= last_pos; ) {
910*0c16b537SWarner Losh             u += opt[u].mlen;
911*0c16b537SWarner Losh         }
912*0c16b537SWarner Losh 
913*0c16b537SWarner Losh         for (cur=0; cur < last_pos; ) {
914*0c16b537SWarner Losh             mlen = opt[cur].mlen;
915*0c16b537SWarner Losh             if (mlen == 1) { ip++; cur++; continue; }
916*0c16b537SWarner Losh             offset = opt[cur].off;
917*0c16b537SWarner Losh             cur += mlen;
918*0c16b537SWarner Losh             litLength = (U32)(ip - anchor);
919*0c16b537SWarner Losh 
920*0c16b537SWarner Losh             if (offset > ZSTD_REP_MOVE_OPT) {
921*0c16b537SWarner Losh                 rep[2] = rep[1];
922*0c16b537SWarner Losh                 rep[1] = rep[0];
923*0c16b537SWarner Losh                 rep[0] = offset - ZSTD_REP_MOVE_OPT;
924*0c16b537SWarner Losh                 offset--;
925*0c16b537SWarner Losh             } else {
926*0c16b537SWarner Losh                 if (offset != 0) {
927*0c16b537SWarner Losh                     best_off = (offset==ZSTD_REP_MOVE_OPT) ? (rep[0] - 1) : (rep[offset]);
928*0c16b537SWarner Losh                     if (offset != 1) rep[2] = rep[1];
929*0c16b537SWarner Losh                     rep[1] = rep[0];
930*0c16b537SWarner Losh                     rep[0] = best_off;
931*0c16b537SWarner Losh                 }
932*0c16b537SWarner Losh 
933*0c16b537SWarner Losh                 if (litLength==0) offset--;
934*0c16b537SWarner Losh             }
935*0c16b537SWarner Losh 
936*0c16b537SWarner Losh             ZSTD_updatePrice(optStatePtr, litLength, anchor, offset, mlen-MINMATCH);
937*0c16b537SWarner Losh             ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH);
938*0c16b537SWarner Losh             anchor = ip = ip + mlen;
939*0c16b537SWarner Losh     }    }   /* for (cur=0; cur < last_pos; ) */
940*0c16b537SWarner Losh 
941*0c16b537SWarner Losh     /* Save reps for next block */
942*0c16b537SWarner Losh     { int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->repToConfirm[i] = rep[i]; }
943*0c16b537SWarner Losh 
944*0c16b537SWarner Losh     /* Return the last literals size */
945*0c16b537SWarner Losh     return iend - anchor;
946*0c16b537SWarner Losh }
947*0c16b537SWarner Losh 
948*0c16b537SWarner Losh 
949*0c16b537SWarner Losh size_t ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
950*0c16b537SWarner Losh {
951*0c16b537SWarner Losh     return ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
952*0c16b537SWarner Losh }
953*0c16b537SWarner Losh 
954*0c16b537SWarner Losh size_t ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
955*0c16b537SWarner Losh {
956*0c16b537SWarner Losh     return ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
957*0c16b537SWarner Losh }
958