1e0c1b49fSNick Terrell /*
2e0c1b49fSNick Terrell * Copyright (c) Yann Collet, Facebook, Inc.
3e0c1b49fSNick Terrell * All rights reserved.
4e0c1b49fSNick Terrell *
5e0c1b49fSNick Terrell * This source code is licensed under both the BSD-style license (found in the
6e0c1b49fSNick Terrell * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7e0c1b49fSNick Terrell * in the COPYING file in the root directory of this source tree).
8e0c1b49fSNick Terrell * You may select, at your option, one of the above-listed licenses.
9e0c1b49fSNick Terrell */
10e0c1b49fSNick Terrell
11e0c1b49fSNick Terrell #include "zstd_compress_internal.h"
12e0c1b49fSNick Terrell #include "zstd_double_fast.h"
13e0c1b49fSNick Terrell
14e0c1b49fSNick Terrell
ZSTD_fillDoubleHashTable(ZSTD_matchState_t * ms,void const * end,ZSTD_dictTableLoadMethod_e dtlm)15e0c1b49fSNick Terrell void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
16e0c1b49fSNick Terrell void const* end, ZSTD_dictTableLoadMethod_e dtlm)
17e0c1b49fSNick Terrell {
18e0c1b49fSNick Terrell const ZSTD_compressionParameters* const cParams = &ms->cParams;
19e0c1b49fSNick Terrell U32* const hashLarge = ms->hashTable;
20e0c1b49fSNick Terrell U32 const hBitsL = cParams->hashLog;
21e0c1b49fSNick Terrell U32 const mls = cParams->minMatch;
22e0c1b49fSNick Terrell U32* const hashSmall = ms->chainTable;
23e0c1b49fSNick Terrell U32 const hBitsS = cParams->chainLog;
24e0c1b49fSNick Terrell const BYTE* const base = ms->window.base;
25e0c1b49fSNick Terrell const BYTE* ip = base + ms->nextToUpdate;
26e0c1b49fSNick Terrell const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
27e0c1b49fSNick Terrell const U32 fastHashFillStep = 3;
28e0c1b49fSNick Terrell
29e0c1b49fSNick Terrell /* Always insert every fastHashFillStep position into the hash tables.
30e0c1b49fSNick Terrell * Insert the other positions into the large hash table if their entry
31e0c1b49fSNick Terrell * is empty.
32e0c1b49fSNick Terrell */
33e0c1b49fSNick Terrell for (; ip + fastHashFillStep - 1 <= iend; ip += fastHashFillStep) {
34e0c1b49fSNick Terrell U32 const curr = (U32)(ip - base);
35e0c1b49fSNick Terrell U32 i;
36e0c1b49fSNick Terrell for (i = 0; i < fastHashFillStep; ++i) {
37e0c1b49fSNick Terrell size_t const smHash = ZSTD_hashPtr(ip + i, hBitsS, mls);
38e0c1b49fSNick Terrell size_t const lgHash = ZSTD_hashPtr(ip + i, hBitsL, 8);
39e0c1b49fSNick Terrell if (i == 0)
40e0c1b49fSNick Terrell hashSmall[smHash] = curr + i;
41e0c1b49fSNick Terrell if (i == 0 || hashLarge[lgHash] == 0)
42e0c1b49fSNick Terrell hashLarge[lgHash] = curr + i;
43e0c1b49fSNick Terrell /* Only load extra positions for ZSTD_dtlm_full */
44e0c1b49fSNick Terrell if (dtlm == ZSTD_dtlm_fast)
45e0c1b49fSNick Terrell break;
46e0c1b49fSNick Terrell } }
47e0c1b49fSNick Terrell }
48e0c1b49fSNick Terrell
49e0c1b49fSNick Terrell
50e0c1b49fSNick Terrell FORCE_INLINE_TEMPLATE
ZSTD_compressBlock_doubleFast_noDict_generic(ZSTD_matchState_t * ms,seqStore_t * seqStore,U32 rep[ZSTD_REP_NUM],void const * src,size_t srcSize,U32 const mls)51*2aa14b1aSNick Terrell size_t ZSTD_compressBlock_doubleFast_noDict_generic(
52*2aa14b1aSNick Terrell ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
53*2aa14b1aSNick Terrell void const* src, size_t srcSize, U32 const mls /* template */)
54*2aa14b1aSNick Terrell {
55*2aa14b1aSNick Terrell ZSTD_compressionParameters const* cParams = &ms->cParams;
56*2aa14b1aSNick Terrell U32* const hashLong = ms->hashTable;
57*2aa14b1aSNick Terrell const U32 hBitsL = cParams->hashLog;
58*2aa14b1aSNick Terrell U32* const hashSmall = ms->chainTable;
59*2aa14b1aSNick Terrell const U32 hBitsS = cParams->chainLog;
60*2aa14b1aSNick Terrell const BYTE* const base = ms->window.base;
61*2aa14b1aSNick Terrell const BYTE* const istart = (const BYTE*)src;
62*2aa14b1aSNick Terrell const BYTE* anchor = istart;
63*2aa14b1aSNick Terrell const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
64*2aa14b1aSNick Terrell /* presumes that, if there is a dictionary, it must be using Attach mode */
65*2aa14b1aSNick Terrell const U32 prefixLowestIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog);
66*2aa14b1aSNick Terrell const BYTE* const prefixLowest = base + prefixLowestIndex;
67*2aa14b1aSNick Terrell const BYTE* const iend = istart + srcSize;
68*2aa14b1aSNick Terrell const BYTE* const ilimit = iend - HASH_READ_SIZE;
69*2aa14b1aSNick Terrell U32 offset_1=rep[0], offset_2=rep[1];
70*2aa14b1aSNick Terrell U32 offsetSaved = 0;
71*2aa14b1aSNick Terrell
72*2aa14b1aSNick Terrell size_t mLength;
73*2aa14b1aSNick Terrell U32 offset;
74*2aa14b1aSNick Terrell U32 curr;
75*2aa14b1aSNick Terrell
76*2aa14b1aSNick Terrell /* how many positions to search before increasing step size */
77*2aa14b1aSNick Terrell const size_t kStepIncr = 1 << kSearchStrength;
78*2aa14b1aSNick Terrell /* the position at which to increment the step size if no match is found */
79*2aa14b1aSNick Terrell const BYTE* nextStep;
80*2aa14b1aSNick Terrell size_t step; /* the current step size */
81*2aa14b1aSNick Terrell
82*2aa14b1aSNick Terrell size_t hl0; /* the long hash at ip */
83*2aa14b1aSNick Terrell size_t hl1; /* the long hash at ip1 */
84*2aa14b1aSNick Terrell
85*2aa14b1aSNick Terrell U32 idxl0; /* the long match index for ip */
86*2aa14b1aSNick Terrell U32 idxl1; /* the long match index for ip1 */
87*2aa14b1aSNick Terrell
88*2aa14b1aSNick Terrell const BYTE* matchl0; /* the long match for ip */
89*2aa14b1aSNick Terrell const BYTE* matchs0; /* the short match for ip */
90*2aa14b1aSNick Terrell const BYTE* matchl1; /* the long match for ip1 */
91*2aa14b1aSNick Terrell
92*2aa14b1aSNick Terrell const BYTE* ip = istart; /* the current position */
93*2aa14b1aSNick Terrell const BYTE* ip1; /* the next position */
94*2aa14b1aSNick Terrell
95*2aa14b1aSNick Terrell DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_noDict_generic");
96*2aa14b1aSNick Terrell
97*2aa14b1aSNick Terrell /* init */
98*2aa14b1aSNick Terrell ip += ((ip - prefixLowest) == 0);
99*2aa14b1aSNick Terrell {
100*2aa14b1aSNick Terrell U32 const current = (U32)(ip - base);
101*2aa14b1aSNick Terrell U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog);
102*2aa14b1aSNick Terrell U32 const maxRep = current - windowLow;
103*2aa14b1aSNick Terrell if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
104*2aa14b1aSNick Terrell if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
105*2aa14b1aSNick Terrell }
106*2aa14b1aSNick Terrell
107*2aa14b1aSNick Terrell /* Outer Loop: one iteration per match found and stored */
108*2aa14b1aSNick Terrell while (1) {
109*2aa14b1aSNick Terrell step = 1;
110*2aa14b1aSNick Terrell nextStep = ip + kStepIncr;
111*2aa14b1aSNick Terrell ip1 = ip + step;
112*2aa14b1aSNick Terrell
113*2aa14b1aSNick Terrell if (ip1 > ilimit) {
114*2aa14b1aSNick Terrell goto _cleanup;
115*2aa14b1aSNick Terrell }
116*2aa14b1aSNick Terrell
117*2aa14b1aSNick Terrell hl0 = ZSTD_hashPtr(ip, hBitsL, 8);
118*2aa14b1aSNick Terrell idxl0 = hashLong[hl0];
119*2aa14b1aSNick Terrell matchl0 = base + idxl0;
120*2aa14b1aSNick Terrell
121*2aa14b1aSNick Terrell /* Inner Loop: one iteration per search / position */
122*2aa14b1aSNick Terrell do {
123*2aa14b1aSNick Terrell const size_t hs0 = ZSTD_hashPtr(ip, hBitsS, mls);
124*2aa14b1aSNick Terrell const U32 idxs0 = hashSmall[hs0];
125*2aa14b1aSNick Terrell curr = (U32)(ip-base);
126*2aa14b1aSNick Terrell matchs0 = base + idxs0;
127*2aa14b1aSNick Terrell
128*2aa14b1aSNick Terrell hashLong[hl0] = hashSmall[hs0] = curr; /* update hash tables */
129*2aa14b1aSNick Terrell
130*2aa14b1aSNick Terrell /* check noDict repcode */
131*2aa14b1aSNick Terrell if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
132*2aa14b1aSNick Terrell mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
133*2aa14b1aSNick Terrell ip++;
134*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_REPCODE_1, mLength);
135*2aa14b1aSNick Terrell goto _match_stored;
136*2aa14b1aSNick Terrell }
137*2aa14b1aSNick Terrell
138*2aa14b1aSNick Terrell hl1 = ZSTD_hashPtr(ip1, hBitsL, 8);
139*2aa14b1aSNick Terrell
140*2aa14b1aSNick Terrell if (idxl0 > prefixLowestIndex) {
141*2aa14b1aSNick Terrell /* check prefix long match */
142*2aa14b1aSNick Terrell if (MEM_read64(matchl0) == MEM_read64(ip)) {
143*2aa14b1aSNick Terrell mLength = ZSTD_count(ip+8, matchl0+8, iend) + 8;
144*2aa14b1aSNick Terrell offset = (U32)(ip-matchl0);
145*2aa14b1aSNick Terrell while (((ip>anchor) & (matchl0>prefixLowest)) && (ip[-1] == matchl0[-1])) { ip--; matchl0--; mLength++; } /* catch up */
146*2aa14b1aSNick Terrell goto _match_found;
147*2aa14b1aSNick Terrell }
148*2aa14b1aSNick Terrell }
149*2aa14b1aSNick Terrell
150*2aa14b1aSNick Terrell idxl1 = hashLong[hl1];
151*2aa14b1aSNick Terrell matchl1 = base + idxl1;
152*2aa14b1aSNick Terrell
153*2aa14b1aSNick Terrell if (idxs0 > prefixLowestIndex) {
154*2aa14b1aSNick Terrell /* check prefix short match */
155*2aa14b1aSNick Terrell if (MEM_read32(matchs0) == MEM_read32(ip)) {
156*2aa14b1aSNick Terrell goto _search_next_long;
157*2aa14b1aSNick Terrell }
158*2aa14b1aSNick Terrell }
159*2aa14b1aSNick Terrell
160*2aa14b1aSNick Terrell if (ip1 >= nextStep) {
161*2aa14b1aSNick Terrell PREFETCH_L1(ip1 + 64);
162*2aa14b1aSNick Terrell PREFETCH_L1(ip1 + 128);
163*2aa14b1aSNick Terrell step++;
164*2aa14b1aSNick Terrell nextStep += kStepIncr;
165*2aa14b1aSNick Terrell }
166*2aa14b1aSNick Terrell ip = ip1;
167*2aa14b1aSNick Terrell ip1 += step;
168*2aa14b1aSNick Terrell
169*2aa14b1aSNick Terrell hl0 = hl1;
170*2aa14b1aSNick Terrell idxl0 = idxl1;
171*2aa14b1aSNick Terrell matchl0 = matchl1;
172*2aa14b1aSNick Terrell #if defined(__aarch64__)
173*2aa14b1aSNick Terrell PREFETCH_L1(ip+256);
174*2aa14b1aSNick Terrell #endif
175*2aa14b1aSNick Terrell } while (ip1 <= ilimit);
176*2aa14b1aSNick Terrell
177*2aa14b1aSNick Terrell _cleanup:
178*2aa14b1aSNick Terrell /* save reps for next block */
179*2aa14b1aSNick Terrell rep[0] = offset_1 ? offset_1 : offsetSaved;
180*2aa14b1aSNick Terrell rep[1] = offset_2 ? offset_2 : offsetSaved;
181*2aa14b1aSNick Terrell
182*2aa14b1aSNick Terrell /* Return the last literals size */
183*2aa14b1aSNick Terrell return (size_t)(iend - anchor);
184*2aa14b1aSNick Terrell
185*2aa14b1aSNick Terrell _search_next_long:
186*2aa14b1aSNick Terrell
187*2aa14b1aSNick Terrell /* check prefix long +1 match */
188*2aa14b1aSNick Terrell if (idxl1 > prefixLowestIndex) {
189*2aa14b1aSNick Terrell if (MEM_read64(matchl1) == MEM_read64(ip1)) {
190*2aa14b1aSNick Terrell ip = ip1;
191*2aa14b1aSNick Terrell mLength = ZSTD_count(ip+8, matchl1+8, iend) + 8;
192*2aa14b1aSNick Terrell offset = (U32)(ip-matchl1);
193*2aa14b1aSNick Terrell while (((ip>anchor) & (matchl1>prefixLowest)) && (ip[-1] == matchl1[-1])) { ip--; matchl1--; mLength++; } /* catch up */
194*2aa14b1aSNick Terrell goto _match_found;
195*2aa14b1aSNick Terrell }
196*2aa14b1aSNick Terrell }
197*2aa14b1aSNick Terrell
198*2aa14b1aSNick Terrell /* if no long +1 match, explore the short match we found */
199*2aa14b1aSNick Terrell mLength = ZSTD_count(ip+4, matchs0+4, iend) + 4;
200*2aa14b1aSNick Terrell offset = (U32)(ip - matchs0);
201*2aa14b1aSNick Terrell while (((ip>anchor) & (matchs0>prefixLowest)) && (ip[-1] == matchs0[-1])) { ip--; matchs0--; mLength++; } /* catch up */
202*2aa14b1aSNick Terrell
203*2aa14b1aSNick Terrell /* fall-through */
204*2aa14b1aSNick Terrell
205*2aa14b1aSNick Terrell _match_found: /* requires ip, offset, mLength */
206*2aa14b1aSNick Terrell offset_2 = offset_1;
207*2aa14b1aSNick Terrell offset_1 = offset;
208*2aa14b1aSNick Terrell
209*2aa14b1aSNick Terrell if (step < 4) {
210*2aa14b1aSNick Terrell /* It is unsafe to write this value back to the hashtable when ip1 is
211*2aa14b1aSNick Terrell * greater than or equal to the new ip we will have after we're done
212*2aa14b1aSNick Terrell * processing this match. Rather than perform that test directly
213*2aa14b1aSNick Terrell * (ip1 >= ip + mLength), which costs speed in practice, we do a simpler
214*2aa14b1aSNick Terrell * more predictable test. The minmatch even if we take a short match is
215*2aa14b1aSNick Terrell * 4 bytes, so as long as step, the distance between ip and ip1
216*2aa14b1aSNick Terrell * (initially) is less than 4, we know ip1 < new ip. */
217*2aa14b1aSNick Terrell hashLong[hl1] = (U32)(ip1 - base);
218*2aa14b1aSNick Terrell }
219*2aa14b1aSNick Terrell
220*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_OFFSET(offset), mLength);
221*2aa14b1aSNick Terrell
222*2aa14b1aSNick Terrell _match_stored:
223*2aa14b1aSNick Terrell /* match found */
224*2aa14b1aSNick Terrell ip += mLength;
225*2aa14b1aSNick Terrell anchor = ip;
226*2aa14b1aSNick Terrell
227*2aa14b1aSNick Terrell if (ip <= ilimit) {
228*2aa14b1aSNick Terrell /* Complementary insertion */
229*2aa14b1aSNick Terrell /* done after iLimit test, as candidates could be > iend-8 */
230*2aa14b1aSNick Terrell { U32 const indexToInsert = curr+2;
231*2aa14b1aSNick Terrell hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert;
232*2aa14b1aSNick Terrell hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
233*2aa14b1aSNick Terrell hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert;
234*2aa14b1aSNick Terrell hashSmall[ZSTD_hashPtr(ip-1, hBitsS, mls)] = (U32)(ip-1-base);
235*2aa14b1aSNick Terrell }
236*2aa14b1aSNick Terrell
237*2aa14b1aSNick Terrell /* check immediate repcode */
238*2aa14b1aSNick Terrell while ( (ip <= ilimit)
239*2aa14b1aSNick Terrell && ( (offset_2>0)
240*2aa14b1aSNick Terrell & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
241*2aa14b1aSNick Terrell /* store sequence */
242*2aa14b1aSNick Terrell size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
243*2aa14b1aSNick Terrell U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */
244*2aa14b1aSNick Terrell hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
245*2aa14b1aSNick Terrell hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
246*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, 0, anchor, iend, STORE_REPCODE_1, rLength);
247*2aa14b1aSNick Terrell ip += rLength;
248*2aa14b1aSNick Terrell anchor = ip;
249*2aa14b1aSNick Terrell continue; /* faster when present ... (?) */
250*2aa14b1aSNick Terrell }
251*2aa14b1aSNick Terrell }
252*2aa14b1aSNick Terrell }
253*2aa14b1aSNick Terrell }
254*2aa14b1aSNick Terrell
255*2aa14b1aSNick Terrell
256*2aa14b1aSNick Terrell FORCE_INLINE_TEMPLATE
ZSTD_compressBlock_doubleFast_dictMatchState_generic(ZSTD_matchState_t * ms,seqStore_t * seqStore,U32 rep[ZSTD_REP_NUM],void const * src,size_t srcSize,U32 const mls)257*2aa14b1aSNick Terrell size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic(
258e0c1b49fSNick Terrell ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
259e0c1b49fSNick Terrell void const* src, size_t srcSize,
260*2aa14b1aSNick Terrell U32 const mls /* template */)
261e0c1b49fSNick Terrell {
262e0c1b49fSNick Terrell ZSTD_compressionParameters const* cParams = &ms->cParams;
263e0c1b49fSNick Terrell U32* const hashLong = ms->hashTable;
264e0c1b49fSNick Terrell const U32 hBitsL = cParams->hashLog;
265e0c1b49fSNick Terrell U32* const hashSmall = ms->chainTable;
266e0c1b49fSNick Terrell const U32 hBitsS = cParams->chainLog;
267e0c1b49fSNick Terrell const BYTE* const base = ms->window.base;
268e0c1b49fSNick Terrell const BYTE* const istart = (const BYTE*)src;
269e0c1b49fSNick Terrell const BYTE* ip = istart;
270e0c1b49fSNick Terrell const BYTE* anchor = istart;
271e0c1b49fSNick Terrell const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
272e0c1b49fSNick Terrell /* presumes that, if there is a dictionary, it must be using Attach mode */
273e0c1b49fSNick Terrell const U32 prefixLowestIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog);
274e0c1b49fSNick Terrell const BYTE* const prefixLowest = base + prefixLowestIndex;
275e0c1b49fSNick Terrell const BYTE* const iend = istart + srcSize;
276e0c1b49fSNick Terrell const BYTE* const ilimit = iend - HASH_READ_SIZE;
277e0c1b49fSNick Terrell U32 offset_1=rep[0], offset_2=rep[1];
278e0c1b49fSNick Terrell U32 offsetSaved = 0;
279e0c1b49fSNick Terrell
280e0c1b49fSNick Terrell const ZSTD_matchState_t* const dms = ms->dictMatchState;
281*2aa14b1aSNick Terrell const ZSTD_compressionParameters* const dictCParams = &dms->cParams;
282*2aa14b1aSNick Terrell const U32* const dictHashLong = dms->hashTable;
283*2aa14b1aSNick Terrell const U32* const dictHashSmall = dms->chainTable;
284*2aa14b1aSNick Terrell const U32 dictStartIndex = dms->window.dictLimit;
285*2aa14b1aSNick Terrell const BYTE* const dictBase = dms->window.base;
286*2aa14b1aSNick Terrell const BYTE* const dictStart = dictBase + dictStartIndex;
287*2aa14b1aSNick Terrell const BYTE* const dictEnd = dms->window.nextSrc;
288*2aa14b1aSNick Terrell const U32 dictIndexDelta = prefixLowestIndex - (U32)(dictEnd - dictBase);
289*2aa14b1aSNick Terrell const U32 dictHBitsL = dictCParams->hashLog;
290*2aa14b1aSNick Terrell const U32 dictHBitsS = dictCParams->chainLog;
291e0c1b49fSNick Terrell const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictStart));
292e0c1b49fSNick Terrell
293*2aa14b1aSNick Terrell DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_dictMatchState_generic");
294e0c1b49fSNick Terrell
295e0c1b49fSNick Terrell /* if a dictionary is attached, it must be within window range */
296e0c1b49fSNick Terrell assert(ms->window.dictLimit + (1U << cParams->windowLog) >= endIndex);
297e0c1b49fSNick Terrell
298e0c1b49fSNick Terrell /* init */
299e0c1b49fSNick Terrell ip += (dictAndPrefixLength == 0);
300*2aa14b1aSNick Terrell
301e0c1b49fSNick Terrell /* dictMatchState repCode checks don't currently handle repCode == 0
302e0c1b49fSNick Terrell * disabling. */
303e0c1b49fSNick Terrell assert(offset_1 <= dictAndPrefixLength);
304e0c1b49fSNick Terrell assert(offset_2 <= dictAndPrefixLength);
305e0c1b49fSNick Terrell
306e0c1b49fSNick Terrell /* Main Search Loop */
307e0c1b49fSNick Terrell while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
308e0c1b49fSNick Terrell size_t mLength;
309e0c1b49fSNick Terrell U32 offset;
310e0c1b49fSNick Terrell size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
311e0c1b49fSNick Terrell size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
312e0c1b49fSNick Terrell size_t const dictHL = ZSTD_hashPtr(ip, dictHBitsL, 8);
313e0c1b49fSNick Terrell size_t const dictHS = ZSTD_hashPtr(ip, dictHBitsS, mls);
314e0c1b49fSNick Terrell U32 const curr = (U32)(ip-base);
315e0c1b49fSNick Terrell U32 const matchIndexL = hashLong[h2];
316e0c1b49fSNick Terrell U32 matchIndexS = hashSmall[h];
317e0c1b49fSNick Terrell const BYTE* matchLong = base + matchIndexL;
318e0c1b49fSNick Terrell const BYTE* match = base + matchIndexS;
319e0c1b49fSNick Terrell const U32 repIndex = curr + 1 - offset_1;
320*2aa14b1aSNick Terrell const BYTE* repMatch = (repIndex < prefixLowestIndex) ?
321e0c1b49fSNick Terrell dictBase + (repIndex - dictIndexDelta) :
322e0c1b49fSNick Terrell base + repIndex;
323e0c1b49fSNick Terrell hashLong[h2] = hashSmall[h] = curr; /* update hash tables */
324e0c1b49fSNick Terrell
325*2aa14b1aSNick Terrell /* check repcode */
326*2aa14b1aSNick Terrell if (((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
327e0c1b49fSNick Terrell && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
328e0c1b49fSNick Terrell const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
329e0c1b49fSNick Terrell mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
330e0c1b49fSNick Terrell ip++;
331*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_REPCODE_1, mLength);
332e0c1b49fSNick Terrell goto _match_stored;
333e0c1b49fSNick Terrell }
334e0c1b49fSNick Terrell
335e0c1b49fSNick Terrell if (matchIndexL > prefixLowestIndex) {
336e0c1b49fSNick Terrell /* check prefix long match */
337e0c1b49fSNick Terrell if (MEM_read64(matchLong) == MEM_read64(ip)) {
338e0c1b49fSNick Terrell mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
339e0c1b49fSNick Terrell offset = (U32)(ip-matchLong);
340e0c1b49fSNick Terrell while (((ip>anchor) & (matchLong>prefixLowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
341e0c1b49fSNick Terrell goto _match_found;
342e0c1b49fSNick Terrell }
343*2aa14b1aSNick Terrell } else {
344e0c1b49fSNick Terrell /* check dictMatchState long match */
345e0c1b49fSNick Terrell U32 const dictMatchIndexL = dictHashLong[dictHL];
346e0c1b49fSNick Terrell const BYTE* dictMatchL = dictBase + dictMatchIndexL;
347e0c1b49fSNick Terrell assert(dictMatchL < dictEnd);
348e0c1b49fSNick Terrell
349e0c1b49fSNick Terrell if (dictMatchL > dictStart && MEM_read64(dictMatchL) == MEM_read64(ip)) {
350e0c1b49fSNick Terrell mLength = ZSTD_count_2segments(ip+8, dictMatchL+8, iend, dictEnd, prefixLowest) + 8;
351e0c1b49fSNick Terrell offset = (U32)(curr - dictMatchIndexL - dictIndexDelta);
352e0c1b49fSNick Terrell while (((ip>anchor) & (dictMatchL>dictStart)) && (ip[-1] == dictMatchL[-1])) { ip--; dictMatchL--; mLength++; } /* catch up */
353e0c1b49fSNick Terrell goto _match_found;
354e0c1b49fSNick Terrell } }
355e0c1b49fSNick Terrell
356e0c1b49fSNick Terrell if (matchIndexS > prefixLowestIndex) {
357e0c1b49fSNick Terrell /* check prefix short match */
358e0c1b49fSNick Terrell if (MEM_read32(match) == MEM_read32(ip)) {
359e0c1b49fSNick Terrell goto _search_next_long;
360e0c1b49fSNick Terrell }
361*2aa14b1aSNick Terrell } else {
362e0c1b49fSNick Terrell /* check dictMatchState short match */
363e0c1b49fSNick Terrell U32 const dictMatchIndexS = dictHashSmall[dictHS];
364e0c1b49fSNick Terrell match = dictBase + dictMatchIndexS;
365e0c1b49fSNick Terrell matchIndexS = dictMatchIndexS + dictIndexDelta;
366e0c1b49fSNick Terrell
367e0c1b49fSNick Terrell if (match > dictStart && MEM_read32(match) == MEM_read32(ip)) {
368e0c1b49fSNick Terrell goto _search_next_long;
369e0c1b49fSNick Terrell } }
370e0c1b49fSNick Terrell
371e0c1b49fSNick Terrell ip += ((ip-anchor) >> kSearchStrength) + 1;
372e0c1b49fSNick Terrell #if defined(__aarch64__)
373e0c1b49fSNick Terrell PREFETCH_L1(ip+256);
374e0c1b49fSNick Terrell #endif
375e0c1b49fSNick Terrell continue;
376e0c1b49fSNick Terrell
377e0c1b49fSNick Terrell _search_next_long:
378e0c1b49fSNick Terrell
379e0c1b49fSNick Terrell { size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
380e0c1b49fSNick Terrell size_t const dictHLNext = ZSTD_hashPtr(ip+1, dictHBitsL, 8);
381e0c1b49fSNick Terrell U32 const matchIndexL3 = hashLong[hl3];
382e0c1b49fSNick Terrell const BYTE* matchL3 = base + matchIndexL3;
383e0c1b49fSNick Terrell hashLong[hl3] = curr + 1;
384e0c1b49fSNick Terrell
385e0c1b49fSNick Terrell /* check prefix long +1 match */
386e0c1b49fSNick Terrell if (matchIndexL3 > prefixLowestIndex) {
387e0c1b49fSNick Terrell if (MEM_read64(matchL3) == MEM_read64(ip+1)) {
388e0c1b49fSNick Terrell mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
389e0c1b49fSNick Terrell ip++;
390e0c1b49fSNick Terrell offset = (U32)(ip-matchL3);
391e0c1b49fSNick Terrell while (((ip>anchor) & (matchL3>prefixLowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
392e0c1b49fSNick Terrell goto _match_found;
393e0c1b49fSNick Terrell }
394*2aa14b1aSNick Terrell } else {
395e0c1b49fSNick Terrell /* check dict long +1 match */
396e0c1b49fSNick Terrell U32 const dictMatchIndexL3 = dictHashLong[dictHLNext];
397e0c1b49fSNick Terrell const BYTE* dictMatchL3 = dictBase + dictMatchIndexL3;
398e0c1b49fSNick Terrell assert(dictMatchL3 < dictEnd);
399e0c1b49fSNick Terrell if (dictMatchL3 > dictStart && MEM_read64(dictMatchL3) == MEM_read64(ip+1)) {
400e0c1b49fSNick Terrell mLength = ZSTD_count_2segments(ip+1+8, dictMatchL3+8, iend, dictEnd, prefixLowest) + 8;
401e0c1b49fSNick Terrell ip++;
402e0c1b49fSNick Terrell offset = (U32)(curr + 1 - dictMatchIndexL3 - dictIndexDelta);
403e0c1b49fSNick Terrell while (((ip>anchor) & (dictMatchL3>dictStart)) && (ip[-1] == dictMatchL3[-1])) { ip--; dictMatchL3--; mLength++; } /* catch up */
404e0c1b49fSNick Terrell goto _match_found;
405e0c1b49fSNick Terrell } } }
406e0c1b49fSNick Terrell
407e0c1b49fSNick Terrell /* if no long +1 match, explore the short match we found */
408*2aa14b1aSNick Terrell if (matchIndexS < prefixLowestIndex) {
409e0c1b49fSNick Terrell mLength = ZSTD_count_2segments(ip+4, match+4, iend, dictEnd, prefixLowest) + 4;
410e0c1b49fSNick Terrell offset = (U32)(curr - matchIndexS);
411e0c1b49fSNick Terrell while (((ip>anchor) & (match>dictStart)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
412e0c1b49fSNick Terrell } else {
413e0c1b49fSNick Terrell mLength = ZSTD_count(ip+4, match+4, iend) + 4;
414e0c1b49fSNick Terrell offset = (U32)(ip - match);
415e0c1b49fSNick Terrell while (((ip>anchor) & (match>prefixLowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
416e0c1b49fSNick Terrell }
417e0c1b49fSNick Terrell
418e0c1b49fSNick Terrell _match_found:
419e0c1b49fSNick Terrell offset_2 = offset_1;
420e0c1b49fSNick Terrell offset_1 = offset;
421e0c1b49fSNick Terrell
422*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_OFFSET(offset), mLength);
423e0c1b49fSNick Terrell
424e0c1b49fSNick Terrell _match_stored:
425e0c1b49fSNick Terrell /* match found */
426e0c1b49fSNick Terrell ip += mLength;
427e0c1b49fSNick Terrell anchor = ip;
428e0c1b49fSNick Terrell
429e0c1b49fSNick Terrell if (ip <= ilimit) {
430e0c1b49fSNick Terrell /* Complementary insertion */
431e0c1b49fSNick Terrell /* done after iLimit test, as candidates could be > iend-8 */
432e0c1b49fSNick Terrell { U32 const indexToInsert = curr+2;
433e0c1b49fSNick Terrell hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert;
434e0c1b49fSNick Terrell hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
435e0c1b49fSNick Terrell hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert;
436e0c1b49fSNick Terrell hashSmall[ZSTD_hashPtr(ip-1, hBitsS, mls)] = (U32)(ip-1-base);
437e0c1b49fSNick Terrell }
438e0c1b49fSNick Terrell
439e0c1b49fSNick Terrell /* check immediate repcode */
440e0c1b49fSNick Terrell while (ip <= ilimit) {
441e0c1b49fSNick Terrell U32 const current2 = (U32)(ip-base);
442e0c1b49fSNick Terrell U32 const repIndex2 = current2 - offset_2;
443*2aa14b1aSNick Terrell const BYTE* repMatch2 = repIndex2 < prefixLowestIndex ?
444e0c1b49fSNick Terrell dictBase + repIndex2 - dictIndexDelta :
445e0c1b49fSNick Terrell base + repIndex2;
446e0c1b49fSNick Terrell if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */)
447e0c1b49fSNick Terrell && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
448e0c1b49fSNick Terrell const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend;
449e0c1b49fSNick Terrell size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4;
450e0c1b49fSNick Terrell U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
451*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, 0, anchor, iend, STORE_REPCODE_1, repLength2);
452e0c1b49fSNick Terrell hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
453e0c1b49fSNick Terrell hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
454e0c1b49fSNick Terrell ip += repLength2;
455e0c1b49fSNick Terrell anchor = ip;
456e0c1b49fSNick Terrell continue;
457e0c1b49fSNick Terrell }
458e0c1b49fSNick Terrell break;
459*2aa14b1aSNick Terrell }
460*2aa14b1aSNick Terrell }
461e0c1b49fSNick Terrell } /* while (ip < ilimit) */
462e0c1b49fSNick Terrell
463e0c1b49fSNick Terrell /* save reps for next block */
464e0c1b49fSNick Terrell rep[0] = offset_1 ? offset_1 : offsetSaved;
465e0c1b49fSNick Terrell rep[1] = offset_2 ? offset_2 : offsetSaved;
466e0c1b49fSNick Terrell
467e0c1b49fSNick Terrell /* Return the last literals size */
468e0c1b49fSNick Terrell return (size_t)(iend - anchor);
469e0c1b49fSNick Terrell }
470e0c1b49fSNick Terrell
471*2aa14b1aSNick Terrell #define ZSTD_GEN_DFAST_FN(dictMode, mls) \
472*2aa14b1aSNick Terrell static size_t ZSTD_compressBlock_doubleFast_##dictMode##_##mls( \
473*2aa14b1aSNick Terrell ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], \
474*2aa14b1aSNick Terrell void const* src, size_t srcSize) \
475*2aa14b1aSNick Terrell { \
476*2aa14b1aSNick Terrell return ZSTD_compressBlock_doubleFast_##dictMode##_generic(ms, seqStore, rep, src, srcSize, mls); \
477*2aa14b1aSNick Terrell }
478*2aa14b1aSNick Terrell
479*2aa14b1aSNick Terrell ZSTD_GEN_DFAST_FN(noDict, 4)
480*2aa14b1aSNick Terrell ZSTD_GEN_DFAST_FN(noDict, 5)
481*2aa14b1aSNick Terrell ZSTD_GEN_DFAST_FN(noDict, 6)
482*2aa14b1aSNick Terrell ZSTD_GEN_DFAST_FN(noDict, 7)
483*2aa14b1aSNick Terrell
484*2aa14b1aSNick Terrell ZSTD_GEN_DFAST_FN(dictMatchState, 4)
485*2aa14b1aSNick Terrell ZSTD_GEN_DFAST_FN(dictMatchState, 5)
486*2aa14b1aSNick Terrell ZSTD_GEN_DFAST_FN(dictMatchState, 6)
487*2aa14b1aSNick Terrell ZSTD_GEN_DFAST_FN(dictMatchState, 7)
488*2aa14b1aSNick Terrell
489e0c1b49fSNick Terrell
ZSTD_compressBlock_doubleFast(ZSTD_matchState_t * ms,seqStore_t * seqStore,U32 rep[ZSTD_REP_NUM],void const * src,size_t srcSize)490e0c1b49fSNick Terrell size_t ZSTD_compressBlock_doubleFast(
491e0c1b49fSNick Terrell ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
492e0c1b49fSNick Terrell void const* src, size_t srcSize)
493e0c1b49fSNick Terrell {
494e0c1b49fSNick Terrell const U32 mls = ms->cParams.minMatch;
495e0c1b49fSNick Terrell switch(mls)
496e0c1b49fSNick Terrell {
497e0c1b49fSNick Terrell default: /* includes case 3 */
498e0c1b49fSNick Terrell case 4 :
499*2aa14b1aSNick Terrell return ZSTD_compressBlock_doubleFast_noDict_4(ms, seqStore, rep, src, srcSize);
500e0c1b49fSNick Terrell case 5 :
501*2aa14b1aSNick Terrell return ZSTD_compressBlock_doubleFast_noDict_5(ms, seqStore, rep, src, srcSize);
502e0c1b49fSNick Terrell case 6 :
503*2aa14b1aSNick Terrell return ZSTD_compressBlock_doubleFast_noDict_6(ms, seqStore, rep, src, srcSize);
504e0c1b49fSNick Terrell case 7 :
505*2aa14b1aSNick Terrell return ZSTD_compressBlock_doubleFast_noDict_7(ms, seqStore, rep, src, srcSize);
506e0c1b49fSNick Terrell }
507e0c1b49fSNick Terrell }
508e0c1b49fSNick Terrell
509e0c1b49fSNick Terrell
ZSTD_compressBlock_doubleFast_dictMatchState(ZSTD_matchState_t * ms,seqStore_t * seqStore,U32 rep[ZSTD_REP_NUM],void const * src,size_t srcSize)510e0c1b49fSNick Terrell size_t ZSTD_compressBlock_doubleFast_dictMatchState(
511e0c1b49fSNick Terrell ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
512e0c1b49fSNick Terrell void const* src, size_t srcSize)
513e0c1b49fSNick Terrell {
514e0c1b49fSNick Terrell const U32 mls = ms->cParams.minMatch;
515e0c1b49fSNick Terrell switch(mls)
516e0c1b49fSNick Terrell {
517e0c1b49fSNick Terrell default: /* includes case 3 */
518e0c1b49fSNick Terrell case 4 :
519*2aa14b1aSNick Terrell return ZSTD_compressBlock_doubleFast_dictMatchState_4(ms, seqStore, rep, src, srcSize);
520e0c1b49fSNick Terrell case 5 :
521*2aa14b1aSNick Terrell return ZSTD_compressBlock_doubleFast_dictMatchState_5(ms, seqStore, rep, src, srcSize);
522e0c1b49fSNick Terrell case 6 :
523*2aa14b1aSNick Terrell return ZSTD_compressBlock_doubleFast_dictMatchState_6(ms, seqStore, rep, src, srcSize);
524e0c1b49fSNick Terrell case 7 :
525*2aa14b1aSNick Terrell return ZSTD_compressBlock_doubleFast_dictMatchState_7(ms, seqStore, rep, src, srcSize);
526e0c1b49fSNick Terrell }
527e0c1b49fSNick Terrell }
528e0c1b49fSNick Terrell
529e0c1b49fSNick Terrell
ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_matchState_t * ms,seqStore_t * seqStore,U32 rep[ZSTD_REP_NUM],void const * src,size_t srcSize,U32 const mls)530e0c1b49fSNick Terrell static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
531e0c1b49fSNick Terrell ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
532e0c1b49fSNick Terrell void const* src, size_t srcSize,
533e0c1b49fSNick Terrell U32 const mls /* template */)
534e0c1b49fSNick Terrell {
535e0c1b49fSNick Terrell ZSTD_compressionParameters const* cParams = &ms->cParams;
536e0c1b49fSNick Terrell U32* const hashLong = ms->hashTable;
537e0c1b49fSNick Terrell U32 const hBitsL = cParams->hashLog;
538e0c1b49fSNick Terrell U32* const hashSmall = ms->chainTable;
539e0c1b49fSNick Terrell U32 const hBitsS = cParams->chainLog;
540e0c1b49fSNick Terrell const BYTE* const istart = (const BYTE*)src;
541e0c1b49fSNick Terrell const BYTE* ip = istart;
542e0c1b49fSNick Terrell const BYTE* anchor = istart;
543e0c1b49fSNick Terrell const BYTE* const iend = istart + srcSize;
544e0c1b49fSNick Terrell const BYTE* const ilimit = iend - 8;
545e0c1b49fSNick Terrell const BYTE* const base = ms->window.base;
546e0c1b49fSNick Terrell const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
547e0c1b49fSNick Terrell const U32 lowLimit = ZSTD_getLowestMatchIndex(ms, endIndex, cParams->windowLog);
548e0c1b49fSNick Terrell const U32 dictStartIndex = lowLimit;
549e0c1b49fSNick Terrell const U32 dictLimit = ms->window.dictLimit;
550e0c1b49fSNick Terrell const U32 prefixStartIndex = (dictLimit > lowLimit) ? dictLimit : lowLimit;
551e0c1b49fSNick Terrell const BYTE* const prefixStart = base + prefixStartIndex;
552e0c1b49fSNick Terrell const BYTE* const dictBase = ms->window.dictBase;
553e0c1b49fSNick Terrell const BYTE* const dictStart = dictBase + dictStartIndex;
554e0c1b49fSNick Terrell const BYTE* const dictEnd = dictBase + prefixStartIndex;
555e0c1b49fSNick Terrell U32 offset_1=rep[0], offset_2=rep[1];
556e0c1b49fSNick Terrell
557e0c1b49fSNick Terrell DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_extDict_generic (srcSize=%zu)", srcSize);
558e0c1b49fSNick Terrell
559e0c1b49fSNick Terrell /* if extDict is invalidated due to maxDistance, switch to "regular" variant */
560e0c1b49fSNick Terrell if (prefixStartIndex == dictStartIndex)
561*2aa14b1aSNick Terrell return ZSTD_compressBlock_doubleFast(ms, seqStore, rep, src, srcSize);
562e0c1b49fSNick Terrell
563e0c1b49fSNick Terrell /* Search Loop */
564e0c1b49fSNick Terrell while (ip < ilimit) { /* < instead of <=, because (ip+1) */
565e0c1b49fSNick Terrell const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
566e0c1b49fSNick Terrell const U32 matchIndex = hashSmall[hSmall];
567e0c1b49fSNick Terrell const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base;
568e0c1b49fSNick Terrell const BYTE* match = matchBase + matchIndex;
569e0c1b49fSNick Terrell
570e0c1b49fSNick Terrell const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
571e0c1b49fSNick Terrell const U32 matchLongIndex = hashLong[hLong];
572e0c1b49fSNick Terrell const BYTE* const matchLongBase = matchLongIndex < prefixStartIndex ? dictBase : base;
573e0c1b49fSNick Terrell const BYTE* matchLong = matchLongBase + matchLongIndex;
574e0c1b49fSNick Terrell
575e0c1b49fSNick Terrell const U32 curr = (U32)(ip-base);
576e0c1b49fSNick Terrell const U32 repIndex = curr + 1 - offset_1; /* offset_1 expected <= curr +1 */
577e0c1b49fSNick Terrell const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base;
578e0c1b49fSNick Terrell const BYTE* const repMatch = repBase + repIndex;
579e0c1b49fSNick Terrell size_t mLength;
580e0c1b49fSNick Terrell hashSmall[hSmall] = hashLong[hLong] = curr; /* update hash table */
581e0c1b49fSNick Terrell
582e0c1b49fSNick Terrell if ((((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex doesn't overlap dict + prefix */
583*2aa14b1aSNick Terrell & (offset_1 <= curr+1 - dictStartIndex)) /* note: we are searching at curr+1 */
584e0c1b49fSNick Terrell && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
585e0c1b49fSNick Terrell const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
586e0c1b49fSNick Terrell mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
587e0c1b49fSNick Terrell ip++;
588*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_REPCODE_1, mLength);
589e0c1b49fSNick Terrell } else {
590e0c1b49fSNick Terrell if ((matchLongIndex > dictStartIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
591e0c1b49fSNick Terrell const BYTE* const matchEnd = matchLongIndex < prefixStartIndex ? dictEnd : iend;
592e0c1b49fSNick Terrell const BYTE* const lowMatchPtr = matchLongIndex < prefixStartIndex ? dictStart : prefixStart;
593e0c1b49fSNick Terrell U32 offset;
594e0c1b49fSNick Terrell mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, prefixStart) + 8;
595e0c1b49fSNick Terrell offset = curr - matchLongIndex;
596e0c1b49fSNick Terrell while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
597e0c1b49fSNick Terrell offset_2 = offset_1;
598e0c1b49fSNick Terrell offset_1 = offset;
599*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_OFFSET(offset), mLength);
600e0c1b49fSNick Terrell
601e0c1b49fSNick Terrell } else if ((matchIndex > dictStartIndex) && (MEM_read32(match) == MEM_read32(ip))) {
602e0c1b49fSNick Terrell size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
603e0c1b49fSNick Terrell U32 const matchIndex3 = hashLong[h3];
604e0c1b49fSNick Terrell const BYTE* const match3Base = matchIndex3 < prefixStartIndex ? dictBase : base;
605e0c1b49fSNick Terrell const BYTE* match3 = match3Base + matchIndex3;
606e0c1b49fSNick Terrell U32 offset;
607e0c1b49fSNick Terrell hashLong[h3] = curr + 1;
608e0c1b49fSNick Terrell if ( (matchIndex3 > dictStartIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
609e0c1b49fSNick Terrell const BYTE* const matchEnd = matchIndex3 < prefixStartIndex ? dictEnd : iend;
610e0c1b49fSNick Terrell const BYTE* const lowMatchPtr = matchIndex3 < prefixStartIndex ? dictStart : prefixStart;
611e0c1b49fSNick Terrell mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, prefixStart) + 8;
612e0c1b49fSNick Terrell ip++;
613e0c1b49fSNick Terrell offset = curr+1 - matchIndex3;
614e0c1b49fSNick Terrell while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
615e0c1b49fSNick Terrell } else {
616e0c1b49fSNick Terrell const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
617e0c1b49fSNick Terrell const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
618e0c1b49fSNick Terrell mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
619e0c1b49fSNick Terrell offset = curr - matchIndex;
620e0c1b49fSNick Terrell while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
621e0c1b49fSNick Terrell }
622e0c1b49fSNick Terrell offset_2 = offset_1;
623e0c1b49fSNick Terrell offset_1 = offset;
624*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_OFFSET(offset), mLength);
625e0c1b49fSNick Terrell
626e0c1b49fSNick Terrell } else {
627e0c1b49fSNick Terrell ip += ((ip-anchor) >> kSearchStrength) + 1;
628e0c1b49fSNick Terrell continue;
629e0c1b49fSNick Terrell } }
630e0c1b49fSNick Terrell
631e0c1b49fSNick Terrell /* move to next sequence start */
632e0c1b49fSNick Terrell ip += mLength;
633e0c1b49fSNick Terrell anchor = ip;
634e0c1b49fSNick Terrell
635e0c1b49fSNick Terrell if (ip <= ilimit) {
636e0c1b49fSNick Terrell /* Complementary insertion */
637e0c1b49fSNick Terrell /* done after iLimit test, as candidates could be > iend-8 */
638e0c1b49fSNick Terrell { U32 const indexToInsert = curr+2;
639e0c1b49fSNick Terrell hashLong[ZSTD_hashPtr(base+indexToInsert, hBitsL, 8)] = indexToInsert;
640e0c1b49fSNick Terrell hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
641e0c1b49fSNick Terrell hashSmall[ZSTD_hashPtr(base+indexToInsert, hBitsS, mls)] = indexToInsert;
642e0c1b49fSNick Terrell hashSmall[ZSTD_hashPtr(ip-1, hBitsS, mls)] = (U32)(ip-1-base);
643e0c1b49fSNick Terrell }
644e0c1b49fSNick Terrell
645e0c1b49fSNick Terrell /* check immediate repcode */
646e0c1b49fSNick Terrell while (ip <= ilimit) {
647e0c1b49fSNick Terrell U32 const current2 = (U32)(ip-base);
648e0c1b49fSNick Terrell U32 const repIndex2 = current2 - offset_2;
649e0c1b49fSNick Terrell const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
650e0c1b49fSNick Terrell if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) /* intentional overflow : ensure repIndex2 doesn't overlap dict + prefix */
651*2aa14b1aSNick Terrell & (offset_2 <= current2 - dictStartIndex))
652e0c1b49fSNick Terrell && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
653e0c1b49fSNick Terrell const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
654e0c1b49fSNick Terrell size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
655e0c1b49fSNick Terrell U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
656*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, 0, anchor, iend, STORE_REPCODE_1, repLength2);
657e0c1b49fSNick Terrell hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
658e0c1b49fSNick Terrell hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
659e0c1b49fSNick Terrell ip += repLength2;
660e0c1b49fSNick Terrell anchor = ip;
661e0c1b49fSNick Terrell continue;
662e0c1b49fSNick Terrell }
663e0c1b49fSNick Terrell break;
664e0c1b49fSNick Terrell } } }
665e0c1b49fSNick Terrell
666e0c1b49fSNick Terrell /* save reps for next block */
667e0c1b49fSNick Terrell rep[0] = offset_1;
668e0c1b49fSNick Terrell rep[1] = offset_2;
669e0c1b49fSNick Terrell
670e0c1b49fSNick Terrell /* Return the last literals size */
671e0c1b49fSNick Terrell return (size_t)(iend - anchor);
672e0c1b49fSNick Terrell }
673e0c1b49fSNick Terrell
674*2aa14b1aSNick Terrell ZSTD_GEN_DFAST_FN(extDict, 4)
675*2aa14b1aSNick Terrell ZSTD_GEN_DFAST_FN(extDict, 5)
676*2aa14b1aSNick Terrell ZSTD_GEN_DFAST_FN(extDict, 6)
677*2aa14b1aSNick Terrell ZSTD_GEN_DFAST_FN(extDict, 7)
678e0c1b49fSNick Terrell
ZSTD_compressBlock_doubleFast_extDict(ZSTD_matchState_t * ms,seqStore_t * seqStore,U32 rep[ZSTD_REP_NUM],void const * src,size_t srcSize)679e0c1b49fSNick Terrell size_t ZSTD_compressBlock_doubleFast_extDict(
680e0c1b49fSNick Terrell ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
681e0c1b49fSNick Terrell void const* src, size_t srcSize)
682e0c1b49fSNick Terrell {
683e0c1b49fSNick Terrell U32 const mls = ms->cParams.minMatch;
684e0c1b49fSNick Terrell switch(mls)
685e0c1b49fSNick Terrell {
686e0c1b49fSNick Terrell default: /* includes case 3 */
687e0c1b49fSNick Terrell case 4 :
688*2aa14b1aSNick Terrell return ZSTD_compressBlock_doubleFast_extDict_4(ms, seqStore, rep, src, srcSize);
689e0c1b49fSNick Terrell case 5 :
690*2aa14b1aSNick Terrell return ZSTD_compressBlock_doubleFast_extDict_5(ms, seqStore, rep, src, srcSize);
691e0c1b49fSNick Terrell case 6 :
692*2aa14b1aSNick Terrell return ZSTD_compressBlock_doubleFast_extDict_6(ms, seqStore, rep, src, srcSize);
693e0c1b49fSNick Terrell case 7 :
694*2aa14b1aSNick Terrell return ZSTD_compressBlock_doubleFast_extDict_7(ms, seqStore, rep, src, srcSize);
695e0c1b49fSNick Terrell }
696e0c1b49fSNick Terrell }
697