1*a28cd43dSSascha Wildner /*
2*a28cd43dSSascha Wildner * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
3*a28cd43dSSascha Wildner * All rights reserved.
4*a28cd43dSSascha Wildner *
5*a28cd43dSSascha Wildner * This source code is licensed under both the BSD-style license (found in the
6*a28cd43dSSascha Wildner * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7*a28cd43dSSascha Wildner * in the COPYING file in the root directory of this source tree).
8*a28cd43dSSascha Wildner * You may select, at your option, one of the above-listed licenses.
9*a28cd43dSSascha Wildner */
10*a28cd43dSSascha Wildner
11*a28cd43dSSascha Wildner #include "zstd_ldm.h"
12*a28cd43dSSascha Wildner
13*a28cd43dSSascha Wildner #include "../common/debug.h"
14*a28cd43dSSascha Wildner #include "zstd_fast.h" /* ZSTD_fillHashTable() */
15*a28cd43dSSascha Wildner #include "zstd_double_fast.h" /* ZSTD_fillDoubleHashTable() */
16*a28cd43dSSascha Wildner
17*a28cd43dSSascha Wildner #define LDM_BUCKET_SIZE_LOG 3
18*a28cd43dSSascha Wildner #define LDM_MIN_MATCH_LENGTH 64
19*a28cd43dSSascha Wildner #define LDM_HASH_RLOG 7
20*a28cd43dSSascha Wildner #define LDM_HASH_CHAR_OFFSET 10
21*a28cd43dSSascha Wildner
ZSTD_ldm_adjustParameters(ldmParams_t * params,ZSTD_compressionParameters const * cParams)22*a28cd43dSSascha Wildner void ZSTD_ldm_adjustParameters(ldmParams_t* params,
23*a28cd43dSSascha Wildner ZSTD_compressionParameters const* cParams)
24*a28cd43dSSascha Wildner {
25*a28cd43dSSascha Wildner params->windowLog = cParams->windowLog;
26*a28cd43dSSascha Wildner ZSTD_STATIC_ASSERT(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX);
27*a28cd43dSSascha Wildner DEBUGLOG(4, "ZSTD_ldm_adjustParameters");
28*a28cd43dSSascha Wildner if (!params->bucketSizeLog) params->bucketSizeLog = LDM_BUCKET_SIZE_LOG;
29*a28cd43dSSascha Wildner if (!params->minMatchLength) params->minMatchLength = LDM_MIN_MATCH_LENGTH;
30*a28cd43dSSascha Wildner if (params->hashLog == 0) {
31*a28cd43dSSascha Wildner params->hashLog = MAX(ZSTD_HASHLOG_MIN, params->windowLog - LDM_HASH_RLOG);
32*a28cd43dSSascha Wildner assert(params->hashLog <= ZSTD_HASHLOG_MAX);
33*a28cd43dSSascha Wildner }
34*a28cd43dSSascha Wildner if (params->hashRateLog == 0) {
35*a28cd43dSSascha Wildner params->hashRateLog = params->windowLog < params->hashLog
36*a28cd43dSSascha Wildner ? 0
37*a28cd43dSSascha Wildner : params->windowLog - params->hashLog;
38*a28cd43dSSascha Wildner }
39*a28cd43dSSascha Wildner params->bucketSizeLog = MIN(params->bucketSizeLog, params->hashLog);
40*a28cd43dSSascha Wildner }
41*a28cd43dSSascha Wildner
ZSTD_ldm_getTableSize(ldmParams_t params)42*a28cd43dSSascha Wildner size_t ZSTD_ldm_getTableSize(ldmParams_t params)
43*a28cd43dSSascha Wildner {
44*a28cd43dSSascha Wildner size_t const ldmHSize = ((size_t)1) << params.hashLog;
45*a28cd43dSSascha Wildner size_t const ldmBucketSizeLog = MIN(params.bucketSizeLog, params.hashLog);
46*a28cd43dSSascha Wildner size_t const ldmBucketSize = ((size_t)1) << (params.hashLog - ldmBucketSizeLog);
47*a28cd43dSSascha Wildner size_t const totalSize = ZSTD_cwksp_alloc_size(ldmBucketSize)
48*a28cd43dSSascha Wildner + ZSTD_cwksp_alloc_size(ldmHSize * sizeof(ldmEntry_t));
49*a28cd43dSSascha Wildner return params.enableLdm ? totalSize : 0;
50*a28cd43dSSascha Wildner }
51*a28cd43dSSascha Wildner
ZSTD_ldm_getMaxNbSeq(ldmParams_t params,size_t maxChunkSize)52*a28cd43dSSascha Wildner size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize)
53*a28cd43dSSascha Wildner {
54*a28cd43dSSascha Wildner return params.enableLdm ? (maxChunkSize / params.minMatchLength) : 0;
55*a28cd43dSSascha Wildner }
56*a28cd43dSSascha Wildner
57*a28cd43dSSascha Wildner /** ZSTD_ldm_getSmallHash() :
58*a28cd43dSSascha Wildner * numBits should be <= 32
59*a28cd43dSSascha Wildner * If numBits==0, returns 0.
60*a28cd43dSSascha Wildner * @return : the most significant numBits of value. */
ZSTD_ldm_getSmallHash(U64 value,U32 numBits)61*a28cd43dSSascha Wildner static U32 ZSTD_ldm_getSmallHash(U64 value, U32 numBits)
62*a28cd43dSSascha Wildner {
63*a28cd43dSSascha Wildner assert(numBits <= 32);
64*a28cd43dSSascha Wildner return numBits == 0 ? 0 : (U32)(value >> (64 - numBits));
65*a28cd43dSSascha Wildner }
66*a28cd43dSSascha Wildner
67*a28cd43dSSascha Wildner /** ZSTD_ldm_getChecksum() :
68*a28cd43dSSascha Wildner * numBitsToDiscard should be <= 32
69*a28cd43dSSascha Wildner * @return : the next most significant 32 bits after numBitsToDiscard */
ZSTD_ldm_getChecksum(U64 hash,U32 numBitsToDiscard)70*a28cd43dSSascha Wildner static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard)
71*a28cd43dSSascha Wildner {
72*a28cd43dSSascha Wildner assert(numBitsToDiscard <= 32);
73*a28cd43dSSascha Wildner return (hash >> (64 - 32 - numBitsToDiscard)) & 0xFFFFFFFF;
74*a28cd43dSSascha Wildner }
75*a28cd43dSSascha Wildner
76*a28cd43dSSascha Wildner /** ZSTD_ldm_getTag() ;
77*a28cd43dSSascha Wildner * Given the hash, returns the most significant numTagBits bits
78*a28cd43dSSascha Wildner * after (32 + hbits) bits.
79*a28cd43dSSascha Wildner *
80*a28cd43dSSascha Wildner * If there are not enough bits remaining, return the last
81*a28cd43dSSascha Wildner * numTagBits bits. */
ZSTD_ldm_getTag(U64 hash,U32 hbits,U32 numTagBits)82*a28cd43dSSascha Wildner static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits)
83*a28cd43dSSascha Wildner {
84*a28cd43dSSascha Wildner assert(numTagBits < 32 && hbits <= 32);
85*a28cd43dSSascha Wildner if (32 - hbits < numTagBits) {
86*a28cd43dSSascha Wildner return hash & (((U32)1 << numTagBits) - 1);
87*a28cd43dSSascha Wildner } else {
88*a28cd43dSSascha Wildner return (hash >> (32 - hbits - numTagBits)) & (((U32)1 << numTagBits) - 1);
89*a28cd43dSSascha Wildner }
90*a28cd43dSSascha Wildner }
91*a28cd43dSSascha Wildner
92*a28cd43dSSascha Wildner /** ZSTD_ldm_getBucket() :
93*a28cd43dSSascha Wildner * Returns a pointer to the start of the bucket associated with hash. */
ZSTD_ldm_getBucket(ldmState_t * ldmState,size_t hash,ldmParams_t const ldmParams)94*a28cd43dSSascha Wildner static ldmEntry_t* ZSTD_ldm_getBucket(
95*a28cd43dSSascha Wildner ldmState_t* ldmState, size_t hash, ldmParams_t const ldmParams)
96*a28cd43dSSascha Wildner {
97*a28cd43dSSascha Wildner return ldmState->hashTable + (hash << ldmParams.bucketSizeLog);
98*a28cd43dSSascha Wildner }
99*a28cd43dSSascha Wildner
100*a28cd43dSSascha Wildner /** ZSTD_ldm_insertEntry() :
101*a28cd43dSSascha Wildner * Insert the entry with corresponding hash into the hash table */
ZSTD_ldm_insertEntry(ldmState_t * ldmState,size_t const hash,const ldmEntry_t entry,ldmParams_t const ldmParams)102*a28cd43dSSascha Wildner static void ZSTD_ldm_insertEntry(ldmState_t* ldmState,
103*a28cd43dSSascha Wildner size_t const hash, const ldmEntry_t entry,
104*a28cd43dSSascha Wildner ldmParams_t const ldmParams)
105*a28cd43dSSascha Wildner {
106*a28cd43dSSascha Wildner BYTE* const bucketOffsets = ldmState->bucketOffsets;
107*a28cd43dSSascha Wildner *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry;
108*a28cd43dSSascha Wildner bucketOffsets[hash]++;
109*a28cd43dSSascha Wildner bucketOffsets[hash] &= ((U32)1 << ldmParams.bucketSizeLog) - 1;
110*a28cd43dSSascha Wildner }
111*a28cd43dSSascha Wildner
112*a28cd43dSSascha Wildner /** ZSTD_ldm_makeEntryAndInsertByTag() :
113*a28cd43dSSascha Wildner *
114*a28cd43dSSascha Wildner * Gets the small hash, checksum, and tag from the rollingHash.
115*a28cd43dSSascha Wildner *
116*a28cd43dSSascha Wildner * If the tag matches (1 << ldmParams.hashRateLog)-1, then
117*a28cd43dSSascha Wildner * creates an ldmEntry from the offset, and inserts it into the hash table.
118*a28cd43dSSascha Wildner *
119*a28cd43dSSascha Wildner * hBits is the length of the small hash, which is the most significant hBits
120*a28cd43dSSascha Wildner * of rollingHash. The checksum is the next 32 most significant bits, followed
121*a28cd43dSSascha Wildner * by ldmParams.hashRateLog bits that make up the tag. */
ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t * ldmState,U64 const rollingHash,U32 const hBits,U32 const offset,ldmParams_t const ldmParams)122*a28cd43dSSascha Wildner static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState,
123*a28cd43dSSascha Wildner U64 const rollingHash,
124*a28cd43dSSascha Wildner U32 const hBits,
125*a28cd43dSSascha Wildner U32 const offset,
126*a28cd43dSSascha Wildner ldmParams_t const ldmParams)
127*a28cd43dSSascha Wildner {
128*a28cd43dSSascha Wildner U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashRateLog);
129*a28cd43dSSascha Wildner U32 const tagMask = ((U32)1 << ldmParams.hashRateLog) - 1;
130*a28cd43dSSascha Wildner if (tag == tagMask) {
131*a28cd43dSSascha Wildner U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits);
132*a28cd43dSSascha Wildner U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
133*a28cd43dSSascha Wildner ldmEntry_t entry;
134*a28cd43dSSascha Wildner entry.offset = offset;
135*a28cd43dSSascha Wildner entry.checksum = checksum;
136*a28cd43dSSascha Wildner ZSTD_ldm_insertEntry(ldmState, hash, entry, ldmParams);
137*a28cd43dSSascha Wildner }
138*a28cd43dSSascha Wildner }
139*a28cd43dSSascha Wildner
140*a28cd43dSSascha Wildner /** ZSTD_ldm_countBackwardsMatch() :
141*a28cd43dSSascha Wildner * Returns the number of bytes that match backwards before pIn and pMatch.
142*a28cd43dSSascha Wildner *
143*a28cd43dSSascha Wildner * We count only bytes where pMatch >= pBase and pIn >= pAnchor. */
ZSTD_ldm_countBackwardsMatch(const BYTE * pIn,const BYTE * pAnchor,const BYTE * pMatch,const BYTE * pMatchBase)144*a28cd43dSSascha Wildner static size_t ZSTD_ldm_countBackwardsMatch(
145*a28cd43dSSascha Wildner const BYTE* pIn, const BYTE* pAnchor,
146*a28cd43dSSascha Wildner const BYTE* pMatch, const BYTE* pMatchBase)
147*a28cd43dSSascha Wildner {
148*a28cd43dSSascha Wildner size_t matchLength = 0;
149*a28cd43dSSascha Wildner while (pIn > pAnchor && pMatch > pMatchBase && pIn[-1] == pMatch[-1]) {
150*a28cd43dSSascha Wildner pIn--;
151*a28cd43dSSascha Wildner pMatch--;
152*a28cd43dSSascha Wildner matchLength++;
153*a28cd43dSSascha Wildner }
154*a28cd43dSSascha Wildner return matchLength;
155*a28cd43dSSascha Wildner }
156*a28cd43dSSascha Wildner
157*a28cd43dSSascha Wildner /** ZSTD_ldm_countBackwardsMatch_2segments() :
158*a28cd43dSSascha Wildner * Returns the number of bytes that match backwards from pMatch,
159*a28cd43dSSascha Wildner * even with the backwards match spanning 2 different segments.
160*a28cd43dSSascha Wildner *
161*a28cd43dSSascha Wildner * On reaching `pMatchBase`, start counting from mEnd */
ZSTD_ldm_countBackwardsMatch_2segments(const BYTE * pIn,const BYTE * pAnchor,const BYTE * pMatch,const BYTE * pMatchBase,const BYTE * pExtDictStart,const BYTE * pExtDictEnd)162*a28cd43dSSascha Wildner static size_t ZSTD_ldm_countBackwardsMatch_2segments(
163*a28cd43dSSascha Wildner const BYTE* pIn, const BYTE* pAnchor,
164*a28cd43dSSascha Wildner const BYTE* pMatch, const BYTE* pMatchBase,
165*a28cd43dSSascha Wildner const BYTE* pExtDictStart, const BYTE* pExtDictEnd)
166*a28cd43dSSascha Wildner {
167*a28cd43dSSascha Wildner size_t matchLength = ZSTD_ldm_countBackwardsMatch(pIn, pAnchor, pMatch, pMatchBase);
168*a28cd43dSSascha Wildner if (pMatch - matchLength != pMatchBase || pMatchBase == pExtDictStart) {
169*a28cd43dSSascha Wildner /* If backwards match is entirely in the extDict or prefix, immediately return */
170*a28cd43dSSascha Wildner return matchLength;
171*a28cd43dSSascha Wildner }
172*a28cd43dSSascha Wildner DEBUGLOG(7, "ZSTD_ldm_countBackwardsMatch_2segments: found 2-parts backwards match (length in prefix==%zu)", matchLength);
173*a28cd43dSSascha Wildner matchLength += ZSTD_ldm_countBackwardsMatch(pIn - matchLength, pAnchor, pExtDictEnd, pExtDictStart);
174*a28cd43dSSascha Wildner DEBUGLOG(7, "final backwards match length = %zu", matchLength);
175*a28cd43dSSascha Wildner return matchLength;
176*a28cd43dSSascha Wildner }
177*a28cd43dSSascha Wildner
178*a28cd43dSSascha Wildner /** ZSTD_ldm_fillFastTables() :
179*a28cd43dSSascha Wildner *
180*a28cd43dSSascha Wildner * Fills the relevant tables for the ZSTD_fast and ZSTD_dfast strategies.
181*a28cd43dSSascha Wildner * This is similar to ZSTD_loadDictionaryContent.
182*a28cd43dSSascha Wildner *
183*a28cd43dSSascha Wildner * The tables for the other strategies are filled within their
184*a28cd43dSSascha Wildner * block compressors. */
ZSTD_ldm_fillFastTables(ZSTD_matchState_t * ms,void const * end)185*a28cd43dSSascha Wildner static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms,
186*a28cd43dSSascha Wildner void const* end)
187*a28cd43dSSascha Wildner {
188*a28cd43dSSascha Wildner const BYTE* const iend = (const BYTE*)end;
189*a28cd43dSSascha Wildner
190*a28cd43dSSascha Wildner switch(ms->cParams.strategy)
191*a28cd43dSSascha Wildner {
192*a28cd43dSSascha Wildner case ZSTD_fast:
193*a28cd43dSSascha Wildner ZSTD_fillHashTable(ms, iend, ZSTD_dtlm_fast);
194*a28cd43dSSascha Wildner break;
195*a28cd43dSSascha Wildner
196*a28cd43dSSascha Wildner case ZSTD_dfast:
197*a28cd43dSSascha Wildner ZSTD_fillDoubleHashTable(ms, iend, ZSTD_dtlm_fast);
198*a28cd43dSSascha Wildner break;
199*a28cd43dSSascha Wildner
200*a28cd43dSSascha Wildner case ZSTD_greedy:
201*a28cd43dSSascha Wildner case ZSTD_lazy:
202*a28cd43dSSascha Wildner case ZSTD_lazy2:
203*a28cd43dSSascha Wildner case ZSTD_btlazy2:
204*a28cd43dSSascha Wildner case ZSTD_btopt:
205*a28cd43dSSascha Wildner case ZSTD_btultra:
206*a28cd43dSSascha Wildner case ZSTD_btultra2:
207*a28cd43dSSascha Wildner break;
208*a28cd43dSSascha Wildner default:
209*a28cd43dSSascha Wildner assert(0); /* not possible : not a valid strategy id */
210*a28cd43dSSascha Wildner }
211*a28cd43dSSascha Wildner
212*a28cd43dSSascha Wildner return 0;
213*a28cd43dSSascha Wildner }
214*a28cd43dSSascha Wildner
215*a28cd43dSSascha Wildner /** ZSTD_ldm_fillLdmHashTable() :
216*a28cd43dSSascha Wildner *
217*a28cd43dSSascha Wildner * Fills hashTable from (lastHashed + 1) to iend (non-inclusive).
218*a28cd43dSSascha Wildner * lastHash is the rolling hash that corresponds to lastHashed.
219*a28cd43dSSascha Wildner *
220*a28cd43dSSascha Wildner * Returns the rolling hash corresponding to position iend-1. */
ZSTD_ldm_fillLdmHashTable(ldmState_t * state,U64 lastHash,const BYTE * lastHashed,const BYTE * iend,const BYTE * base,U32 hBits,ldmParams_t const ldmParams)221*a28cd43dSSascha Wildner static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state,
222*a28cd43dSSascha Wildner U64 lastHash, const BYTE* lastHashed,
223*a28cd43dSSascha Wildner const BYTE* iend, const BYTE* base,
224*a28cd43dSSascha Wildner U32 hBits, ldmParams_t const ldmParams)
225*a28cd43dSSascha Wildner {
226*a28cd43dSSascha Wildner U64 rollingHash = lastHash;
227*a28cd43dSSascha Wildner const BYTE* cur = lastHashed + 1;
228*a28cd43dSSascha Wildner
229*a28cd43dSSascha Wildner while (cur < iend) {
230*a28cd43dSSascha Wildner rollingHash = ZSTD_rollingHash_rotate(rollingHash, cur[-1],
231*a28cd43dSSascha Wildner cur[ldmParams.minMatchLength-1],
232*a28cd43dSSascha Wildner state->hashPower);
233*a28cd43dSSascha Wildner ZSTD_ldm_makeEntryAndInsertByTag(state,
234*a28cd43dSSascha Wildner rollingHash, hBits,
235*a28cd43dSSascha Wildner (U32)(cur - base), ldmParams);
236*a28cd43dSSascha Wildner ++cur;
237*a28cd43dSSascha Wildner }
238*a28cd43dSSascha Wildner return rollingHash;
239*a28cd43dSSascha Wildner }
240*a28cd43dSSascha Wildner
ZSTD_ldm_fillHashTable(ldmState_t * state,const BYTE * ip,const BYTE * iend,ldmParams_t const * params)241*a28cd43dSSascha Wildner void ZSTD_ldm_fillHashTable(
242*a28cd43dSSascha Wildner ldmState_t* state, const BYTE* ip,
243*a28cd43dSSascha Wildner const BYTE* iend, ldmParams_t const* params)
244*a28cd43dSSascha Wildner {
245*a28cd43dSSascha Wildner DEBUGLOG(5, "ZSTD_ldm_fillHashTable");
246*a28cd43dSSascha Wildner if ((size_t)(iend - ip) >= params->minMatchLength) {
247*a28cd43dSSascha Wildner U64 startingHash = ZSTD_rollingHash_compute(ip, params->minMatchLength);
248*a28cd43dSSascha Wildner ZSTD_ldm_fillLdmHashTable(
249*a28cd43dSSascha Wildner state, startingHash, ip, iend - params->minMatchLength, state->window.base,
250*a28cd43dSSascha Wildner params->hashLog - params->bucketSizeLog,
251*a28cd43dSSascha Wildner *params);
252*a28cd43dSSascha Wildner }
253*a28cd43dSSascha Wildner }
254*a28cd43dSSascha Wildner
255*a28cd43dSSascha Wildner
256*a28cd43dSSascha Wildner /** ZSTD_ldm_limitTableUpdate() :
257*a28cd43dSSascha Wildner *
258*a28cd43dSSascha Wildner * Sets cctx->nextToUpdate to a position corresponding closer to anchor
259*a28cd43dSSascha Wildner * if it is far way
260*a28cd43dSSascha Wildner * (after a long match, only update tables a limited amount). */
ZSTD_ldm_limitTableUpdate(ZSTD_matchState_t * ms,const BYTE * anchor)261*a28cd43dSSascha Wildner static void ZSTD_ldm_limitTableUpdate(ZSTD_matchState_t* ms, const BYTE* anchor)
262*a28cd43dSSascha Wildner {
263*a28cd43dSSascha Wildner U32 const curr = (U32)(anchor - ms->window.base);
264*a28cd43dSSascha Wildner if (curr > ms->nextToUpdate + 1024) {
265*a28cd43dSSascha Wildner ms->nextToUpdate =
266*a28cd43dSSascha Wildner curr - MIN(512, curr - ms->nextToUpdate - 1024);
267*a28cd43dSSascha Wildner }
268*a28cd43dSSascha Wildner }
269*a28cd43dSSascha Wildner
ZSTD_ldm_generateSequences_internal(ldmState_t * ldmState,rawSeqStore_t * rawSeqStore,ldmParams_t const * params,void const * src,size_t srcSize)270*a28cd43dSSascha Wildner static size_t ZSTD_ldm_generateSequences_internal(
271*a28cd43dSSascha Wildner ldmState_t* ldmState, rawSeqStore_t* rawSeqStore,
272*a28cd43dSSascha Wildner ldmParams_t const* params, void const* src, size_t srcSize)
273*a28cd43dSSascha Wildner {
274*a28cd43dSSascha Wildner /* LDM parameters */
275*a28cd43dSSascha Wildner int const extDict = ZSTD_window_hasExtDict(ldmState->window);
276*a28cd43dSSascha Wildner U32 const minMatchLength = params->minMatchLength;
277*a28cd43dSSascha Wildner U64 const hashPower = ldmState->hashPower;
278*a28cd43dSSascha Wildner U32 const hBits = params->hashLog - params->bucketSizeLog;
279*a28cd43dSSascha Wildner U32 const ldmBucketSize = 1U << params->bucketSizeLog;
280*a28cd43dSSascha Wildner U32 const hashRateLog = params->hashRateLog;
281*a28cd43dSSascha Wildner U32 const ldmTagMask = (1U << params->hashRateLog) - 1;
282*a28cd43dSSascha Wildner /* Prefix and extDict parameters */
283*a28cd43dSSascha Wildner U32 const dictLimit = ldmState->window.dictLimit;
284*a28cd43dSSascha Wildner U32 const lowestIndex = extDict ? ldmState->window.lowLimit : dictLimit;
285*a28cd43dSSascha Wildner BYTE const* const base = ldmState->window.base;
286*a28cd43dSSascha Wildner BYTE const* const dictBase = extDict ? ldmState->window.dictBase : NULL;
287*a28cd43dSSascha Wildner BYTE const* const dictStart = extDict ? dictBase + lowestIndex : NULL;
288*a28cd43dSSascha Wildner BYTE const* const dictEnd = extDict ? dictBase + dictLimit : NULL;
289*a28cd43dSSascha Wildner BYTE const* const lowPrefixPtr = base + dictLimit;
290*a28cd43dSSascha Wildner /* Input bounds */
291*a28cd43dSSascha Wildner BYTE const* const istart = (BYTE const*)src;
292*a28cd43dSSascha Wildner BYTE const* const iend = istart + srcSize;
293*a28cd43dSSascha Wildner BYTE const* const ilimit = iend - MAX(minMatchLength, HASH_READ_SIZE);
294*a28cd43dSSascha Wildner /* Input positions */
295*a28cd43dSSascha Wildner BYTE const* anchor = istart;
296*a28cd43dSSascha Wildner BYTE const* ip = istart;
297*a28cd43dSSascha Wildner /* Rolling hash */
298*a28cd43dSSascha Wildner BYTE const* lastHashed = NULL;
299*a28cd43dSSascha Wildner U64 rollingHash = 0;
300*a28cd43dSSascha Wildner
301*a28cd43dSSascha Wildner while (ip <= ilimit) {
302*a28cd43dSSascha Wildner size_t mLength;
303*a28cd43dSSascha Wildner U32 const curr = (U32)(ip - base);
304*a28cd43dSSascha Wildner size_t forwardMatchLength = 0, backwardMatchLength = 0;
305*a28cd43dSSascha Wildner ldmEntry_t* bestEntry = NULL;
306*a28cd43dSSascha Wildner if (ip != istart) {
307*a28cd43dSSascha Wildner rollingHash = ZSTD_rollingHash_rotate(rollingHash, lastHashed[0],
308*a28cd43dSSascha Wildner lastHashed[minMatchLength],
309*a28cd43dSSascha Wildner hashPower);
310*a28cd43dSSascha Wildner } else {
311*a28cd43dSSascha Wildner rollingHash = ZSTD_rollingHash_compute(ip, minMatchLength);
312*a28cd43dSSascha Wildner }
313*a28cd43dSSascha Wildner lastHashed = ip;
314*a28cd43dSSascha Wildner
315*a28cd43dSSascha Wildner /* Do not insert and do not look for a match */
316*a28cd43dSSascha Wildner if (ZSTD_ldm_getTag(rollingHash, hBits, hashRateLog) != ldmTagMask) {
317*a28cd43dSSascha Wildner ip++;
318*a28cd43dSSascha Wildner continue;
319*a28cd43dSSascha Wildner }
320*a28cd43dSSascha Wildner
321*a28cd43dSSascha Wildner /* Get the best entry and compute the match lengths */
322*a28cd43dSSascha Wildner {
323*a28cd43dSSascha Wildner ldmEntry_t* const bucket =
324*a28cd43dSSascha Wildner ZSTD_ldm_getBucket(ldmState,
325*a28cd43dSSascha Wildner ZSTD_ldm_getSmallHash(rollingHash, hBits),
326*a28cd43dSSascha Wildner *params);
327*a28cd43dSSascha Wildner ldmEntry_t* cur;
328*a28cd43dSSascha Wildner size_t bestMatchLength = 0;
329*a28cd43dSSascha Wildner U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
330*a28cd43dSSascha Wildner
331*a28cd43dSSascha Wildner for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) {
332*a28cd43dSSascha Wildner size_t curForwardMatchLength, curBackwardMatchLength,
333*a28cd43dSSascha Wildner curTotalMatchLength;
334*a28cd43dSSascha Wildner if (cur->checksum != checksum || cur->offset <= lowestIndex) {
335*a28cd43dSSascha Wildner continue;
336*a28cd43dSSascha Wildner }
337*a28cd43dSSascha Wildner if (extDict) {
338*a28cd43dSSascha Wildner BYTE const* const curMatchBase =
339*a28cd43dSSascha Wildner cur->offset < dictLimit ? dictBase : base;
340*a28cd43dSSascha Wildner BYTE const* const pMatch = curMatchBase + cur->offset;
341*a28cd43dSSascha Wildner BYTE const* const matchEnd =
342*a28cd43dSSascha Wildner cur->offset < dictLimit ? dictEnd : iend;
343*a28cd43dSSascha Wildner BYTE const* const lowMatchPtr =
344*a28cd43dSSascha Wildner cur->offset < dictLimit ? dictStart : lowPrefixPtr;
345*a28cd43dSSascha Wildner
346*a28cd43dSSascha Wildner curForwardMatchLength = ZSTD_count_2segments(
347*a28cd43dSSascha Wildner ip, pMatch, iend,
348*a28cd43dSSascha Wildner matchEnd, lowPrefixPtr);
349*a28cd43dSSascha Wildner if (curForwardMatchLength < minMatchLength) {
350*a28cd43dSSascha Wildner continue;
351*a28cd43dSSascha Wildner }
352*a28cd43dSSascha Wildner curBackwardMatchLength =
353*a28cd43dSSascha Wildner ZSTD_ldm_countBackwardsMatch_2segments(ip, anchor,
354*a28cd43dSSascha Wildner pMatch, lowMatchPtr,
355*a28cd43dSSascha Wildner dictStart, dictEnd);
356*a28cd43dSSascha Wildner curTotalMatchLength = curForwardMatchLength +
357*a28cd43dSSascha Wildner curBackwardMatchLength;
358*a28cd43dSSascha Wildner } else { /* !extDict */
359*a28cd43dSSascha Wildner BYTE const* const pMatch = base + cur->offset;
360*a28cd43dSSascha Wildner curForwardMatchLength = ZSTD_count(ip, pMatch, iend);
361*a28cd43dSSascha Wildner if (curForwardMatchLength < minMatchLength) {
362*a28cd43dSSascha Wildner continue;
363*a28cd43dSSascha Wildner }
364*a28cd43dSSascha Wildner curBackwardMatchLength =
365*a28cd43dSSascha Wildner ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch,
366*a28cd43dSSascha Wildner lowPrefixPtr);
367*a28cd43dSSascha Wildner curTotalMatchLength = curForwardMatchLength +
368*a28cd43dSSascha Wildner curBackwardMatchLength;
369*a28cd43dSSascha Wildner }
370*a28cd43dSSascha Wildner
371*a28cd43dSSascha Wildner if (curTotalMatchLength > bestMatchLength) {
372*a28cd43dSSascha Wildner bestMatchLength = curTotalMatchLength;
373*a28cd43dSSascha Wildner forwardMatchLength = curForwardMatchLength;
374*a28cd43dSSascha Wildner backwardMatchLength = curBackwardMatchLength;
375*a28cd43dSSascha Wildner bestEntry = cur;
376*a28cd43dSSascha Wildner }
377*a28cd43dSSascha Wildner }
378*a28cd43dSSascha Wildner }
379*a28cd43dSSascha Wildner
380*a28cd43dSSascha Wildner /* No match found -- continue searching */
381*a28cd43dSSascha Wildner if (bestEntry == NULL) {
382*a28cd43dSSascha Wildner ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash,
383*a28cd43dSSascha Wildner hBits, curr,
384*a28cd43dSSascha Wildner *params);
385*a28cd43dSSascha Wildner ip++;
386*a28cd43dSSascha Wildner continue;
387*a28cd43dSSascha Wildner }
388*a28cd43dSSascha Wildner
389*a28cd43dSSascha Wildner /* Match found */
390*a28cd43dSSascha Wildner mLength = forwardMatchLength + backwardMatchLength;
391*a28cd43dSSascha Wildner ip -= backwardMatchLength;
392*a28cd43dSSascha Wildner
393*a28cd43dSSascha Wildner {
394*a28cd43dSSascha Wildner /* Store the sequence:
395*a28cd43dSSascha Wildner * ip = curr - backwardMatchLength
396*a28cd43dSSascha Wildner * The match is at (bestEntry->offset - backwardMatchLength)
397*a28cd43dSSascha Wildner */
398*a28cd43dSSascha Wildner U32 const matchIndex = bestEntry->offset;
399*a28cd43dSSascha Wildner U32 const offset = curr - matchIndex;
400*a28cd43dSSascha Wildner rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size;
401*a28cd43dSSascha Wildner
402*a28cd43dSSascha Wildner /* Out of sequence storage */
403*a28cd43dSSascha Wildner if (rawSeqStore->size == rawSeqStore->capacity)
404*a28cd43dSSascha Wildner return ERROR(dstSize_tooSmall);
405*a28cd43dSSascha Wildner seq->litLength = (U32)(ip - anchor);
406*a28cd43dSSascha Wildner seq->matchLength = (U32)mLength;
407*a28cd43dSSascha Wildner seq->offset = offset;
408*a28cd43dSSascha Wildner rawSeqStore->size++;
409*a28cd43dSSascha Wildner }
410*a28cd43dSSascha Wildner
411*a28cd43dSSascha Wildner /* Insert the current entry into the hash table */
412*a28cd43dSSascha Wildner ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits,
413*a28cd43dSSascha Wildner (U32)(lastHashed - base),
414*a28cd43dSSascha Wildner *params);
415*a28cd43dSSascha Wildner
416*a28cd43dSSascha Wildner assert(ip + backwardMatchLength == lastHashed);
417*a28cd43dSSascha Wildner
418*a28cd43dSSascha Wildner /* Fill the hash table from lastHashed+1 to ip+mLength*/
419*a28cd43dSSascha Wildner /* Heuristic: don't need to fill the entire table at end of block */
420*a28cd43dSSascha Wildner if (ip + mLength <= ilimit) {
421*a28cd43dSSascha Wildner rollingHash = ZSTD_ldm_fillLdmHashTable(
422*a28cd43dSSascha Wildner ldmState, rollingHash, lastHashed,
423*a28cd43dSSascha Wildner ip + mLength, base, hBits, *params);
424*a28cd43dSSascha Wildner lastHashed = ip + mLength - 1;
425*a28cd43dSSascha Wildner }
426*a28cd43dSSascha Wildner ip += mLength;
427*a28cd43dSSascha Wildner anchor = ip;
428*a28cd43dSSascha Wildner }
429*a28cd43dSSascha Wildner return iend - anchor;
430*a28cd43dSSascha Wildner }
431*a28cd43dSSascha Wildner
432*a28cd43dSSascha Wildner /*! ZSTD_ldm_reduceTable() :
433*a28cd43dSSascha Wildner * reduce table indexes by `reducerValue` */
ZSTD_ldm_reduceTable(ldmEntry_t * const table,U32 const size,U32 const reducerValue)434*a28cd43dSSascha Wildner static void ZSTD_ldm_reduceTable(ldmEntry_t* const table, U32 const size,
435*a28cd43dSSascha Wildner U32 const reducerValue)
436*a28cd43dSSascha Wildner {
437*a28cd43dSSascha Wildner U32 u;
438*a28cd43dSSascha Wildner for (u = 0; u < size; u++) {
439*a28cd43dSSascha Wildner if (table[u].offset < reducerValue) table[u].offset = 0;
440*a28cd43dSSascha Wildner else table[u].offset -= reducerValue;
441*a28cd43dSSascha Wildner }
442*a28cd43dSSascha Wildner }
443*a28cd43dSSascha Wildner
ZSTD_ldm_generateSequences(ldmState_t * ldmState,rawSeqStore_t * sequences,ldmParams_t const * params,void const * src,size_t srcSize)444*a28cd43dSSascha Wildner size_t ZSTD_ldm_generateSequences(
445*a28cd43dSSascha Wildner ldmState_t* ldmState, rawSeqStore_t* sequences,
446*a28cd43dSSascha Wildner ldmParams_t const* params, void const* src, size_t srcSize)
447*a28cd43dSSascha Wildner {
448*a28cd43dSSascha Wildner U32 const maxDist = 1U << params->windowLog;
449*a28cd43dSSascha Wildner BYTE const* const istart = (BYTE const*)src;
450*a28cd43dSSascha Wildner BYTE const* const iend = istart + srcSize;
451*a28cd43dSSascha Wildner size_t const kMaxChunkSize = 1 << 20;
452*a28cd43dSSascha Wildner size_t const nbChunks = (srcSize / kMaxChunkSize) + ((srcSize % kMaxChunkSize) != 0);
453*a28cd43dSSascha Wildner size_t chunk;
454*a28cd43dSSascha Wildner size_t leftoverSize = 0;
455*a28cd43dSSascha Wildner
456*a28cd43dSSascha Wildner assert(ZSTD_CHUNKSIZE_MAX >= kMaxChunkSize);
457*a28cd43dSSascha Wildner /* Check that ZSTD_window_update() has been called for this chunk prior
458*a28cd43dSSascha Wildner * to passing it to this function.
459*a28cd43dSSascha Wildner */
460*a28cd43dSSascha Wildner assert(ldmState->window.nextSrc >= (BYTE const*)src + srcSize);
461*a28cd43dSSascha Wildner /* The input could be very large (in zstdmt), so it must be broken up into
462*a28cd43dSSascha Wildner * chunks to enforce the maximum distance and handle overflow correction.
463*a28cd43dSSascha Wildner */
464*a28cd43dSSascha Wildner assert(sequences->pos <= sequences->size);
465*a28cd43dSSascha Wildner assert(sequences->size <= sequences->capacity);
466*a28cd43dSSascha Wildner for (chunk = 0; chunk < nbChunks && sequences->size < sequences->capacity; ++chunk) {
467*a28cd43dSSascha Wildner BYTE const* const chunkStart = istart + chunk * kMaxChunkSize;
468*a28cd43dSSascha Wildner size_t const remaining = (size_t)(iend - chunkStart);
469*a28cd43dSSascha Wildner BYTE const *const chunkEnd =
470*a28cd43dSSascha Wildner (remaining < kMaxChunkSize) ? iend : chunkStart + kMaxChunkSize;
471*a28cd43dSSascha Wildner size_t const chunkSize = chunkEnd - chunkStart;
472*a28cd43dSSascha Wildner size_t newLeftoverSize;
473*a28cd43dSSascha Wildner size_t const prevSize = sequences->size;
474*a28cd43dSSascha Wildner
475*a28cd43dSSascha Wildner assert(chunkStart < iend);
476*a28cd43dSSascha Wildner /* 1. Perform overflow correction if necessary. */
477*a28cd43dSSascha Wildner if (ZSTD_window_needOverflowCorrection(ldmState->window, chunkEnd)) {
478*a28cd43dSSascha Wildner U32 const ldmHSize = 1U << params->hashLog;
479*a28cd43dSSascha Wildner U32 const correction = ZSTD_window_correctOverflow(
480*a28cd43dSSascha Wildner &ldmState->window, /* cycleLog */ 0, maxDist, chunkStart);
481*a28cd43dSSascha Wildner ZSTD_ldm_reduceTable(ldmState->hashTable, ldmHSize, correction);
482*a28cd43dSSascha Wildner /* invalidate dictionaries on overflow correction */
483*a28cd43dSSascha Wildner ldmState->loadedDictEnd = 0;
484*a28cd43dSSascha Wildner }
485*a28cd43dSSascha Wildner /* 2. We enforce the maximum offset allowed.
486*a28cd43dSSascha Wildner *
487*a28cd43dSSascha Wildner * kMaxChunkSize should be small enough that we don't lose too much of
488*a28cd43dSSascha Wildner * the window through early invalidation.
489*a28cd43dSSascha Wildner * TODO: * Test the chunk size.
490*a28cd43dSSascha Wildner * * Try invalidation after the sequence generation and test the
491*a28cd43dSSascha Wildner * the offset against maxDist directly.
492*a28cd43dSSascha Wildner *
493*a28cd43dSSascha Wildner * NOTE: Because of dictionaries + sequence splitting we MUST make sure
494*a28cd43dSSascha Wildner * that any offset used is valid at the END of the sequence, since it may
495*a28cd43dSSascha Wildner * be split into two sequences. This condition holds when using
496*a28cd43dSSascha Wildner * ZSTD_window_enforceMaxDist(), but if we move to checking offsets
497*a28cd43dSSascha Wildner * against maxDist directly, we'll have to carefully handle that case.
498*a28cd43dSSascha Wildner */
499*a28cd43dSSascha Wildner ZSTD_window_enforceMaxDist(&ldmState->window, chunkEnd, maxDist, &ldmState->loadedDictEnd, NULL);
500*a28cd43dSSascha Wildner /* 3. Generate the sequences for the chunk, and get newLeftoverSize. */
501*a28cd43dSSascha Wildner newLeftoverSize = ZSTD_ldm_generateSequences_internal(
502*a28cd43dSSascha Wildner ldmState, sequences, params, chunkStart, chunkSize);
503*a28cd43dSSascha Wildner if (ZSTD_isError(newLeftoverSize))
504*a28cd43dSSascha Wildner return newLeftoverSize;
505*a28cd43dSSascha Wildner /* 4. We add the leftover literals from previous iterations to the first
506*a28cd43dSSascha Wildner * newly generated sequence, or add the `newLeftoverSize` if none are
507*a28cd43dSSascha Wildner * generated.
508*a28cd43dSSascha Wildner */
509*a28cd43dSSascha Wildner /* Prepend the leftover literals from the last call */
510*a28cd43dSSascha Wildner if (prevSize < sequences->size) {
511*a28cd43dSSascha Wildner sequences->seq[prevSize].litLength += (U32)leftoverSize;
512*a28cd43dSSascha Wildner leftoverSize = newLeftoverSize;
513*a28cd43dSSascha Wildner } else {
514*a28cd43dSSascha Wildner assert(newLeftoverSize == chunkSize);
515*a28cd43dSSascha Wildner leftoverSize += chunkSize;
516*a28cd43dSSascha Wildner }
517*a28cd43dSSascha Wildner }
518*a28cd43dSSascha Wildner return 0;
519*a28cd43dSSascha Wildner }
520*a28cd43dSSascha Wildner
ZSTD_ldm_skipSequences(rawSeqStore_t * rawSeqStore,size_t srcSize,U32 const minMatch)521*a28cd43dSSascha Wildner void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize, U32 const minMatch) {
522*a28cd43dSSascha Wildner while (srcSize > 0 && rawSeqStore->pos < rawSeqStore->size) {
523*a28cd43dSSascha Wildner rawSeq* seq = rawSeqStore->seq + rawSeqStore->pos;
524*a28cd43dSSascha Wildner if (srcSize <= seq->litLength) {
525*a28cd43dSSascha Wildner /* Skip past srcSize literals */
526*a28cd43dSSascha Wildner seq->litLength -= (U32)srcSize;
527*a28cd43dSSascha Wildner return;
528*a28cd43dSSascha Wildner }
529*a28cd43dSSascha Wildner srcSize -= seq->litLength;
530*a28cd43dSSascha Wildner seq->litLength = 0;
531*a28cd43dSSascha Wildner if (srcSize < seq->matchLength) {
532*a28cd43dSSascha Wildner /* Skip past the first srcSize of the match */
533*a28cd43dSSascha Wildner seq->matchLength -= (U32)srcSize;
534*a28cd43dSSascha Wildner if (seq->matchLength < minMatch) {
535*a28cd43dSSascha Wildner /* The match is too short, omit it */
536*a28cd43dSSascha Wildner if (rawSeqStore->pos + 1 < rawSeqStore->size) {
537*a28cd43dSSascha Wildner seq[1].litLength += seq[0].matchLength;
538*a28cd43dSSascha Wildner }
539*a28cd43dSSascha Wildner rawSeqStore->pos++;
540*a28cd43dSSascha Wildner }
541*a28cd43dSSascha Wildner return;
542*a28cd43dSSascha Wildner }
543*a28cd43dSSascha Wildner srcSize -= seq->matchLength;
544*a28cd43dSSascha Wildner seq->matchLength = 0;
545*a28cd43dSSascha Wildner rawSeqStore->pos++;
546*a28cd43dSSascha Wildner }
547*a28cd43dSSascha Wildner }
548*a28cd43dSSascha Wildner
549*a28cd43dSSascha Wildner /**
550*a28cd43dSSascha Wildner * If the sequence length is longer than remaining then the sequence is split
551*a28cd43dSSascha Wildner * between this block and the next.
552*a28cd43dSSascha Wildner *
553*a28cd43dSSascha Wildner * Returns the current sequence to handle, or if the rest of the block should
554*a28cd43dSSascha Wildner * be literals, it returns a sequence with offset == 0.
555*a28cd43dSSascha Wildner */
maybeSplitSequence(rawSeqStore_t * rawSeqStore,U32 const remaining,U32 const minMatch)556*a28cd43dSSascha Wildner static rawSeq maybeSplitSequence(rawSeqStore_t* rawSeqStore,
557*a28cd43dSSascha Wildner U32 const remaining, U32 const minMatch)
558*a28cd43dSSascha Wildner {
559*a28cd43dSSascha Wildner rawSeq sequence = rawSeqStore->seq[rawSeqStore->pos];
560*a28cd43dSSascha Wildner assert(sequence.offset > 0);
561*a28cd43dSSascha Wildner /* Likely: No partial sequence */
562*a28cd43dSSascha Wildner if (remaining >= sequence.litLength + sequence.matchLength) {
563*a28cd43dSSascha Wildner rawSeqStore->pos++;
564*a28cd43dSSascha Wildner return sequence;
565*a28cd43dSSascha Wildner }
566*a28cd43dSSascha Wildner /* Cut the sequence short (offset == 0 ==> rest is literals). */
567*a28cd43dSSascha Wildner if (remaining <= sequence.litLength) {
568*a28cd43dSSascha Wildner sequence.offset = 0;
569*a28cd43dSSascha Wildner } else if (remaining < sequence.litLength + sequence.matchLength) {
570*a28cd43dSSascha Wildner sequence.matchLength = remaining - sequence.litLength;
571*a28cd43dSSascha Wildner if (sequence.matchLength < minMatch) {
572*a28cd43dSSascha Wildner sequence.offset = 0;
573*a28cd43dSSascha Wildner }
574*a28cd43dSSascha Wildner }
575*a28cd43dSSascha Wildner /* Skip past `remaining` bytes for the future sequences. */
576*a28cd43dSSascha Wildner ZSTD_ldm_skipSequences(rawSeqStore, remaining, minMatch);
577*a28cd43dSSascha Wildner return sequence;
578*a28cd43dSSascha Wildner }
579*a28cd43dSSascha Wildner
ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore_t * rawSeqStore,size_t nbBytes)580*a28cd43dSSascha Wildner void ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes) {
581*a28cd43dSSascha Wildner U32 currPos = (U32)(rawSeqStore->posInSequence + nbBytes);
582*a28cd43dSSascha Wildner while (currPos && rawSeqStore->pos < rawSeqStore->size) {
583*a28cd43dSSascha Wildner rawSeq currSeq = rawSeqStore->seq[rawSeqStore->pos];
584*a28cd43dSSascha Wildner if (currPos >= currSeq.litLength + currSeq.matchLength) {
585*a28cd43dSSascha Wildner currPos -= currSeq.litLength + currSeq.matchLength;
586*a28cd43dSSascha Wildner rawSeqStore->pos++;
587*a28cd43dSSascha Wildner } else {
588*a28cd43dSSascha Wildner rawSeqStore->posInSequence = currPos;
589*a28cd43dSSascha Wildner break;
590*a28cd43dSSascha Wildner }
591*a28cd43dSSascha Wildner }
592*a28cd43dSSascha Wildner if (currPos == 0 || rawSeqStore->pos == rawSeqStore->size) {
593*a28cd43dSSascha Wildner rawSeqStore->posInSequence = 0;
594*a28cd43dSSascha Wildner }
595*a28cd43dSSascha Wildner }
596*a28cd43dSSascha Wildner
ZSTD_ldm_blockCompress(rawSeqStore_t * rawSeqStore,ZSTD_matchState_t * ms,seqStore_t * seqStore,U32 rep[ZSTD_REP_NUM],void const * src,size_t srcSize)597*a28cd43dSSascha Wildner size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
598*a28cd43dSSascha Wildner ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
599*a28cd43dSSascha Wildner void const* src, size_t srcSize)
600*a28cd43dSSascha Wildner {
601*a28cd43dSSascha Wildner const ZSTD_compressionParameters* const cParams = &ms->cParams;
602*a28cd43dSSascha Wildner unsigned const minMatch = cParams->minMatch;
603*a28cd43dSSascha Wildner ZSTD_blockCompressor const blockCompressor =
604*a28cd43dSSascha Wildner ZSTD_selectBlockCompressor(cParams->strategy, ZSTD_matchState_dictMode(ms));
605*a28cd43dSSascha Wildner /* Input bounds */
606*a28cd43dSSascha Wildner BYTE const* const istart = (BYTE const*)src;
607*a28cd43dSSascha Wildner BYTE const* const iend = istart + srcSize;
608*a28cd43dSSascha Wildner /* Input positions */
609*a28cd43dSSascha Wildner BYTE const* ip = istart;
610*a28cd43dSSascha Wildner
611*a28cd43dSSascha Wildner DEBUGLOG(5, "ZSTD_ldm_blockCompress: srcSize=%zu", srcSize);
612*a28cd43dSSascha Wildner /* If using opt parser, use LDMs only as candidates rather than always accepting them */
613*a28cd43dSSascha Wildner if (cParams->strategy >= ZSTD_btopt) {
614*a28cd43dSSascha Wildner size_t lastLLSize;
615*a28cd43dSSascha Wildner ms->ldmSeqStore = rawSeqStore;
616*a28cd43dSSascha Wildner lastLLSize = blockCompressor(ms, seqStore, rep, src, srcSize);
617*a28cd43dSSascha Wildner ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore, srcSize);
618*a28cd43dSSascha Wildner return lastLLSize;
619*a28cd43dSSascha Wildner }
620*a28cd43dSSascha Wildner
621*a28cd43dSSascha Wildner assert(rawSeqStore->pos <= rawSeqStore->size);
622*a28cd43dSSascha Wildner assert(rawSeqStore->size <= rawSeqStore->capacity);
623*a28cd43dSSascha Wildner /* Loop through each sequence and apply the block compressor to the lits */
624*a28cd43dSSascha Wildner while (rawSeqStore->pos < rawSeqStore->size && ip < iend) {
625*a28cd43dSSascha Wildner /* maybeSplitSequence updates rawSeqStore->pos */
626*a28cd43dSSascha Wildner rawSeq const sequence = maybeSplitSequence(rawSeqStore,
627*a28cd43dSSascha Wildner (U32)(iend - ip), minMatch);
628*a28cd43dSSascha Wildner int i;
629*a28cd43dSSascha Wildner /* End signal */
630*a28cd43dSSascha Wildner if (sequence.offset == 0)
631*a28cd43dSSascha Wildner break;
632*a28cd43dSSascha Wildner
633*a28cd43dSSascha Wildner assert(ip + sequence.litLength + sequence.matchLength <= iend);
634*a28cd43dSSascha Wildner
635*a28cd43dSSascha Wildner /* Fill tables for block compressor */
636*a28cd43dSSascha Wildner ZSTD_ldm_limitTableUpdate(ms, ip);
637*a28cd43dSSascha Wildner ZSTD_ldm_fillFastTables(ms, ip);
638*a28cd43dSSascha Wildner /* Run the block compressor */
639*a28cd43dSSascha Wildner DEBUGLOG(5, "pos %u : calling block compressor on segment of size %u", (unsigned)(ip-istart), sequence.litLength);
640*a28cd43dSSascha Wildner {
641*a28cd43dSSascha Wildner size_t const newLitLength =
642*a28cd43dSSascha Wildner blockCompressor(ms, seqStore, rep, ip, sequence.litLength);
643*a28cd43dSSascha Wildner ip += sequence.litLength;
644*a28cd43dSSascha Wildner /* Update the repcodes */
645*a28cd43dSSascha Wildner for (i = ZSTD_REP_NUM - 1; i > 0; i--)
646*a28cd43dSSascha Wildner rep[i] = rep[i-1];
647*a28cd43dSSascha Wildner rep[0] = sequence.offset;
648*a28cd43dSSascha Wildner /* Store the sequence */
649*a28cd43dSSascha Wildner ZSTD_storeSeq(seqStore, newLitLength, ip - newLitLength, iend,
650*a28cd43dSSascha Wildner sequence.offset + ZSTD_REP_MOVE,
651*a28cd43dSSascha Wildner sequence.matchLength - MINMATCH);
652*a28cd43dSSascha Wildner ip += sequence.matchLength;
653*a28cd43dSSascha Wildner }
654*a28cd43dSSascha Wildner }
655*a28cd43dSSascha Wildner /* Fill the tables for the block compressor */
656*a28cd43dSSascha Wildner ZSTD_ldm_limitTableUpdate(ms, ip);
657*a28cd43dSSascha Wildner ZSTD_ldm_fillFastTables(ms, ip);
658*a28cd43dSSascha Wildner /* Compress the last literals */
659*a28cd43dSSascha Wildner return blockCompressor(ms, seqStore, rep, ip, iend - ip);
660*a28cd43dSSascha Wildner }
661