comparison contrib/python-zstandard/zstd/compress/zstd_opt.h @ 30434:2e484bdea8c4

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