Split ZSTD_CCtx into smaller sub-structures
This commit is contained in:
+301
-214
@@ -81,11 +81,15 @@ ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
|
||||
cctx->workSpace = (void*)(cctx+1);
|
||||
cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx);
|
||||
|
||||
/* entropy space (never moves) */
|
||||
if (cctx->workSpaceSize < sizeof(ZSTD_entropyCTables_t)) return NULL;
|
||||
/* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */
|
||||
if (cctx->workSpaceSize < HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_blockState_t)) return NULL;
|
||||
assert(((size_t)cctx->workSpace & (sizeof(void*)-1)) == 0); /* ensure correct alignment */
|
||||
cctx->entropy = (ZSTD_entropyCTables_t*)cctx->workSpace;
|
||||
|
||||
cctx->prevBlock = (ZSTD_blockState_t*)cctx->workSpace;
|
||||
cctx->nextBlock = cctx->prevBlock + 1;
|
||||
{
|
||||
void* const ptr = cctx->nextBlock + 1;
|
||||
cctx->entropyWorkspace = (U32*)ptr;
|
||||
}
|
||||
return cctx;
|
||||
}
|
||||
|
||||
@@ -660,7 +664,8 @@ size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
|
||||
U32 const hashLog3 = (cParams.searchLength>3) ?
|
||||
0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
|
||||
size_t const h3Size = ((size_t)1) << hashLog3;
|
||||
size_t const entropySpace = sizeof(ZSTD_entropyCTables_t);
|
||||
size_t const entropySpace = HUF_WORKSPACE_SIZE;
|
||||
size_t const blockStateSpace = 2 * sizeof(ZSTD_blockState_t);
|
||||
size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
|
||||
|
||||
size_t const optBudget =
|
||||
@@ -672,7 +677,7 @@ size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
|
||||
ZSTD_ldm_getTableSize(params->ldmParams.hashLog,
|
||||
params->ldmParams.bucketSizeLog) : 0;
|
||||
|
||||
size_t const neededSpace = entropySpace + tableSpace + tokenSpace +
|
||||
size_t const neededSpace = entropySpace + blockStateSpace + tableSpace + tokenSpace +
|
||||
optSpace + ldmSpace;
|
||||
|
||||
DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx));
|
||||
@@ -794,16 +799,41 @@ static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1,
|
||||
ZSTD_sufficientBuff(buffSize1, blockSize1, buffPol2, params2.cParams, pledgedSrcSize);
|
||||
}
|
||||
|
||||
static void ZSTD_resetBlockState(ZSTD_blockState_t* bs)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ZSTD_REP_NUM; ++i)
|
||||
bs->rep[i] = repStartValue[i];
|
||||
bs->entropy.hufCTable_repeatMode = HUF_repeat_none;
|
||||
bs->entropy.offcode_repeatMode = FSE_repeat_none;
|
||||
bs->entropy.matchlength_repeatMode = FSE_repeat_none;
|
||||
bs->entropy.litlength_repeatMode = FSE_repeat_none;
|
||||
}
|
||||
|
||||
/*! ZSTD_invalidateMatchState()
|
||||
* Invalidate all the matches in the match finder tables.
|
||||
* Requires nextSrc and base to be set (can be NULL).
|
||||
*/
|
||||
static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms)
|
||||
{
|
||||
size_t const endT = (size_t)(ms->nextSrc - ms->base);
|
||||
U32 const end = (U32)endT;
|
||||
assert(endT < (3U<<30));
|
||||
|
||||
ms->lowLimit = end;
|
||||
ms->dictLimit = end;
|
||||
ms->nextToUpdate = end + 1;
|
||||
ms->loadedDictEnd = 0;
|
||||
ms->opt.litLengthSum = 0; /* force reset of btopt stats */
|
||||
}
|
||||
|
||||
/*! ZSTD_continueCCtx() :
|
||||
* reuse CCtx without reset (note : requires no dictionary) */
|
||||
static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize)
|
||||
{
|
||||
size_t const endT = (size_t)(cctx->nextSrc - cctx->base);
|
||||
U32 const end = (U32)endT;
|
||||
size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
|
||||
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
|
||||
DEBUGLOG(4, "ZSTD_continueCCtx: re-use context in place");
|
||||
assert(endT < (3U<<30));
|
||||
|
||||
cctx->blockSize = blockSize; /* previous block size could be different even for same windowLog, due to pledgedSrcSize */
|
||||
cctx->appliedParams = params;
|
||||
@@ -813,14 +843,10 @@ static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pl
|
||||
cctx->appliedParams.fParams.contentSizeFlag = 0;
|
||||
DEBUGLOG(4, "pledged content size : %u ; flag : %u",
|
||||
(U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag);
|
||||
cctx->lowLimit = end;
|
||||
cctx->dictLimit = end;
|
||||
cctx->nextToUpdate = end+1;
|
||||
cctx->stage = ZSTDcs_init;
|
||||
cctx->dictID = 0;
|
||||
cctx->loadedDictEnd = 0;
|
||||
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->seqStore.rep[i] = repStartValue[i]; }
|
||||
cctx->optState.litLengthSum = 0; /* force reset of btopt stats */
|
||||
ZSTD_invalidateMatchState(&cctx->matchState);
|
||||
ZSTD_resetBlockState(cctx->prevBlock);
|
||||
XXH64_reset(&cctx->xxhState, 0);
|
||||
return 0;
|
||||
}
|
||||
@@ -846,10 +872,6 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
zc->appliedParams.cParams.windowLog, (U32)zc->blockSize);
|
||||
assert(!(params.ldmParams.enableLdm &&
|
||||
params.ldmParams.hashEveryLog == ZSTD_LDM_HASHEVERYLOG_NOTSET));
|
||||
zc->entropy->hufCTable_repeatMode = HUF_repeat_none;
|
||||
zc->entropy->offcode_repeatMode = FSE_repeat_none;
|
||||
zc->entropy->matchlength_repeatMode = FSE_repeat_none;
|
||||
zc->entropy->litlength_repeatMode = FSE_repeat_none;
|
||||
return ZSTD_continueCCtx(zc, params, pledgedSrcSize);
|
||||
} }
|
||||
DEBUGLOG(4, "ZSTD_equivalentParams()==0 -> reset CCtx");
|
||||
@@ -880,7 +902,8 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
void* ptr;
|
||||
|
||||
/* Check if workSpace is large enough, alloc a new one if needed */
|
||||
{ size_t const entropySpace = sizeof(ZSTD_entropyCTables_t);
|
||||
{ size_t const entropySpace = HUF_WORKSPACE_SIZE;
|
||||
size_t const blockStateSpace = 2 * sizeof(ZSTD_blockState_t);
|
||||
size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32)
|
||||
+ (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t));
|
||||
size_t const optSpace = ( (params.cParams.strategy == ZSTD_btopt)
|
||||
@@ -890,7 +913,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
size_t const ldmSpace = params.ldmParams.enableLdm
|
||||
? ZSTD_ldm_getTableSize(params.ldmParams.hashLog, params.ldmParams.bucketSizeLog)
|
||||
: 0;
|
||||
size_t const neededSpace = entropySpace + optSpace + ldmSpace +
|
||||
size_t const neededSpace = entropySpace + blockStateSpace + optSpace + ldmSpace +
|
||||
tableSpace + tokenSpace + bufferSpace;
|
||||
DEBUGLOG(4, "Need %uKB workspace, including %uKB for tables, and %uKB for buffers",
|
||||
(U32)(neededSpace>>10), (U32)(tableSpace>>10), (U32)(bufferSpace>>10));
|
||||
@@ -911,10 +934,13 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
zc->workSpaceSize = neededSpace;
|
||||
ptr = zc->workSpace;
|
||||
|
||||
/* entropy space */
|
||||
/* Statically sized space. entropyWorkspace never moves (but prev/next block swap places) */
|
||||
assert(((size_t)zc->workSpace & 3) == 0); /* ensure correct alignment */
|
||||
assert(zc->workSpaceSize >= sizeof(ZSTD_entropyCTables_t));
|
||||
zc->entropy = (ZSTD_entropyCTables_t*)zc->workSpace;
|
||||
assert(zc->workSpaceSize >= 2 * sizeof(ZSTD_blockState_t));
|
||||
zc->prevBlock = (ZSTD_blockState_t*)zc->workSpace;
|
||||
zc->nextBlock = zc->prevBlock + 1;
|
||||
ptr = zc->nextBlock + 1;
|
||||
zc->entropyWorkspace = (U32*)ptr;
|
||||
} }
|
||||
|
||||
/* init params */
|
||||
@@ -930,36 +956,31 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
XXH64_reset(&zc->xxhState, 0);
|
||||
zc->stage = ZSTDcs_init;
|
||||
zc->dictID = 0;
|
||||
zc->loadedDictEnd = 0;
|
||||
zc->entropy->hufCTable_repeatMode = HUF_repeat_none;
|
||||
zc->entropy->offcode_repeatMode = FSE_repeat_none;
|
||||
zc->entropy->matchlength_repeatMode = FSE_repeat_none;
|
||||
zc->entropy->litlength_repeatMode = FSE_repeat_none;
|
||||
zc->base = NULL;
|
||||
zc->dictBase = NULL;
|
||||
zc->lowLimit = 0;
|
||||
zc->dictLimit = 0;
|
||||
zc->nextToUpdate = 1;
|
||||
zc->nextSrc = NULL;
|
||||
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->seqStore.rep[i] = repStartValue[i]; }
|
||||
zc->hashLog3 = hashLog3;
|
||||
zc->optState.litLengthSum = 0;
|
||||
|
||||
ptr = zc->entropy + 1;
|
||||
zc->matchState.nextSrc = NULL;
|
||||
zc->matchState.base = NULL;
|
||||
zc->matchState.dictBase = NULL;
|
||||
zc->matchState.hashLog3 = hashLog3;
|
||||
ZSTD_invalidateMatchState(&zc->matchState);
|
||||
|
||||
ZSTD_resetBlockState(zc->prevBlock);
|
||||
|
||||
ptr = zc->entropyWorkspace + HUF_WORKSPACE_SIZE_U32;
|
||||
|
||||
/* opt parser space */
|
||||
if ((params.cParams.strategy == ZSTD_btopt) | (params.cParams.strategy == ZSTD_btultra)) {
|
||||
optState_t* opt = &zc->matchState.opt;
|
||||
DEBUGLOG(4, "reserving optimal parser space");
|
||||
assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
|
||||
zc->optState.litFreq = (U32*)ptr;
|
||||
zc->optState.litLengthFreq = zc->optState.litFreq + (1<<Litbits);
|
||||
zc->optState.matchLengthFreq = zc->optState.litLengthFreq + (MaxLL+1);
|
||||
zc->optState.offCodeFreq = zc->optState.matchLengthFreq + (MaxML+1);
|
||||
ptr = zc->optState.offCodeFreq + (MaxOff+1);
|
||||
zc->optState.matchTable = (ZSTD_match_t*)ptr;
|
||||
ptr = zc->optState.matchTable + ZSTD_OPT_NUM+1;
|
||||
zc->optState.priceTable = (ZSTD_optimal_t*)ptr;
|
||||
ptr = zc->optState.priceTable + ZSTD_OPT_NUM+1;
|
||||
opt->litFreq = (U32*)ptr;
|
||||
opt->litLengthFreq = opt->litFreq + (1<<Litbits);
|
||||
opt->matchLengthFreq = opt->litLengthFreq + (MaxLL+1);
|
||||
opt->offCodeFreq = opt->matchLengthFreq + (MaxML+1);
|
||||
ptr = opt->offCodeFreq + (MaxOff+1);
|
||||
opt->matchTable = (ZSTD_match_t*)ptr;
|
||||
ptr = opt->matchTable + ZSTD_OPT_NUM+1;
|
||||
opt->priceTable = (ZSTD_optimal_t*)ptr;
|
||||
ptr = opt->priceTable + ZSTD_OPT_NUM+1;
|
||||
}
|
||||
|
||||
/* ldm hash table */
|
||||
@@ -976,10 +997,10 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_noMemset);
|
||||
if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */
|
||||
assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
|
||||
zc->hashTable = (U32*)(ptr);
|
||||
zc->chainTable = zc->hashTable + hSize;
|
||||
zc->hashTable3 = zc->chainTable + chainSize;
|
||||
ptr = zc->hashTable3 + h3Size;
|
||||
zc->matchState.hashTable = (U32*)(ptr);
|
||||
zc->matchState.chainTable = zc->matchState.hashTable + hSize;
|
||||
zc->matchState.hashTable3 = zc->matchState.chainTable + chainSize;
|
||||
ptr = zc->matchState.hashTable3 + h3Size;
|
||||
|
||||
/* sequences storage */
|
||||
zc->seqStore.sequencesStart = (seqDef*)ptr;
|
||||
@@ -1016,7 +1037,8 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
* do not use with extDict variant ! */
|
||||
void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
|
||||
int i;
|
||||
for (i=0; i<ZSTD_REP_NUM; i++) cctx->seqStore.rep[i] = 0;
|
||||
for (i=0; i<ZSTD_REP_NUM; i++) cctx->prevBlock->rep[i] = 0;
|
||||
assert(/* !extDict */ cctx->matchState.lowLimit == cctx->matchState.dictLimit);
|
||||
}
|
||||
|
||||
|
||||
@@ -1050,32 +1072,30 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
|
||||
/* copy tables */
|
||||
{ size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog);
|
||||
size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
|
||||
size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
|
||||
size_t const h3Size = (size_t)1 << srcCCtx->matchState.hashLog3;
|
||||
size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
|
||||
assert((U32*)dstCCtx->chainTable == (U32*)dstCCtx->hashTable + hSize); /* chainTable must follow hashTable */
|
||||
assert((U32*)dstCCtx->hashTable3 == (U32*)dstCCtx->chainTable + chainSize);
|
||||
memcpy(dstCCtx->hashTable, srcCCtx->hashTable, tableSpace); /* presumes all tables follow each other */
|
||||
assert((U32*)dstCCtx->matchState.chainTable == (U32*)dstCCtx->matchState.hashTable + hSize); /* chainTable must follow hashTable */
|
||||
assert((U32*)dstCCtx->matchState.hashTable3 == (U32*)dstCCtx->matchState.chainTable + chainSize);
|
||||
memcpy(dstCCtx->matchState.hashTable, srcCCtx->matchState.hashTable, tableSpace); /* presumes all tables follow each other */
|
||||
}
|
||||
|
||||
/* copy dictionary offsets */
|
||||
dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
|
||||
dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
|
||||
dstCCtx->nextSrc = srcCCtx->nextSrc;
|
||||
dstCCtx->base = srcCCtx->base;
|
||||
dstCCtx->dictBase = srcCCtx->dictBase;
|
||||
dstCCtx->dictLimit = srcCCtx->dictLimit;
|
||||
dstCCtx->lowLimit = srcCCtx->lowLimit;
|
||||
dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
|
||||
dstCCtx->dictID = srcCCtx->dictID;
|
||||
|
||||
/* copy entropy tables */
|
||||
memcpy(dstCCtx->entropy, srcCCtx->entropy, sizeof(ZSTD_entropyCTables_t));
|
||||
/* copy repcodes */
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ZSTD_REP_NUM; ++i)
|
||||
dstCCtx->seqStore.rep[i] = srcCCtx->seqStore.rep[i];
|
||||
ZSTD_matchState_t const* srcMatchState = &srcCCtx->matchState;
|
||||
ZSTD_matchState_t* dstMatchState = &dstCCtx->matchState;
|
||||
dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
|
||||
dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3;
|
||||
dstMatchState->nextSrc = srcMatchState->nextSrc;
|
||||
dstMatchState->base = srcMatchState->base;
|
||||
dstMatchState->dictBase = srcMatchState->dictBase;
|
||||
dstMatchState->dictLimit = srcMatchState->dictLimit;
|
||||
dstMatchState->lowLimit = srcMatchState->lowLimit;
|
||||
dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
|
||||
}
|
||||
dstCCtx->dictID = srcCCtx->dictID;
|
||||
|
||||
/* copy block state */
|
||||
memcpy(dstCCtx->prevBlock, srcCCtx->prevBlock, sizeof(*srcCCtx->prevBlock));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1142,20 +1162,21 @@ static void ZSTD_ldm_reduceTable(ldmEntry_t* const table, U32 const size,
|
||||
* rescale all indexes to avoid future overflow (indexes are U32) */
|
||||
static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
|
||||
{
|
||||
ZSTD_matchState_t* const ms = &zc->matchState;
|
||||
{ U32 const hSize = (U32)1 << zc->appliedParams.cParams.hashLog;
|
||||
ZSTD_reduceTable(zc->hashTable, hSize, reducerValue);
|
||||
ZSTD_reduceTable(ms->hashTable, hSize, reducerValue);
|
||||
}
|
||||
|
||||
if (zc->appliedParams.cParams.strategy != ZSTD_fast) {
|
||||
U32 const chainSize = (U32)1 << zc->appliedParams.cParams.chainLog;
|
||||
if (zc->appliedParams.cParams.strategy == ZSTD_btlazy2)
|
||||
ZSTD_preserveUnsortedMark(zc->chainTable, chainSize, reducerValue);
|
||||
ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue);
|
||||
ZSTD_preserveUnsortedMark(ms->chainTable, chainSize, reducerValue);
|
||||
ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue);
|
||||
}
|
||||
|
||||
if (zc->hashLog3) {
|
||||
U32 const h3Size = (U32)1 << zc->hashLog3;
|
||||
ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue);
|
||||
if (ms->hashLog3) {
|
||||
U32 const h3Size = (U32)1 << ms->hashLog3;
|
||||
ZSTD_reduceTable(ms->hashTable3, h3Size, reducerValue);
|
||||
}
|
||||
|
||||
if (zc->appliedParams.ldmParams.enableLdm) {
|
||||
@@ -1235,10 +1256,12 @@ static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, cons
|
||||
|
||||
static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
|
||||
|
||||
static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t * entropy,
|
||||
static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t const* prevEntropy,
|
||||
ZSTD_entropyCTables_t* nextEntropy,
|
||||
ZSTD_strategy strategy,
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize)
|
||||
const void* src, size_t srcSize,
|
||||
U32* workspace)
|
||||
{
|
||||
size_t const minGain = ZSTD_minGain(srcSize);
|
||||
size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
|
||||
@@ -1247,34 +1270,45 @@ static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t * entropy,
|
||||
symbolEncodingType_e hType = set_compressed;
|
||||
size_t cLitSize;
|
||||
|
||||
/* Prepare nextEntropy assuming reusing the existing table */
|
||||
nextEntropy->hufCTable_repeatMode = prevEntropy->hufCTable_repeatMode;
|
||||
memcpy(nextEntropy->hufCTable, prevEntropy->hufCTable,
|
||||
sizeof(prevEntropy->hufCTable));
|
||||
|
||||
/* small ? don't even attempt compression (speed opt) */
|
||||
# define LITERAL_NOENTROPY 63
|
||||
{ size_t const minLitSize = entropy->hufCTable_repeatMode == HUF_repeat_valid ? 6 : LITERAL_NOENTROPY;
|
||||
{ size_t const minLitSize = prevEntropy->hufCTable_repeatMode == HUF_repeat_valid ? 6 : LITERAL_NOENTROPY;
|
||||
if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
||||
}
|
||||
|
||||
if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
|
||||
{ HUF_repeat repeat = entropy->hufCTable_repeatMode;
|
||||
{ HUF_repeat repeat = prevEntropy->hufCTable_repeatMode;
|
||||
int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
|
||||
if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
|
||||
cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
|
||||
entropy->workspace, sizeof(entropy->workspace), (HUF_CElt*)entropy->hufCTable, &repeat, preferRepeat)
|
||||
workspace, HUF_WORKSPACE_SIZE, (HUF_CElt*)nextEntropy->hufCTable, &repeat, preferRepeat)
|
||||
: HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
|
||||
entropy->workspace, sizeof(entropy->workspace), (HUF_CElt*)entropy->hufCTable, &repeat, preferRepeat);
|
||||
if (repeat != HUF_repeat_none) { hType = set_repeat; } /* reused the existing table */
|
||||
else { entropy->hufCTable_repeatMode = HUF_repeat_check; } /* now have a table to reuse */
|
||||
workspace, HUF_WORKSPACE_SIZE, (HUF_CElt*)nextEntropy->hufCTable, &repeat, preferRepeat);
|
||||
if (repeat != HUF_repeat_none) {
|
||||
/* reused the existing table */
|
||||
hType = set_repeat;
|
||||
}
|
||||
}
|
||||
|
||||
if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) {
|
||||
entropy->hufCTable_repeatMode = HUF_repeat_none;
|
||||
memcpy(nextEntropy->hufCTable, prevEntropy->hufCTable, sizeof(prevEntropy->hufCTable));
|
||||
return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
||||
}
|
||||
if (cLitSize==1) {
|
||||
entropy->hufCTable_repeatMode = HUF_repeat_none;
|
||||
memcpy(nextEntropy->hufCTable, prevEntropy->hufCTable, sizeof(prevEntropy->hufCTable));
|
||||
return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
|
||||
}
|
||||
|
||||
if (hType == set_compressed) {
|
||||
/* using a newly constructed table */
|
||||
nextEntropy->hufCTable_repeatMode = HUF_repeat_check;
|
||||
}
|
||||
|
||||
/* Build header */
|
||||
switch(lhSize)
|
||||
{
|
||||
@@ -1368,10 +1402,11 @@ symbolEncodingType_e ZSTD_selectEncodingType(
|
||||
|
||||
MEM_STATIC
|
||||
size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
|
||||
FSE_CTable* CTable, U32 FSELog, symbolEncodingType_e type,
|
||||
FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type,
|
||||
U32* count, U32 max,
|
||||
BYTE const* codeTable, size_t nbSeq,
|
||||
S16 const* defaultNorm, U32 defaultNormLog, U32 defaultMax,
|
||||
FSE_CTable const* prevCTable, size_t prevCTableSize,
|
||||
void* workspace, size_t workspaceSize)
|
||||
{
|
||||
BYTE* op = (BYTE*)dst;
|
||||
@@ -1380,12 +1415,13 @@ size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
|
||||
switch (type) {
|
||||
case set_rle:
|
||||
*op = codeTable[0];
|
||||
CHECK_F(FSE_buildCTable_rle(CTable, (BYTE)max));
|
||||
CHECK_F(FSE_buildCTable_rle(nextCTable, (BYTE)max));
|
||||
return 1;
|
||||
case set_repeat:
|
||||
memcpy(nextCTable, prevCTable, prevCTableSize);
|
||||
return 0;
|
||||
case set_basic:
|
||||
CHECK_F(FSE_buildCTable_wksp(CTable, defaultNorm, defaultMax, defaultNormLog, workspace, workspaceSize)); /* note : could be pre-calculated */
|
||||
CHECK_F(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, workspace, workspaceSize)); /* note : could be pre-calculated */
|
||||
return 0;
|
||||
case set_compressed: {
|
||||
S16 norm[MaxSeq + 1];
|
||||
@@ -1399,7 +1435,7 @@ size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
|
||||
CHECK_F(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max));
|
||||
{ size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
|
||||
if (FSE_isError(NCountSize)) return NCountSize;
|
||||
CHECK_F(FSE_buildCTable_wksp(CTable, norm, max, tableLog, workspace, workspaceSize));
|
||||
CHECK_F(FSE_buildCTable_wksp(nextCTable, norm, max, tableLog, workspace, workspaceSize));
|
||||
return NCountSize;
|
||||
}
|
||||
}
|
||||
@@ -1492,15 +1528,16 @@ size_t ZSTD_encodeSequences(
|
||||
}
|
||||
|
||||
MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||
ZSTD_entropyCTables_t* entropy,
|
||||
ZSTD_entropyCTables_t const* prevEntropy,
|
||||
ZSTD_entropyCTables_t* nextEntropy,
|
||||
ZSTD_compressionParameters const* cParams,
|
||||
void* dst, size_t dstCapacity)
|
||||
void* dst, size_t dstCapacity, U32* workspace)
|
||||
{
|
||||
const int longOffsets = cParams->windowLog > STREAM_ACCUMULATOR_MIN;
|
||||
U32 count[MaxSeq+1];
|
||||
FSE_CTable* CTable_LitLength = entropy->litlengthCTable;
|
||||
FSE_CTable* CTable_OffsetBits = entropy->offcodeCTable;
|
||||
FSE_CTable* CTable_MatchLength = entropy->matchlengthCTable;
|
||||
FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable;
|
||||
FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable;
|
||||
FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable;
|
||||
U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
|
||||
const seqDef* const sequences = seqStorePtr->sequencesStart;
|
||||
const BYTE* const ofCodeTable = seqStorePtr->ofCode;
|
||||
@@ -1512,13 +1549,14 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||
size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
|
||||
BYTE* seqHead;
|
||||
|
||||
ZSTD_STATIC_ASSERT(sizeof(entropy->workspace) >= (1<<MAX(MLFSELog,LLFSELog)));
|
||||
ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
|
||||
|
||||
/* Compress literals */
|
||||
{ const BYTE* const literals = seqStorePtr->litStart;
|
||||
size_t const litSize = seqStorePtr->lit - literals;
|
||||
size_t const cSize = ZSTD_compressLiterals(
|
||||
entropy, cParams->strategy, op, dstCapacity, literals, litSize);
|
||||
size_t const cSize = ZSTD_compressLiterals(prevEntropy, nextEntropy,
|
||||
cParams->strategy, op, dstCapacity, literals, litSize,
|
||||
workspace);
|
||||
if (ZSTD_isError(cSize))
|
||||
return cSize;
|
||||
assert(cSize <= dstCapacity);
|
||||
@@ -1533,7 +1571,15 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||
op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
|
||||
else
|
||||
op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
|
||||
if (nbSeq==0) return op - ostart;
|
||||
if (nbSeq==0) {
|
||||
memcpy(nextEntropy->litlengthCTable, prevEntropy->litlengthCTable, sizeof(prevEntropy->litlengthCTable));
|
||||
nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode;
|
||||
memcpy(nextEntropy->offcodeCTable, prevEntropy->offcodeCTable, sizeof(prevEntropy->offcodeCTable));
|
||||
nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode;
|
||||
memcpy(nextEntropy->matchlengthCTable, prevEntropy->matchlengthCTable, sizeof(prevEntropy->matchlengthCTable));
|
||||
nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode;
|
||||
return op - ostart;
|
||||
}
|
||||
|
||||
/* seqHead : flags for FSE encoding type */
|
||||
seqHead = op++;
|
||||
@@ -1542,36 +1588,42 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||
ZSTD_seqToCodes(seqStorePtr);
|
||||
/* build CTable for Literal Lengths */
|
||||
{ U32 max = MaxLL;
|
||||
size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, entropy->workspace);
|
||||
size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, workspace);
|
||||
DEBUGLOG(5, "Building LL table");
|
||||
LLtype = ZSTD_selectEncodingType(&entropy->litlength_repeatMode, mostFrequent, nbSeq, LL_defaultNormLog, ZSTD_defaultAllowed);
|
||||
nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode;
|
||||
LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode, mostFrequent, nbSeq, LL_defaultNormLog, ZSTD_defaultAllowed);
|
||||
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
|
||||
count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
|
||||
entropy->workspace, sizeof(entropy->workspace));
|
||||
prevEntropy->litlengthCTable, sizeof(prevEntropy->litlengthCTable),
|
||||
workspace, HUF_WORKSPACE_SIZE);
|
||||
if (ZSTD_isError(countSize)) return countSize;
|
||||
op += countSize;
|
||||
} }
|
||||
/* build CTable for Offsets */
|
||||
{ U32 max = MaxOff;
|
||||
size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, entropy->workspace);
|
||||
size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, workspace);
|
||||
/* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
|
||||
ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
|
||||
DEBUGLOG(5, "Building OF table");
|
||||
Offtype = ZSTD_selectEncodingType(&entropy->offcode_repeatMode, mostFrequent, nbSeq, OF_defaultNormLog, defaultPolicy);
|
||||
nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode;
|
||||
Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode, mostFrequent, nbSeq, OF_defaultNormLog, defaultPolicy);
|
||||
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
|
||||
count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
|
||||
entropy->workspace, sizeof(entropy->workspace));
|
||||
prevEntropy->offcodeCTable, sizeof(prevEntropy->offcodeCTable),
|
||||
workspace, HUF_WORKSPACE_SIZE);
|
||||
if (ZSTD_isError(countSize)) return countSize;
|
||||
op += countSize;
|
||||
} }
|
||||
/* build CTable for MatchLengths */
|
||||
{ U32 max = MaxML;
|
||||
size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, entropy->workspace);
|
||||
size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, workspace);
|
||||
DEBUGLOG(5, "Building ML table");
|
||||
MLtype = ZSTD_selectEncodingType(&entropy->matchlength_repeatMode, mostFrequent, nbSeq, ML_defaultNormLog, ZSTD_defaultAllowed);
|
||||
nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode;
|
||||
MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode, mostFrequent, nbSeq, ML_defaultNormLog, ZSTD_defaultAllowed);
|
||||
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
|
||||
count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
|
||||
entropy->workspace, sizeof(entropy->workspace));
|
||||
prevEntropy->matchlengthCTable, sizeof(prevEntropy->matchlengthCTable),
|
||||
workspace, HUF_WORKSPACE_SIZE);
|
||||
if (ZSTD_isError(countSize)) return countSize;
|
||||
op += countSize;
|
||||
} }
|
||||
@@ -1593,13 +1645,15 @@ MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||
}
|
||||
|
||||
MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr,
|
||||
ZSTD_entropyCTables_t* entropy,
|
||||
ZSTD_entropyCTables_t const* prevEntropy,
|
||||
ZSTD_entropyCTables_t* nextEntropy,
|
||||
ZSTD_compressionParameters const* cParams,
|
||||
void* dst, size_t dstCapacity,
|
||||
size_t srcSize)
|
||||
size_t srcSize, U32* workspace)
|
||||
{
|
||||
size_t const cSize = ZSTD_compressSequences_internal(seqStorePtr, entropy, cParams,
|
||||
dst, dstCapacity);
|
||||
size_t const cSize = ZSTD_compressSequences_internal(
|
||||
seqStorePtr, prevEntropy, nextEntropy, cParams, dst, dstCapacity,
|
||||
workspace);
|
||||
/* If the srcSize <= dstCapacity, then there is enough space to write a
|
||||
* raw uncompressed block. Since we ran out of space, the block must not
|
||||
* be compressible, so fall back to a raw uncompressed block.
|
||||
@@ -1607,34 +1661,28 @@ MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr,
|
||||
int const uncompressibleError = (cSize == ERROR(dstSize_tooSmall)) && (srcSize <= dstCapacity);
|
||||
if (ZSTD_isError(cSize) && !uncompressibleError)
|
||||
return cSize;
|
||||
/* We check that dictionaries have offset codes available for the first
|
||||
* block. After the first block, the offcode table might not have large
|
||||
* enough codes to represent the offsets in the data.
|
||||
*/
|
||||
if (entropy->offcode_repeatMode == FSE_repeat_valid)
|
||||
entropy->offcode_repeatMode = FSE_repeat_check;
|
||||
|
||||
/* Check compressibility */
|
||||
{ size_t const minGain = ZSTD_minGain(srcSize); /* note : fixed formula, maybe should depend on compression level, or strategy */
|
||||
size_t const maxCSize = srcSize - minGain;
|
||||
if (cSize >= maxCSize || uncompressibleError) {
|
||||
entropy->hufCTable_repeatMode = HUF_repeat_none;
|
||||
entropy->offcode_repeatMode = FSE_repeat_none;
|
||||
entropy->matchlength_repeatMode = FSE_repeat_none;
|
||||
entropy->litlength_repeatMode = FSE_repeat_none;
|
||||
return 0; /* block not compressed */
|
||||
} }
|
||||
assert(!ZSTD_isError(cSize));
|
||||
|
||||
/* block is compressed => confirm repcodes in history */
|
||||
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->rep[i] = seqStorePtr->repToConfirm[i]; }
|
||||
/* We check that dictionaries have offset codes available for the first
|
||||
* block. After the first block, the offcode table might not have large
|
||||
* enough codes to represent the offsets in the data.
|
||||
*/
|
||||
if (nextEntropy->offcode_repeatMode == FSE_repeat_valid)
|
||||
nextEntropy->offcode_repeatMode = FSE_repeat_check;
|
||||
|
||||
return cSize;
|
||||
}
|
||||
|
||||
/* ZSTD_selectBlockCompressor() :
|
||||
* Not static, but internal use only (used by long distance matcher)
|
||||
* assumption : strat is a valid strategy */
|
||||
typedef size_t (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
|
||||
ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
|
||||
{
|
||||
static const ZSTD_blockCompressor blockCompressor[2][(unsigned)ZSTD_btultra+1] = {
|
||||
@@ -1673,30 +1721,54 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
|
||||
const void* src, size_t srcSize)
|
||||
{
|
||||
DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u) (dictLimit=%u, nextToUpdate=%u)",
|
||||
(U32)dstCapacity, zc->dictLimit, zc->nextToUpdate);
|
||||
(U32)dstCapacity, zc->matchState.dictLimit, zc->matchState.nextToUpdate);
|
||||
if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1)
|
||||
return 0; /* don't even attempt compression below a certain srcSize */
|
||||
ZSTD_resetSeqStore(&(zc->seqStore));
|
||||
|
||||
/* limited update after a very long match */
|
||||
{ const BYTE* const base = zc->base;
|
||||
{ const BYTE* const base = zc->matchState.base;
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
const U32 current = (U32)(istart-base);
|
||||
if (current > zc->nextToUpdate + 384)
|
||||
zc->nextToUpdate = current - MIN(192, (U32)(current - zc->nextToUpdate - 384));
|
||||
if (current > zc->matchState.nextToUpdate + 384)
|
||||
zc->matchState.nextToUpdate = current - MIN(192, (U32)(current - zc->matchState.nextToUpdate - 384));
|
||||
}
|
||||
/* find and store sequences */
|
||||
{ U32 const extDict = zc->lowLimit < zc->dictLimit;
|
||||
const ZSTD_blockCompressor blockCompressor =
|
||||
zc->appliedParams.ldmParams.enableLdm
|
||||
? (extDict ? ZSTD_compressBlock_ldm_extDict : ZSTD_compressBlock_ldm)
|
||||
: ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, extDict);
|
||||
size_t const lastLLSize = blockCompressor(zc, src, srcSize);
|
||||
const BYTE* const anchor = (const BYTE*)src + srcSize - lastLLSize;
|
||||
ZSTD_storeLastLiterals(&zc->seqStore, anchor, lastLLSize);
|
||||
{
|
||||
U32 const extDict = zc->matchState.lowLimit < zc->matchState.dictLimit;
|
||||
size_t lastLLSize;
|
||||
{ int i; for (i = 0; i < ZSTD_REP_NUM; ++i) zc->nextBlock->rep[i] = zc->prevBlock->rep[i]; }
|
||||
if (zc->appliedParams.ldmParams.enableLdm) {
|
||||
typedef size_t (*ZSTD_ldmBlockCompressor)(
|
||||
ldmState_t* ldms, ZSTD_matchState_t* ms, seqStore_t* seqStore,
|
||||
U32 rep[ZSTD_REP_NUM], ZSTD_CCtx_params const* params,
|
||||
void const* src, size_t srcSize);
|
||||
ZSTD_ldmBlockCompressor const ldmBlockCompressor = extDict ? ZSTD_compressBlock_ldm_extDict : ZSTD_compressBlock_ldm;
|
||||
|
||||
lastLLSize = ldmBlockCompressor(&zc->ldmState, &zc->matchState, &zc->seqStore, zc->nextBlock->rep, &zc->appliedParams, src, srcSize);
|
||||
} else {
|
||||
ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, extDict);
|
||||
|
||||
lastLLSize = blockCompressor(&zc->matchState, &zc->seqStore, zc->nextBlock->rep, &zc->appliedParams.cParams, src, srcSize);
|
||||
}
|
||||
{
|
||||
const BYTE* const anchor = (const BYTE*)src + srcSize - lastLLSize;
|
||||
ZSTD_storeLastLiterals(&zc->seqStore, anchor, lastLLSize);
|
||||
}
|
||||
}
|
||||
/* encode */
|
||||
return ZSTD_compressSequences(&zc->seqStore, zc->entropy, &zc->appliedParams.cParams, dst, dstCapacity, srcSize);
|
||||
{
|
||||
size_t const cSize = ZSTD_compressSequences(&zc->seqStore, &zc->prevBlock->entropy, &zc->nextBlock->entropy, &zc->appliedParams.cParams, dst, dstCapacity, srcSize, zc->entropyWorkspace);
|
||||
if (ZSTD_isError(cSize) || cSize == 0)
|
||||
return cSize;
|
||||
/* confirm repcodes and entropy tables */
|
||||
{
|
||||
ZSTD_blockState_t* const tmp = zc->prevBlock;
|
||||
zc->prevBlock = zc->nextBlock;
|
||||
zc->nextBlock = tmp;
|
||||
}
|
||||
return cSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1725,6 +1797,7 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
|
||||
XXH64_update(&cctx->xxhState, src, srcSize);
|
||||
|
||||
while (remaining) {
|
||||
ZSTD_matchState_t* const ms = &cctx->matchState;
|
||||
U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
|
||||
|
||||
if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
|
||||
@@ -1748,9 +1821,9 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
|
||||
* 3. cctx->lowLimit < 1<<32:
|
||||
* windowLog <= 31 ==> 3<<29 + 1<<windowLog < 7<<29 < 1<<32.
|
||||
*/
|
||||
if (cctx->lowLimit > (3U<<29)) {
|
||||
if (ms->lowLimit > (3U<<29)) {
|
||||
U32 const cycleMask = ((U32)1 << ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy)) - 1;
|
||||
U32 const current = (U32)(ip - cctx->base);
|
||||
U32 const current = (U32)(ip - cctx->matchState.base);
|
||||
U32 const newCurrent = (current & cycleMask) + ((U32)1 << cctx->appliedParams.cParams.windowLog);
|
||||
U32 const correction = current - newCurrent;
|
||||
ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
|
||||
@@ -1759,23 +1832,23 @@ static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
|
||||
assert(current > newCurrent);
|
||||
assert(correction > 1<<28); /* Loose bound, should be about 1<<29 */
|
||||
ZSTD_reduceIndex(cctx, correction);
|
||||
cctx->base += correction;
|
||||
cctx->dictBase += correction;
|
||||
cctx->lowLimit -= correction;
|
||||
cctx->dictLimit -= correction;
|
||||
if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
|
||||
else cctx->nextToUpdate -= correction;
|
||||
DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x", correction, cctx->lowLimit);
|
||||
ms->base += correction;
|
||||
ms->dictBase += correction;
|
||||
ms->lowLimit -= correction;
|
||||
ms->dictLimit -= correction;
|
||||
if (ms->nextToUpdate < correction) ms->nextToUpdate = 0;
|
||||
else ms->nextToUpdate -= correction;
|
||||
DEBUGLOG(4, "Correction of 0x%x bytes to lowLimit=0x%x", correction, ms->lowLimit);
|
||||
}
|
||||
/* enforce maxDist */
|
||||
if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
|
||||
U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
|
||||
if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
|
||||
if (cctx->dictLimit < cctx->lowLimit)
|
||||
if ((U32)(ip+blockSize - ms->base) > ms->loadedDictEnd + maxDist) {
|
||||
U32 const newLowLimit = (U32)(ip+blockSize - ms->base) - maxDist;
|
||||
if (ms->lowLimit < newLowLimit) ms->lowLimit = newLowLimit;
|
||||
if (ms->dictLimit < ms->lowLimit)
|
||||
DEBUGLOG(5, "ZSTD_compress_frameChunk : update dictLimit from %u to %u ",
|
||||
cctx->dictLimit, cctx->lowLimit);
|
||||
if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
|
||||
if (cctx->nextToUpdate < cctx->lowLimit) cctx->nextToUpdate = cctx->lowLimit;
|
||||
ms->dictLimit, ms->lowLimit);
|
||||
if (ms->dictLimit < ms->lowLimit) ms->dictLimit = ms->lowLimit;
|
||||
if (ms->nextToUpdate < ms->lowLimit) ms->nextToUpdate = ms->lowLimit;
|
||||
}
|
||||
|
||||
{ size_t cSize = ZSTD_compressBlock_internal(cctx,
|
||||
@@ -1854,12 +1927,38 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
|
||||
}
|
||||
|
||||
|
||||
static void ZSTD_manageWindowContinuity(ZSTD_matchState_t* ms, void const* src, size_t srcSize)
|
||||
{
|
||||
const BYTE* const ip = (const BYTE*) src;
|
||||
|
||||
/* Check if blocks follow each other */
|
||||
if (src != ms->nextSrc) {
|
||||
/* not contiguous */
|
||||
size_t const distanceFromBase = (size_t)(ms->nextSrc - ms->base);
|
||||
DEBUGLOG(5, "ZSTD_manageWindowContinuity: non contiguous blocks, new segment starts at %u", ms->dictLimit);
|
||||
ms->lowLimit = ms->dictLimit;
|
||||
assert(distanceFromBase == (size_t)(U32)distanceFromBase); /* should never overflow */
|
||||
ms->dictLimit = (U32)distanceFromBase;
|
||||
ms->dictBase = ms->base;
|
||||
ms->base = ip - distanceFromBase;
|
||||
ms->nextToUpdate = ms->dictLimit;
|
||||
if (ms->dictLimit - ms->lowLimit < HASH_READ_SIZE) ms->lowLimit = ms->dictLimit; /* too small extDict */
|
||||
}
|
||||
ms->nextSrc = ip + srcSize;
|
||||
/* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
|
||||
if ((ip+srcSize > ms->dictBase + ms->lowLimit) & (ip < ms->dictBase + ms->dictLimit)) {
|
||||
ptrdiff_t const highInputIdx = (ip + srcSize) - ms->dictBase;
|
||||
U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)ms->dictLimit) ? ms->dictLimit : (U32)highInputIdx;
|
||||
ms->lowLimit = lowLimitMax;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
|
||||
void* dst, size_t dstCapacity,
|
||||
const void* src, size_t srcSize,
|
||||
U32 frame, U32 lastFrameChunk)
|
||||
{
|
||||
const BYTE* const ip = (const BYTE*) src;
|
||||
size_t fhSize = 0;
|
||||
|
||||
DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u", cctx->stage);
|
||||
@@ -1876,27 +1975,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
|
||||
|
||||
if (!srcSize) return fhSize; /* do not generate an empty block if no input */
|
||||
|
||||
/* Check if blocks follow each other */
|
||||
if (src != cctx->nextSrc) {
|
||||
size_t const distanceFromBase = (size_t)(cctx->nextSrc - cctx->base);
|
||||
DEBUGLOG(5, "ZSTD_compressContinue_internal: non contiguous blocks, new segment starts at %u",
|
||||
cctx->dictLimit);
|
||||
cctx->lowLimit = cctx->dictLimit;
|
||||
assert(distanceFromBase == (size_t)(U32)distanceFromBase); /* should never overflow */
|
||||
cctx->dictLimit = (U32)distanceFromBase;
|
||||
cctx->dictBase = cctx->base;
|
||||
cctx->base = ip - distanceFromBase;
|
||||
cctx->nextToUpdate = cctx->dictLimit;
|
||||
if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
|
||||
}
|
||||
cctx->nextSrc = ip + srcSize;
|
||||
|
||||
/* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
|
||||
if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
|
||||
ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
|
||||
U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
|
||||
cctx->lowLimit = lowLimitMax;
|
||||
}
|
||||
ZSTD_manageWindowContinuity(&cctx->matchState, src, srcSize);
|
||||
|
||||
DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (U32)cctx->blockSize);
|
||||
{ size_t const cSize = frame ?
|
||||
@@ -1934,50 +2013,51 @@ size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const
|
||||
/*! ZSTD_loadDictionaryContent() :
|
||||
* @return : 0, or an error code
|
||||
*/
|
||||
static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
|
||||
static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const void* src, size_t srcSize)
|
||||
{
|
||||
const BYTE* const ip = (const BYTE*) src;
|
||||
const BYTE* const iend = ip + srcSize;
|
||||
ZSTD_compressionParameters const* cParams = ¶ms->cParams;
|
||||
|
||||
/* input becomes current prefix */
|
||||
zc->lowLimit = zc->dictLimit;
|
||||
zc->dictLimit = (U32)(zc->nextSrc - zc->base);
|
||||
zc->dictBase = zc->base;
|
||||
zc->base = ip - zc->dictLimit;
|
||||
zc->nextToUpdate = zc->dictLimit;
|
||||
zc->loadedDictEnd = zc->appliedParams.forceWindow ? 0 : (U32)(iend - zc->base);
|
||||
ms->lowLimit = ms->dictLimit;
|
||||
ms->dictLimit = (U32)(ms->nextSrc - ms->base);
|
||||
ms->dictBase = ms->base;
|
||||
ms->base = ip - ms->dictLimit;
|
||||
ms->nextToUpdate = ms->dictLimit;
|
||||
ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->base);
|
||||
|
||||
zc->nextSrc = iend;
|
||||
ms->nextSrc = iend;
|
||||
if (srcSize <= HASH_READ_SIZE) return 0;
|
||||
|
||||
switch(zc->appliedParams.cParams.strategy)
|
||||
switch(params->cParams.strategy)
|
||||
{
|
||||
case ZSTD_fast:
|
||||
ZSTD_fillHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
|
||||
ZSTD_fillHashTable(ms, cParams, iend);
|
||||
break;
|
||||
case ZSTD_dfast:
|
||||
ZSTD_fillDoubleHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
|
||||
ZSTD_fillDoubleHashTable(ms, cParams, iend);
|
||||
break;
|
||||
|
||||
case ZSTD_greedy:
|
||||
case ZSTD_lazy:
|
||||
case ZSTD_lazy2:
|
||||
if (srcSize >= HASH_READ_SIZE)
|
||||
ZSTD_insertAndFindFirstIndex(zc, iend-HASH_READ_SIZE, zc->appliedParams.cParams.searchLength);
|
||||
ZSTD_insertAndFindFirstIndex(ms, cParams, iend-HASH_READ_SIZE);
|
||||
break;
|
||||
|
||||
case ZSTD_btlazy2: /* we want the dictionary table fully sorted */
|
||||
case ZSTD_btopt:
|
||||
case ZSTD_btultra:
|
||||
if (srcSize >= HASH_READ_SIZE)
|
||||
ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, (U32)1 << zc->appliedParams.cParams.searchLog, zc->appliedParams.cParams.searchLength);
|
||||
ZSTD_updateTree(ms, cParams, iend-HASH_READ_SIZE, iend);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0); /* not possible : not a valid strategy id */
|
||||
}
|
||||
|
||||
zc->nextToUpdate = (U32)(iend - zc->base);
|
||||
ms->nextToUpdate = (U32)(iend - ms->base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2001,25 +2081,26 @@ static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSym
|
||||
* https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
|
||||
*/
|
||||
/*! ZSTD_loadZstdDictionary() :
|
||||
* @return : 0, or an error code
|
||||
* @return : dictID, or an error code
|
||||
* assumptions : magic number supposed already checked
|
||||
* dictSize supposed > 8
|
||||
*/
|
||||
static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
|
||||
static size_t ZSTD_loadZstdDictionary(ZSTD_blockState_t* bs, ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const void* dict, size_t dictSize, void* workspace)
|
||||
{
|
||||
const BYTE* dictPtr = (const BYTE*)dict;
|
||||
const BYTE* const dictEnd = dictPtr + dictSize;
|
||||
short offcodeNCount[MaxOff+1];
|
||||
unsigned offcodeMaxValue = MaxOff;
|
||||
size_t dictID;
|
||||
|
||||
ZSTD_STATIC_ASSERT(sizeof(cctx->entropy->workspace) >= (1<<MAX(MLFSELog,LLFSELog)));
|
||||
ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
|
||||
|
||||
dictPtr += 4; /* skip magic number */
|
||||
cctx->dictID = cctx->appliedParams.fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
|
||||
dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
|
||||
dictPtr += 4;
|
||||
|
||||
{ unsigned maxSymbolValue = 255;
|
||||
size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)cctx->entropy->hufCTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr);
|
||||
size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.hufCTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr);
|
||||
if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
|
||||
if (maxSymbolValue < 255) return ERROR(dictionary_corrupted);
|
||||
dictPtr += hufHeaderSize;
|
||||
@@ -2030,7 +2111,7 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t
|
||||
if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
|
||||
if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
|
||||
/* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
|
||||
CHECK_E( FSE_buildCTable_wksp(cctx->entropy->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, cctx->entropy->workspace, sizeof(cctx->entropy->workspace)),
|
||||
CHECK_E( FSE_buildCTable_wksp(bs->entropy.offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, workspace, HUF_WORKSPACE_SIZE),
|
||||
dictionary_corrupted);
|
||||
dictPtr += offcodeHeaderSize;
|
||||
}
|
||||
@@ -2042,7 +2123,7 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t
|
||||
if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
|
||||
/* Every match length code must have non-zero probability */
|
||||
CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
|
||||
CHECK_E( FSE_buildCTable_wksp(cctx->entropy->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, cctx->entropy->workspace, sizeof(cctx->entropy->workspace)),
|
||||
CHECK_E( FSE_buildCTable_wksp(bs->entropy.matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, workspace, HUF_WORKSPACE_SIZE),
|
||||
dictionary_corrupted);
|
||||
dictPtr += matchlengthHeaderSize;
|
||||
}
|
||||
@@ -2054,15 +2135,15 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t
|
||||
if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
|
||||
/* Every literal length code must have non-zero probability */
|
||||
CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
|
||||
CHECK_E( FSE_buildCTable_wksp(cctx->entropy->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, cctx->entropy->workspace, sizeof(cctx->entropy->workspace)),
|
||||
CHECK_E( FSE_buildCTable_wksp(bs->entropy.litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, workspace, HUF_WORKSPACE_SIZE),
|
||||
dictionary_corrupted);
|
||||
dictPtr += litlengthHeaderSize;
|
||||
}
|
||||
|
||||
if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
|
||||
cctx->seqStore.rep[0] = MEM_readLE32(dictPtr+0);
|
||||
cctx->seqStore.rep[1] = MEM_readLE32(dictPtr+4);
|
||||
cctx->seqStore.rep[2] = MEM_readLE32(dictPtr+8);
|
||||
bs->rep[0] = MEM_readLE32(dictPtr+0);
|
||||
bs->rep[1] = MEM_readLE32(dictPtr+4);
|
||||
bs->rep[2] = MEM_readLE32(dictPtr+8);
|
||||
dictPtr += 12;
|
||||
|
||||
{ size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
|
||||
@@ -2076,15 +2157,16 @@ static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t
|
||||
/* All repCodes must be <= dictContentSize and != 0*/
|
||||
{ U32 u;
|
||||
for (u=0; u<3; u++) {
|
||||
if (cctx->seqStore.rep[u] == 0) return ERROR(dictionary_corrupted);
|
||||
if (cctx->seqStore.rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
|
||||
if (bs->rep[u] == 0) return ERROR(dictionary_corrupted);
|
||||
if (bs->rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
|
||||
} }
|
||||
|
||||
cctx->entropy->hufCTable_repeatMode = HUF_repeat_valid;
|
||||
cctx->entropy->offcode_repeatMode = FSE_repeat_valid;
|
||||
cctx->entropy->matchlength_repeatMode = FSE_repeat_valid;
|
||||
cctx->entropy->litlength_repeatMode = FSE_repeat_valid;
|
||||
return ZSTD_loadDictionaryContent(cctx, dictPtr, dictContentSize);
|
||||
bs->entropy.hufCTable_repeatMode = HUF_repeat_valid;
|
||||
bs->entropy.offcode_repeatMode = FSE_repeat_valid;
|
||||
bs->entropy.matchlength_repeatMode = FSE_repeat_valid;
|
||||
bs->entropy.litlength_repeatMode = FSE_repeat_valid;
|
||||
CHECK_F(ZSTD_loadDictionaryContent(ms, params, dictPtr, dictContentSize));
|
||||
return dictID;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2099,12 +2181,12 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx,
|
||||
|
||||
/* dict restricted modes */
|
||||
if (dictMode==ZSTD_dm_rawContent)
|
||||
return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
|
||||
return ZSTD_loadDictionaryContent(&cctx->matchState, &cctx->appliedParams, dict, dictSize);
|
||||
|
||||
if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) {
|
||||
if (dictMode == ZSTD_dm_auto) {
|
||||
DEBUGLOG(4, "raw content dictionary detected");
|
||||
return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
|
||||
return ZSTD_loadDictionaryContent(&cctx->matchState, &cctx->appliedParams, dict, dictSize);
|
||||
}
|
||||
if (dictMode == ZSTD_dm_fullDict)
|
||||
return ERROR(dictionary_wrong);
|
||||
@@ -2112,7 +2194,12 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx,
|
||||
}
|
||||
|
||||
/* dict as full zstd dictionary */
|
||||
return ZSTD_loadZstdDictionary(cctx, dict, dictSize);
|
||||
{
|
||||
size_t const dictID = ZSTD_loadZstdDictionary(cctx->prevBlock, &cctx->matchState, &cctx->appliedParams, dict, dictSize, cctx->entropyWorkspace);
|
||||
if (ZSTD_isError(dictID)) return dictID;
|
||||
cctx->dictID = (U32)dictID;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! ZSTD_compressBegin_internal() :
|
||||
|
||||
Reference in New Issue
Block a user