13#include "../common/debug.h"
14#include "../common/xxhash.h"
19#define LDM_BUCKET_SIZE_LOG 3
20#define LDM_MIN_MATCH_LENGTH 64
21#define LDM_HASH_RLOG 7
37 state->rolling = ~(
U32)0;
52 if (hashRateLog > 0 && hashRateLog <= maxBitsInMask) {
53 state->stopMask = (((
U64)1 << hashRateLog) - 1) << (maxBitsInMask - hashRateLog);
56 state->stopMask = ((
U64)1 << hashRateLog) - 1;
66 BYTE const* data,
size_t minMatchLength)
71#define GEAR_ITER_ONCE() do { \
72 hash = (hash << 1) + ZSTD_ldm_gearTab[data[n] & 0xff]; \
75 while (n + 3 < minMatchLength) {
81 while (n < minMatchLength) {
97 BYTE const* data,
size_t size,
98 size_t* splits,
unsigned* numSplits)
103 hash =
state->rolling;
104 mask =
state->stopMask;
107#define GEAR_ITER_ONCE() do { \
108 hash = (hash << 1) + ZSTD_ldm_gearTab[data[n] & 0xff]; \
110 if (UNLIKELY((hash & mask) == 0)) { \
111 splits[*numSplits] = n; \
113 if (*numSplits == LDM_BATCH_SIZE) \
118 while (n + 3 < size) {
131 state->rolling = hash;
136 ZSTD_compressionParameters
const* cParams)
140 DEBUGLOG(4,
"ZSTD_ldm_adjustParameters");
157 size_t const ldmHSize = ((size_t)1) << params.
hashLog;
159 size_t const ldmBucketSize = ((size_t)1) << (params.
hashLog - ldmBucketSizeLog);
162 return params.
enableLdm == ZSTD_ps_enable ? totalSize : 0;
180static void ZSTD_ldm_insertEntry(
ldmState_t* ldmState,
185 unsigned const offset = *pOffset;
187 *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + offset) = entry;
196static size_t ZSTD_ldm_countBackwardsMatch(
197 const BYTE* pIn,
const BYTE* pAnchor,
198 const BYTE* pMatch,
const BYTE* pMatchBase)
200 size_t matchLength = 0;
201 while (pIn > pAnchor && pMatch > pMatchBase && pIn[-1] == pMatch[-1]) {
214static size_t ZSTD_ldm_countBackwardsMatch_2segments(
215 const BYTE* pIn,
const BYTE* pAnchor,
216 const BYTE* pMatch,
const BYTE* pMatchBase,
217 const BYTE* pExtDictStart,
const BYTE* pExtDictEnd)
219 size_t matchLength = ZSTD_ldm_countBackwardsMatch(pIn, pAnchor, pMatch, pMatchBase);
220 if (pMatch - matchLength != pMatchBase || pMatchBase == pExtDictStart) {
224 DEBUGLOG(7,
"ZSTD_ldm_countBackwardsMatch_2segments: found 2-parts backwards match (length in prefix==%zu)", matchLength);
225 matchLength += ZSTD_ldm_countBackwardsMatch(pIn - matchLength, pAnchor, pExtDictEnd, pExtDictStart);
226 DEBUGLOG(7,
"final backwards match length = %zu", matchLength);
240 const BYTE*
const iend = (
const BYTE*)end;
249#ifndef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR
278 BYTE const*
const istart = ip;
283 DEBUGLOG(5,
"ZSTD_ldm_fillHashTable");
285 ZSTD_ldm_gear_init(&hashState, params);
291 hashed = ZSTD_ldm_gear_feed(&hashState, ip, iend - ip, splits, &numSplits);
293 for (n = 0; n < numSplits; n++) {
294 if (ip + splits[n] >= istart + minMatchLength) {
295 BYTE const*
const split = ip + splits[n] - minMatchLength;
296 U64 const xxhash =
XXH64(split, minMatchLength, 0);
297 U32 const hash = (
U32)(xxhash & (((
U32)1 << hBits) - 1));
302 ZSTD_ldm_insertEntry(ldmState, hash, entry, *params);
327size_t ZSTD_ldm_generateSequences_internal(
329 ldmParams_t const* params,
void const* src,
size_t srcSize)
341 BYTE const*
const dictStart = extDict ? dictBase + lowestIndex : NULL;
342 BYTE const*
const dictEnd = extDict ? dictBase + dictLimit : NULL;
343 BYTE const*
const lowPrefixPtr =
base + dictLimit;
345 BYTE const*
const istart = (
BYTE const*)src;
346 BYTE const*
const iend = istart + srcSize;
349 BYTE const* anchor = istart;
350 BYTE const* ip = istart;
358 if (srcSize < minMatchLength)
359 return iend - anchor;
362 ZSTD_ldm_gear_init(&hashState, params);
363 ZSTD_ldm_gear_reset(&hashState, ip, minMatchLength);
364 ip += minMatchLength;
366 while (ip < ilimit) {
371 hashed = ZSTD_ldm_gear_feed(&hashState, ip, ilimit - ip,
374 for (n = 0;
n < numSplits;
n++) {
375 BYTE const*
const split = ip + splits[
n] - minMatchLength;
376 U64 const xxhash =
XXH64(split, minMatchLength, 0);
377 U32 const hash = (
U32)(xxhash & (((
U32)1 << hBits) - 1));
380 candidates[
n].
hash = hash;
382 candidates[
n].
bucket = ZSTD_ldm_getBucket(ldmState, hash, *params);
386 for (n = 0;
n < numSplits;
n++) {
387 size_t forwardMatchLength = 0, backwardMatchLength = 0,
388 bestMatchLength = 0, mLength;
392 U32 const hash = candidates[
n].
hash;
404 if (split < anchor) {
405 ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
409 for (cur = bucket; cur < bucket + entsPerBucket; cur++) {
410 size_t curForwardMatchLength, curBackwardMatchLength,
416 BYTE const*
const curMatchBase =
418 BYTE const*
const pMatch = curMatchBase + cur->
offset;
419 BYTE const*
const matchEnd =
420 cur->
offset < dictLimit ? dictEnd : iend;
421 BYTE const*
const lowMatchPtr =
422 cur->
offset < dictLimit ? dictStart : lowPrefixPtr;
423 curForwardMatchLength =
425 if (curForwardMatchLength < minMatchLength) {
428 curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch_2segments(
429 split, anchor, pMatch, lowMatchPtr, dictStart, dictEnd);
432 curForwardMatchLength =
ZSTD_count(split, pMatch, iend);
433 if (curForwardMatchLength < minMatchLength) {
436 curBackwardMatchLength =
437 ZSTD_ldm_countBackwardsMatch(split, anchor, pMatch, lowPrefixPtr);
439 curTotalMatchLength = curForwardMatchLength + curBackwardMatchLength;
441 if (curTotalMatchLength > bestMatchLength) {
442 bestMatchLength = curTotalMatchLength;
443 forwardMatchLength = curForwardMatchLength;
444 backwardMatchLength = curBackwardMatchLength;
451 if (bestEntry == NULL) {
452 ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
457 offset = (
U32)(split - base) - bestEntry->
offset;
458 mLength = forwardMatchLength + backwardMatchLength;
464 return ERROR(dstSize_tooSmall);
465 seq->
litLength = (
U32)(split - backwardMatchLength - anchor);
473 ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
475 anchor =
split + forwardMatchLength;
485 if (anchor > ip + hashed) {
486 ZSTD_ldm_gear_reset(&hashState, anchor - minMatchLength, minMatchLength);
488 ip = anchor - hashed;
496 return iend - anchor;
502 U32 const reducerValue)
505 for (u = 0; u <
size; u++) {
506 if (
table[u].offset < reducerValue)
table[u].offset = 0;
507 else table[u].offset -= reducerValue;
513 ldmParams_t const* params,
void const* src,
size_t srcSize)
516 BYTE const*
const istart = (
BYTE const*)src;
517 BYTE const*
const iend = istart + srcSize;
518 size_t const kMaxChunkSize = 1 << 20;
519 size_t const nbChunks = (srcSize / kMaxChunkSize) + ((srcSize % kMaxChunkSize) != 0);
521 size_t leftoverSize = 0;
533 for (chunk = 0; chunk < nbChunks && sequences->
size < sequences->
capacity; ++chunk) {
534 BYTE const*
const chunkStart = istart + chunk * kMaxChunkSize;
535 size_t const remaining = (size_t)(iend - chunkStart);
536 BYTE const *
const chunkEnd =
537 (remaining < kMaxChunkSize) ? iend : chunkStart + kMaxChunkSize;
538 size_t const chunkSize = chunkEnd - chunkStart;
539 size_t newLeftoverSize;
540 size_t const prevSize = sequences->
size;
542 assert(chunkStart < iend);
547 &ldmState->
window, 0, maxDist, chunkStart);
548 ZSTD_ldm_reduceTable(ldmState->
hashTable, ldmHSize, correction);
568 newLeftoverSize = ZSTD_ldm_generateSequences_internal(
569 ldmState, sequences, params, chunkStart, chunkSize);
571 return newLeftoverSize;
577 if (prevSize < sequences->size) {
579 leftoverSize = newLeftoverSize;
581 assert(newLeftoverSize == chunkSize);
582 leftoverSize += chunkSize;
591 while (srcSize > 0 && rawSeqStore->
pos < rawSeqStore->
size) {
593 if (srcSize <= seq->litLength) {
600 if (srcSize < seq->matchLength) {
605 if (rawSeqStore->
pos + 1 < rawSeqStore->
size) {
626 U32 const remaining,
U32 const minMatch)
651 while (currPos && rawSeqStore->
pos < rawSeqStore->
size) {
661 if (currPos == 0 || rawSeqStore->
pos == rawSeqStore->
size) {
668 ZSTD_paramSwitch_e useRowMatchFinder,
669 void const* src,
size_t srcSize)
671 const ZSTD_compressionParameters*
const cParams = &ms->
cParams;
672 unsigned const minMatch = cParams->minMatch;
676 BYTE const*
const istart = (
BYTE const*)src;
677 BYTE const*
const iend = istart + srcSize;
679 BYTE const* ip = istart;
681 DEBUGLOG(5,
"ZSTD_ldm_blockCompress: srcSize=%zu", srcSize);
686 lastLLSize = blockCompressor(ms, seqStore, rep, src, srcSize);
694 while (rawSeqStore->
pos < rawSeqStore->
size && ip < iend) {
696 rawSeq const sequence = maybeSplitSequence(rawSeqStore,
697 (
U32)(iend - ip), minMatch);
705 ZSTD_ldm_limitTableUpdate(ms, ip);
706 ZSTD_ldm_fillFastTables(ms, ip);
708 DEBUGLOG(5,
"pos %u : calling block compressor on segment of size %u", (
unsigned)(ip-istart), sequence.
litLength);
711 size_t const newLitLength =
712 blockCompressor(ms, seqStore, rep, ip, sequence.
litLength);
719 ZSTD_storeSeq(seqStore, newLitLength, ip - newLitLength, iend,
726 ZSTD_ldm_limitTableUpdate(ms, ip);
727 ZSTD_ldm_fillFastTables(ms, ip);
729 return blockCompressor(ms, seqStore, rep, ip, iend - ip);
#define ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
#define assert(condition)
uint32_t size(sys::state const &state)
const rawSeqStore_t * ldmSeqStore
ZSTD_compressionParameters cParams
ZSTD_paramSwitch_e enableLdm
ldmMatchCandidate_t matchCandidates[LDM_BATCH_SIZE]
size_t splitIndices[LDM_BATCH_SIZE]
ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_paramSwitch_e useRowMatchFinder, ZSTD_dictMode_e dictMode)
MEM_STATIC ZSTD_dictMode_e ZSTD_matchState_dictMode(const ZSTD_matchState_t *ms)
MEM_STATIC U32 ZSTD_window_needOverflowCorrection(ZSTD_window_t const window, U32 cycleLog, U32 maxDist, U32 loadedDictEnd, void const *src, void const *srcEnd)
MEM_STATIC size_t ZSTD_count_2segments(const BYTE *ip, const BYTE *match, const BYTE *iEnd, const BYTE *mEnd, const BYTE *iStart)
#define ZSTD_CHUNKSIZE_MAX
#define OFFSET_TO_OFFBASE(o)
MEM_STATIC U32 ZSTD_window_hasExtDict(ZSTD_window_t const window)
MEM_STATIC ZSTD_ALLOW_POINTER_OVERFLOW_ATTR U32 ZSTD_window_correctOverflow(ZSTD_window_t *window, U32 cycleLog, U32 maxDist, void const *src)
MEM_STATIC size_t ZSTD_count(const BYTE *pIn, const BYTE *pMatch, const BYTE *const pInLimit)
size_t(* ZSTD_blockCompressor)(ZSTD_matchState_t *bs, seqStore_t *seqStore, U32 rep[ZSTD_REP_NUM], void const *src, size_t srcSize)
HINT_INLINE UNUSED_ATTR void ZSTD_storeSeq(seqStore_t *seqStorePtr, size_t litLength, const BYTE *literals, const BYTE *litLimit, U32 offBase, size_t matchLength)
MEM_STATIC void ZSTD_window_enforceMaxDist(ZSTD_window_t *window, const void *blockEnd, U32 maxDist, U32 *loadedDictEndPtr, const ZSTD_matchState_t **dictMatchStatePtr)
MEM_STATIC size_t ZSTD_cwksp_alloc_size(size_t size)
void ZSTD_fillDoubleHashTable(ZSTD_matchState_t *ms, const void *const end, ZSTD_dictTableLoadMethod_e dtlm, ZSTD_tableFillPurpose_e tfp)
void ZSTD_fillHashTable(ZSTD_matchState_t *ms, const void *const end, ZSTD_dictTableLoadMethod_e dtlm, ZSTD_tableFillPurpose_e tfp)
#define ZSTD_STATIC_ASSERT(c)
size_t ZSTD_ldm_generateSequences(ldmState_t *ldmState, rawSeqStore_t *sequences, ldmParams_t const *params, void const *src, size_t srcSize)
void ZSTD_ldm_skipSequences(rawSeqStore_t *rawSeqStore, size_t srcSize, U32 const minMatch)
void ZSTD_ldm_adjustParameters(ldmParams_t *params, ZSTD_compressionParameters const *cParams)
size_t ZSTD_ldm_blockCompress(rawSeqStore_t *rawSeqStore, ZSTD_matchState_t *ms, seqStore_t *seqStore, U32 rep[ZSTD_REP_NUM], ZSTD_paramSwitch_e useRowMatchFinder, void const *src, size_t srcSize)
#define LDM_BUCKET_SIZE_LOG
void ZSTD_ldm_fillHashTable(ldmState_t *ldmState, const BYTE *ip, const BYTE *iend, ldmParams_t const *params)
size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize)
#define LDM_MIN_MATCH_LENGTH
void ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore_t *rawSeqStore, size_t nbBytes)
size_t ZSTD_ldm_getTableSize(ldmParams_t params)