diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index 899a57b754b..47af1c17aae 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -28,7 +28,7 @@ jobs: steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 - name: make test - run: make test + run: MOREFLAGS="-DZSTD_WINDOW_ALLOW_PICKING_FRACTIONAL_SIZES=1" make test # lasts ~26mn make-test-macos: @@ -51,7 +51,7 @@ jobs: sudo apt-get -qqq update make libc6install make clean - CFLAGS="-m32 -O2" make -j test V=1 + CFLAGS="-m32 -O2" MOREFLAGS="-DZSTD_WINDOW_ALLOW_PICKING_FRACTIONAL_SIZES=1" make -j test V=1 no-intrinsics-fuzztest: runs-on: ubuntu-latest @@ -72,7 +72,7 @@ jobs: steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 - name: ub + address sanitizer on zstreamtest - run: CC=clang make uasan-test-zstream + run: CC=clang MOREFLAGS="-DZSTD_WINDOW_ALLOW_PICKING_FRACTIONAL_SIZES=1" make uasan-test-zstream # lasts ~15mn tsan-fuzztest: @@ -91,7 +91,7 @@ jobs: run: | sudo apt-get -qqq update make libc6install - CC=clang make -C tests test-zstream32 FUZZER_FLAGS="--big-tests" + CC=clang MOREFLAGS="-DZSTD_WINDOW_ALLOW_PICKING_FRACTIONAL_SIZES=1" make -C tests test-zstream32 FUZZER_FLAGS="--big-tests" # lasts ~23mn gcc-8-asan-ubsan-testzstd: @@ -121,7 +121,7 @@ jobs: run: | sudo apt-get -qqq update make libc6install - make -j uasan-test-zstd32 V=1 + MOREFLAGS="-DZSTD_WINDOW_ALLOW_PICKING_FRACTIONAL_SIZES=1" make -j uasan-test-zstd32 V=1 # Note : external libraries must be turned off when using MSAN tests, # because they are not msan-instrumented, @@ -144,7 +144,7 @@ jobs: steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v4.1.1 - name: clang + ASan + UBSan + Fuzz Test - run: CC=clang FUZZER_FLAGS="--long-tests" make clean uasan-fuzztest + run: CC=clang FUZZER_FLAGS="--long-tests" MOREFLAGS="-DZSTD_WINDOW_ALLOW_PICKING_FRACTIONAL_SIZES=1" make clean uasan-fuzztest gcc-asan-ubsan-fuzz32: runs-on: ubuntu-latest @@ -154,7 +154,7 @@ jobs: run: | sudo apt-get -qqq update make libc6install - CFLAGS="-O3 -m32" FUZZER_FLAGS="--long-tests" make uasan-fuzztest + CFLAGS="-O3 -m32" MOREFLAGS="-DZSTD_WINDOW_ALLOW_PICKING_FRACTIONAL_SIZES=1" FUZZER_FLAGS="--long-tests" make uasan-fuzztest clang-asan-fuzz32: runs-on: ubuntu-latest diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index d928b1d3ee3..51483bc5791 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -87,11 +87,10 @@ struct ZSTD_CDict_s { ZSTD_compressedBlockState_t cBlockState; ZSTD_customMem customMem; U32 dictID; - int compressionLevel; /* 0 indicates that advanced API was used to select CDict params */ - ZSTD_ParamSwitch_e useRowMatchFinder; /* Indicates whether the CDict was created with params that would use - * row-based matchfinder. Unless the cdict is reloaded, we will use - * the same greedy/lazy matchfinder at compression time. - */ + ZSTD_CCtx_params params; /* Storage for matchState.cctxParams pointer. + * Not all member fields are used. Used fields: + * cParams, compressionLevel, useRowMatchFinder. */ + /* A compression level of 0 indicates that advanced API was used to select CDict params */ }; /* typedef'd to ZSTD_CDict within "zstd.h" */ ZSTD_CCtx* ZSTD_createCCtx(void) @@ -266,8 +265,9 @@ static int ZSTD_allocateChainTable(const ZSTD_strategy strategy, * enable long distance matching (wlog >= 27, strategy >= btopt). * Returns ZSTD_ps_disable otherwise. */ -static ZSTD_ParamSwitch_e ZSTD_resolveEnableLdm(ZSTD_ParamSwitch_e mode, - const ZSTD_compressionParameters* const cParams) { +static ZSTD_ParamSwitch_e ZSTD_resolveEnableLdm( + ZSTD_ParamSwitch_e mode, + const ZSTD_compressionParameters* const cParams) { if (mode != ZSTD_ps_auto) return mode; return (cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 27) ? ZSTD_ps_enable : ZSTD_ps_disable; } @@ -311,7 +311,7 @@ static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( /* Adjust advanced params according to cParams */ cctxParams.ldmParams.enableLdm = ZSTD_resolveEnableLdm(cctxParams.ldmParams.enableLdm, &cParams); if (cctxParams.ldmParams.enableLdm == ZSTD_ps_enable) { - ZSTD_ldm_adjustParameters(&cctxParams.ldmParams, &cParams); + ZSTD_ldm_adjustParameters(&cctxParams.ldmParams, &cctxParams); assert(cctxParams.ldmParams.hashLog >= cctxParams.ldmParams.bucketSizeLog); assert(cctxParams.ldmParams.hashRateLog < 32); } @@ -321,7 +321,7 @@ static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( cctxParams.maxBlockSize = ZSTD_resolveMaxBlockSize(cctxParams.maxBlockSize); cctxParams.searchForExternalRepcodes = ZSTD_resolveExternalRepcodeSearch(cctxParams.searchForExternalRepcodes, cctxParams.compressionLevel); - assert(!ZSTD_checkCParams(cParams)); + assert(!ZSTD_checkCCtxCParams_internal(&cctxParams)); return cctxParams; } @@ -365,33 +365,46 @@ size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) #define ZSTD_NO_CLEVEL 0 -/** - * Initializes `cctxParams` from `params` and `compressionLevel`. - * @param compressionLevel If params are derived from a compression level then that compression level, otherwise ZSTD_NO_CLEVEL. - */ -static void -ZSTD_CCtxParams_init_internal(ZSTD_CCtx_params* cctxParams, - const ZSTD_parameters* params, - int compressionLevel) +static void ZSTD_CCtxParams_init_fromCCtxParams( + ZSTD_CCtx_params* cctxParams, + const ZSTD_CCtx_params* srcParams) { - assert(!ZSTD_checkCParams(params->cParams)); + assert(!ZSTD_checkCCtxCParams_internal(srcParams)); ZSTD_memset(cctxParams, 0, sizeof(*cctxParams)); - cctxParams->cParams = params->cParams; - cctxParams->fParams = params->fParams; + cctxParams->cParams = srcParams->cParams; + cctxParams->windowFrac = srcParams->windowFrac; + cctxParams->fParams = srcParams->fParams; /* Should not matter, as all cParams are presumed properly defined. * But, set it for tracing anyway. */ - cctxParams->compressionLevel = compressionLevel; - cctxParams->useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams->useRowMatchFinder, ¶ms->cParams); - cctxParams->postBlockSplitter = ZSTD_resolveBlockSplitterMode(cctxParams->postBlockSplitter, ¶ms->cParams); - cctxParams->ldmParams.enableLdm = ZSTD_resolveEnableLdm(cctxParams->ldmParams.enableLdm, ¶ms->cParams); + cctxParams->compressionLevel = srcParams->compressionLevel; + cctxParams->useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams->useRowMatchFinder, &cctxParams->cParams); + cctxParams->postBlockSplitter = ZSTD_resolveBlockSplitterMode(cctxParams->postBlockSplitter, &cctxParams->cParams); + cctxParams->ldmParams.enableLdm = ZSTD_resolveEnableLdm(cctxParams->ldmParams.enableLdm, &cctxParams->cParams); cctxParams->validateSequences = ZSTD_resolveExternalSequenceValidation(cctxParams->validateSequences); cctxParams->maxBlockSize = ZSTD_resolveMaxBlockSize(cctxParams->maxBlockSize); - cctxParams->searchForExternalRepcodes = ZSTD_resolveExternalRepcodeSearch(cctxParams->searchForExternalRepcodes, compressionLevel); + cctxParams->searchForExternalRepcodes = ZSTD_resolveExternalRepcodeSearch(cctxParams->searchForExternalRepcodes, cctxParams->compressionLevel); DEBUGLOG(4, "ZSTD_CCtxParams_init_internal: useRowMatchFinder=%d, useBlockSplitter=%d ldm=%d", cctxParams->useRowMatchFinder, cctxParams->postBlockSplitter, cctxParams->ldmParams.enableLdm); } +/** + * Initializes `cctxParams` from `params` and `compressionLevel`. + * @param compressionLevel If params are derived from a compression level then that compression level, otherwise ZSTD_NO_CLEVEL. + */ +static void +ZSTD_CCtxParams_init_internal(ZSTD_CCtx_params* cctxParams, + const ZSTD_parameters* params, + int compressionLevel) +{ + ZSTD_CCtx_params tmpParams; + ZSTD_memset(&tmpParams, 0, sizeof(tmpParams)); + tmpParams.cParams = params->cParams; + tmpParams.fParams = params->fParams; + tmpParams.compressionLevel = compressionLevel; + ZSTD_CCtxParams_init_fromCCtxParams(cctxParams, &tmpParams); +} + size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) { RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!"); @@ -432,6 +445,11 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) bounds.upperBound = ZSTD_WINDOWLOG_MAX; return bounds; + case ZSTD_c_windowFrac: + bounds.lowerBound = 0; + bounds.upperBound = 7; + return bounds; + case ZSTD_c_hashLog: bounds.lowerBound = ZSTD_HASHLOG_MIN; bounds.upperBound = ZSTD_HASHLOG_MAX; @@ -671,6 +689,7 @@ static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) case ZSTD_c_format: case ZSTD_c_windowLog: + case ZSTD_c_windowFrac: case ZSTD_c_contentSizeFlag: case ZSTD_c_checksumFlag: case ZSTD_c_dictIDFlag: @@ -724,6 +743,7 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value) case ZSTD_c_compressionLevel: case ZSTD_c_windowLog: + case ZSTD_c_windowFrac: case ZSTD_c_hashLog: case ZSTD_c_chainLog: case ZSTD_c_searchLog: @@ -792,8 +812,20 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, if (value!=0) /* 0 => use default */ BOUNDCHECK(ZSTD_c_windowLog, value); CCtxParams->cParams.windowLog = (U32)value; + if (value == ZSTD_WINDOWLOG_MAX) { + CCtxParams->windowFrac = 0; + } return CCtxParams->cParams.windowLog; + case ZSTD_c_windowFrac : + BOUNDCHECK(ZSTD_c_windowFrac, value); + if (CCtxParams->cParams.windowLog != ZSTD_WINDOWLOG_MAX) { + CCtxParams->windowFrac = (U32)value; + } else { + CCtxParams->windowFrac = 0; + } + return CCtxParams->windowFrac; + case ZSTD_c_hashLog : if (value!=0) /* 0 => use default */ BOUNDCHECK(ZSTD_c_hashLog, value); @@ -1039,6 +1071,9 @@ size_t ZSTD_CCtxParams_getParameter( case ZSTD_c_windowLog : *value = (int)CCtxParams->cParams.windowLog; break; + case ZSTD_c_windowFrac : + *value = (int)CCtxParams->windowFrac; + break; case ZSTD_c_hashLog : *value = (int)CCtxParams->cParams.hashLog; break; @@ -1236,7 +1271,7 @@ size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSr return 0; } -static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams( +static ZSTD_CCtx_params ZSTD_dedicatedDictSearch_getCParams( int const compressionLevel, size_t const dictSize); static int ZSTD_dedicatedDictSearch_isSupported( @@ -1381,27 +1416,43 @@ size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset) return 0; } +size_t ZSTD_checkCCtxCParams_internal(const ZSTD_CCtx_params* params) +{ + BOUNDCHECK(ZSTD_c_windowLog, (int)params->cParams.windowLog); + BOUNDCHECK(ZSTD_c_windowFrac, (int)params->windowFrac); + RETURN_ERROR_IF( + params->cParams.windowLog + !!params->windowFrac > ZSTD_WINDOWLOG_MAX, + parameter_outOfBound, "Param out of bounds"); + BOUNDCHECK(ZSTD_c_chainLog, (int)params->cParams.chainLog); + BOUNDCHECK(ZSTD_c_hashLog, (int)params->cParams.hashLog); + BOUNDCHECK(ZSTD_c_searchLog, (int)params->cParams.searchLog); + BOUNDCHECK(ZSTD_c_minMatch, (int)params->cParams.minMatch); + BOUNDCHECK(ZSTD_c_targetLength, (int)params->cParams.targetLength); + BOUNDCHECK(ZSTD_c_strategy, (int)params->cParams.strategy); + return 0; +} /** ZSTD_checkCParams() : - control CParam values remain within authorized range. + Control CParam values remain within authorized range. Only used for + cparams coming from the user. Checks are limited compared to checking the + whole CCtxParams via the `ZSTD_checkCCtxCParams_internal()`. @return : 0, or an error code if one value is beyond authorized range */ size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams) { - BOUNDCHECK(ZSTD_c_windowLog, (int)cParams.windowLog); - BOUNDCHECK(ZSTD_c_chainLog, (int)cParams.chainLog); - BOUNDCHECK(ZSTD_c_hashLog, (int)cParams.hashLog); - BOUNDCHECK(ZSTD_c_searchLog, (int)cParams.searchLog); - BOUNDCHECK(ZSTD_c_minMatch, (int)cParams.minMatch); - BOUNDCHECK(ZSTD_c_targetLength,(int)cParams.targetLength); - BOUNDCHECK(ZSTD_c_strategy, (int)cParams.strategy); + BOUNDCHECK(ZSTD_c_windowLog, (int)cParams.windowLog); + BOUNDCHECK(ZSTD_c_chainLog, (int)cParams.chainLog); + BOUNDCHECK(ZSTD_c_hashLog, (int)cParams.hashLog); + BOUNDCHECK(ZSTD_c_searchLog, (int)cParams.searchLog); + BOUNDCHECK(ZSTD_c_minMatch, (int)cParams.minMatch); + BOUNDCHECK(ZSTD_c_targetLength, (int)cParams.targetLength); + BOUNDCHECK(ZSTD_c_strategy, (int)cParams.strategy); return 0; } /** ZSTD_clampCParams() : - * make CParam values within valid range. - * @return : valid CParams */ -static ZSTD_compressionParameters -ZSTD_clampCParams(ZSTD_compressionParameters cParams) + * make CParam values within valid range. */ +static void +ZSTD_clampCParams(ZSTD_CCtx_params* params) { # define CLAMP_TYPE(cParam, val, type) \ do { \ @@ -1410,54 +1461,54 @@ ZSTD_clampCParams(ZSTD_compressionParameters cParams) else if ((int)val>bounds.upperBound) val=(type)bounds.upperBound; \ } while (0) # define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, unsigned) - CLAMP(ZSTD_c_windowLog, cParams.windowLog); - CLAMP(ZSTD_c_chainLog, cParams.chainLog); - CLAMP(ZSTD_c_hashLog, cParams.hashLog); - CLAMP(ZSTD_c_searchLog, cParams.searchLog); - CLAMP(ZSTD_c_minMatch, cParams.minMatch); - CLAMP(ZSTD_c_targetLength,cParams.targetLength); - CLAMP_TYPE(ZSTD_c_strategy,cParams.strategy, ZSTD_strategy); - return cParams; + CLAMP(ZSTD_c_windowLog, params->cParams.windowLog); + if (params->cParams.windowLog == ZSTD_WINDOWLOG_MAX) { + params->windowFrac = 0; + } + CLAMP(ZSTD_c_windowFrac, params->windowFrac); + CLAMP(ZSTD_c_chainLog, params->cParams.chainLog); + CLAMP(ZSTD_c_hashLog, params->cParams.hashLog); + CLAMP(ZSTD_c_searchLog, params->cParams.searchLog); + CLAMP(ZSTD_c_minMatch, params->cParams.minMatch); + CLAMP(ZSTD_c_targetLength, params->cParams.targetLength); + CLAMP_TYPE(ZSTD_c_strategy, params->cParams.strategy, ZSTD_strategy); } /** ZSTD_cycleLog() : * condition for correct operation : hashLog > 1 */ -U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) +U32 ZSTD_cycleLog(U32 chainLog, ZSTD_strategy strat) { U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2); - return hashLog - btScale; + return chainLog - btScale; } /** ZSTD_dictAndWindowLog() : - * Returns an adjusted window log that is large enough to fit the source and the dictionary. + * Adjusts the provided window params to be large enough to fit the source and the dictionary. * The zstd format says that the entire dictionary is valid if one byte of the dictionary * is within the window. So the hashLog and chainLog should be large enough to reference both * the dictionary and the window. So we must use this adjusted dictAndWindowLog when downsizing * the hashLog and windowLog. * NOTE: srcSize must not be ZSTD_CONTENTSIZE_UNKNOWN. */ -static U32 ZSTD_dictAndWindowLog(U32 windowLog, U64 srcSize, U64 dictSize) +static void ZSTD_dictAndWindowLog(ZSTD_CCtx_params* params, U64 srcSize, U64 dictSize) { - const U64 maxWindowSize = 1ULL << ZSTD_WINDOWLOG_MAX; /* No dictionary ==> No change */ if (dictSize == 0) { - return windowLog; + return; } - assert(windowLog <= ZSTD_WINDOWLOG_MAX); + assert(params->cParams.windowLog + !!params->windowFrac <= ZSTD_WINDOWLOG_MAX); assert(srcSize != ZSTD_CONTENTSIZE_UNKNOWN); /* Handled in ZSTD_adjustCParams_internal() */ { - U64 const windowSize = 1ULL << windowLog; + U64 const windowSize = ZSTD_windowSize(params); U64 const dictAndWindowSize = dictSize + windowSize; /* If the window size is already large enough to fit both the source and the dictionary * then just use the window size. Otherwise adjust so that it fits the dictionary and * the window. */ if (windowSize >= dictSize + srcSize) { - return windowLog; /* Window size large enough already */ - } else if (dictAndWindowSize >= maxWindowSize) { - return ZSTD_WINDOWLOG_MAX; /* Larger than max window log */ - } else { - return ZSTD_highbit32((U32)dictAndWindowSize - 1) + 1; + /* Window size large enough already */ + } else { + ZSTD_setMinimalWindowLogAndFrac(params, (U32)dictAndWindowSize, ZSTD_WINDOWLOG_MIN); } } } @@ -1469,56 +1520,57 @@ static U32 ZSTD_dictAndWindowLog(U32 windowLog, U64 srcSize, U64 dictSize) * `mode` is the mode for parameter adjustment. See docs for `ZSTD_CParamMode_e`. * note : `srcSize==0` means 0! * condition : cPar is presumed validated (can be checked using ZSTD_checkCParams()). */ -static ZSTD_compressionParameters -ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, +static void +ZSTD_adjustCParams_internal(ZSTD_CCtx_params* params, unsigned long long srcSize, size_t dictSize, ZSTD_CParamMode_e mode, ZSTD_ParamSwitch_e useRowMatchFinder) { + ZSTD_compressionParameters* cPar = ¶ms->cParams; const U64 minSrcSize = 513; /* (1<<9) + 1 */ - const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1); - assert(ZSTD_checkCParams(cPar)==0); + const U64 maxWindowResize = 15ULL << (ZSTD_WINDOWLOG_MAX-4); + assert(ZSTD_checkCCtxCParams_internal(params)==0); /* Cascade the selected strategy down to the next-highest one built into * this binary. */ #ifdef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR - if (cPar.strategy == ZSTD_btultra2) { - cPar.strategy = ZSTD_btultra; + if (cPar->strategy == ZSTD_btultra2) { + cPar->strategy = ZSTD_btultra; } - if (cPar.strategy == ZSTD_btultra) { - cPar.strategy = ZSTD_btopt; + if (cPar->strategy == ZSTD_btultra) { + cPar->strategy = ZSTD_btopt; } #endif #ifdef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR - if (cPar.strategy == ZSTD_btopt) { - cPar.strategy = ZSTD_btlazy2; + if (cPar->strategy == ZSTD_btopt) { + cPar->strategy = ZSTD_btlazy2; } #endif #ifdef ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR - if (cPar.strategy == ZSTD_btlazy2) { - cPar.strategy = ZSTD_lazy2; + if (cPar->strategy == ZSTD_btlazy2) { + cPar->strategy = ZSTD_lazy2; } #endif #ifdef ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR - if (cPar.strategy == ZSTD_lazy2) { - cPar.strategy = ZSTD_lazy; + if (cPar->strategy == ZSTD_lazy2) { + cPar->strategy = ZSTD_lazy; } #endif #ifdef ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR - if (cPar.strategy == ZSTD_lazy) { - cPar.strategy = ZSTD_greedy; + if (cPar->strategy == ZSTD_lazy) { + cPar->strategy = ZSTD_greedy; } #endif #ifdef ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR - if (cPar.strategy == ZSTD_greedy) { - cPar.strategy = ZSTD_dfast; + if (cPar->strategy == ZSTD_greedy) { + cPar->strategy = ZSTD_dfast; } #endif #ifdef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR - if (cPar.strategy == ZSTD_dfast) { - cPar.strategy = ZSTD_fast; - cPar.targetLength = 0; + if (cPar->strategy == ZSTD_dfast) { + cPar->strategy = ZSTD_fast; + cPar->targetLength = 0; } #endif @@ -1554,31 +1606,54 @@ ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, && (dictSize <= maxWindowResize) ) { U32 const tSize = (U32)(srcSize + dictSize); static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN; - U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN : - ZSTD_highbit32(tSize-1) + 1; - if (cPar.windowLog > srcLog) cPar.windowLog = srcLog; + if (ZSTD_windowSize(params) > tSize) { + if (tSize < hashSizeMin) { + cPar->windowLog = ZSTD_HASHLOG_MIN; + params->windowFrac = 0; + } else +#if !ZSTD_WINDOW_ALLOW_PICKING_FRACTIONAL_SIZES + /* Prevents adjustment in the scenario where we have explicitly + * selected a fractional window size that is slightly larger than + * the src size hint. If we allow picking without this check, we + * might end up growing the window to the next power of two. */ + if (ZSTD_windowSize(params) > (1u << (ZSTD_highbit32(tSize - 1) + 1))) +#endif + { + const U32 tmpMinWindowLog = ZSTD_HASHLOG_MIN < ZSTD_WINDOWLOG_MIN ? ZSTD_HASHLOG_MIN : ZSTD_WINDOWLOG_MIN; + ZSTD_setMinimalWindowLogAndFrac(params, tSize, tmpMinWindowLog); + } + } } if (srcSize != ZSTD_CONTENTSIZE_UNKNOWN) { - U32 const dictAndWindowLog = ZSTD_dictAndWindowLog(cPar.windowLog, (U64)srcSize, (U64)dictSize); - U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); - if (cPar.hashLog > dictAndWindowLog+1) cPar.hashLog = dictAndWindowLog+1; - if (cycleLog > dictAndWindowLog) - cPar.chainLog -= (cycleLog - dictAndWindowLog); + ZSTD_CCtx_params dictWindowParams = *params; + U32 const cycleLog = ZSTD_cycleLog(cPar->chainLog, cPar->strategy); + ZSTD_dictAndWindowLog(&dictWindowParams, (U64)srcSize, (U64)dictSize); + if (dictWindowParams.windowFrac != 0) { + /* Round up to a whole power of two. */ + dictWindowParams.cParams.windowLog++; + dictWindowParams.windowFrac = 0; + } + if (cPar->hashLog > dictWindowParams.cParams.windowLog+1) + cPar->hashLog = dictWindowParams.cParams.windowLog+1; + if (cycleLog > dictWindowParams.cParams.windowLog) + cPar->chainLog -= (cycleLog - dictWindowParams.cParams.windowLog); } - if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) - cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* minimum wlog required for valid frame header */ + if (cPar->windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) { + cPar->windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* minimum wlog required for valid frame header */ + params->windowFrac = 0; + } /* We can't use more than 32 bits of hash in total, so that means that we require: * (hashLog + 8) <= 32 && (chainLog + 8) <= 32 */ - if (mode == ZSTD_cpm_createCDict && ZSTD_CDictIndicesAreTagged(&cPar)) { + if (mode == ZSTD_cpm_createCDict && ZSTD_CDictIndicesAreTagged(cPar)) { U32 const maxShortCacheHashLog = 32 - ZSTD_SHORT_CACHE_TAG_BITS; - if (cPar.hashLog > maxShortCacheHashLog) { - cPar.hashLog = maxShortCacheHashLog; + if (cPar->hashLog > maxShortCacheHashLog) { + cPar->hashLog = maxShortCacheHashLog; } - if (cPar.chainLog > maxShortCacheHashLog) { - cPar.chainLog = maxShortCacheHashLog; + if (cPar->chainLog > maxShortCacheHashLog) { + cPar->chainLog = maxShortCacheHashLog; } } @@ -1594,18 +1669,16 @@ ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, /* We can't hash more than 32-bits in total. So that means that we require: * (hashLog - rowLog + 8) <= 32 */ - if (ZSTD_rowMatchFinderUsed(cPar.strategy, useRowMatchFinder)) { + if (ZSTD_rowMatchFinderUsed(cPar->strategy, useRowMatchFinder)) { /* Switch to 32-entry rows if searchLog is 5 (or more) */ - U32 const rowLog = BOUNDED(4, cPar.searchLog, 6); + U32 const rowLog = BOUNDED(4, cPar->searchLog, 6); U32 const maxRowHashLog = 32 - ZSTD_ROW_HASH_TAG_BITS; U32 const maxHashLog = maxRowHashLog + rowLog; - assert(cPar.hashLog >= rowLog); - if (cPar.hashLog > maxHashLog) { - cPar.hashLog = maxHashLog; + assert(cPar->hashLog >= rowLog); + if (cPar->hashLog > maxHashLog) { + cPar->hashLog = maxHashLog; } } - - return cPar; } ZSTD_compressionParameters @@ -1613,41 +1686,71 @@ ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize) { - cPar = ZSTD_clampCParams(cPar); /* resulting cPar is necessarily valid (all parameters within range) */ + ZSTD_CCtx_params params; + ZSTD_CCtxParams_init(¶ms, 0); + params.cParams = cPar; + ZSTD_clampCParams(¶ms); /* resulting cPar is necessarily valid (all parameters within range) */ if (srcSize == 0) srcSize = ZSTD_CONTENTSIZE_UNKNOWN; - return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize, ZSTD_cpm_unknown, ZSTD_ps_auto); -} - -static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_CParamMode_e mode); -static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_CParamMode_e mode); - -static void ZSTD_overrideCParams( - ZSTD_compressionParameters* cParams, - const ZSTD_compressionParameters* overrides) -{ - if (overrides->windowLog) cParams->windowLog = overrides->windowLog; - if (overrides->hashLog) cParams->hashLog = overrides->hashLog; - if (overrides->chainLog) cParams->chainLog = overrides->chainLog; - if (overrides->searchLog) cParams->searchLog = overrides->searchLog; - if (overrides->minMatch) cParams->minMatch = overrides->minMatch; - if (overrides->targetLength) cParams->targetLength = overrides->targetLength; - if (overrides->strategy) cParams->strategy = overrides->strategy; -} - -ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( - const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize, ZSTD_CParamMode_e mode) -{ - ZSTD_compressionParameters cParams; - if (srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN && CCtxParams->srcSizeHint > 0) { - assert(CCtxParams->srcSizeHint>=0); - srcSizeHint = (U64)CCtxParams->srcSizeHint; + ZSTD_adjustCParams_internal(¶ms, srcSize, dictSize, ZSTD_cpm_unknown, ZSTD_ps_auto); + return params.cParams; +} + +static ZSTD_CCtx_params ZSTD_getCCtxParams_internal( + int compressionLevel, + unsigned long long srcSizeHint, + size_t dictSize, + ZSTD_CParamMode_e mode); + +/* Prefer ZSTD_getCCtxParams_internal() unless you're sure you *only* need + * the CParams actually stored in the ZSTD_compressionParameters struct. + * (i.e., not the window size!) */ +static ZSTD_compressionParameters ZSTD_getCParams_internal( + int compressionLevel, + unsigned long long srcSizeHint, + size_t dictSize, + ZSTD_CParamMode_e mode); +static ZSTD_parameters ZSTD_getParams_internal( + int compressionLevel, + unsigned long long srcSizeHint, + size_t dictSize, ZSTD_CParamMode_e + mode); + +/* fills unset fields in `dst` with values from `defaults` */ +static void ZSTD_fillCParams( + ZSTD_CCtx_params* dst, + const ZSTD_CCtx_params* defaults) { + if (!dst->cParams.windowLog) { + dst->cParams.windowLog = defaults->cParams.windowLog; + /* windowFrac only has effect if windowLog is explicitly set */ + dst->windowFrac = defaults->windowFrac; + } + if (!dst->cParams.hashLog) dst->cParams.hashLog = defaults->cParams.hashLog; + if (!dst->cParams.chainLog) dst->cParams.chainLog = defaults->cParams.chainLog; + if (!dst->cParams.searchLog) dst->cParams.searchLog = defaults->cParams.searchLog; + if (!dst->cParams.minMatch) dst->cParams.minMatch = defaults->cParams.minMatch; + if (!dst->cParams.targetLength) dst->cParams.targetLength = defaults->cParams.targetLength; + if (!dst->cParams.strategy) dst->cParams.strategy = defaults->cParams.strategy; +} + +void ZSTD_fillCParamsInCCtxParams( + ZSTD_CCtx_params* params, U64 srcSizeHint, size_t dictSize, ZSTD_CParamMode_e mode) +{ + if (srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN && params->srcSizeHint > 0) { + assert(params->srcSizeHint>=0); + srcSizeHint = (U64)params->srcSizeHint; + } + { + ZSTD_CCtx_params tmpParams = ZSTD_getCCtxParams_internal(params->compressionLevel, srcSizeHint, dictSize, mode); + if (params->ldmParams.enableLdm == ZSTD_ps_enable) { + tmpParams.cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; + tmpParams.windowFrac = 0; + } + ZSTD_fillCParams(params, &tmpParams); + assert(!ZSTD_checkCCtxCParams_internal(params)); } - cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize, mode); - if (CCtxParams->ldmParams.enableLdm == ZSTD_ps_enable) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; - ZSTD_overrideCParams(&cParams, &CCtxParams->cParams); - assert(!ZSTD_checkCParams(cParams)); + /* srcSizeHint == 0 means 0 */ - return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize, mode, CCtxParams->useRowMatchFinder); + ZSTD_adjustCParams_internal(params, srcSizeHint, dictSize, mode, params->useRowMatchFinder); } static size_t @@ -1700,29 +1803,26 @@ static size_t ZSTD_maxNbSeq(size_t blockSize, unsigned minMatch, int useSequence } static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal( - const ZSTD_compressionParameters* cParams, - const ldmParams_t* ldmParams, + const ZSTD_CCtx_params* params, const int isStatic, - const ZSTD_ParamSwitch_e useRowMatchFinder, const size_t buffInSize, const size_t buffOutSize, - const U64 pledgedSrcSize, - int useSequenceProducer, - size_t maxBlockSize) + const U64 pledgedSrcSize) { - size_t const windowSize = (size_t) BOUNDED(1ULL, 1ULL << cParams->windowLog, pledgedSrcSize); - size_t const blockSize = MIN(ZSTD_resolveMaxBlockSize(maxBlockSize), windowSize); - size_t const maxNbSeq = ZSTD_maxNbSeq(blockSize, cParams->minMatch, useSequenceProducer); + int const useSequenceProducer = ZSTD_hasExtSeqProd(params); + size_t const windowSize = (size_t) BOUNDED(1ULL, ZSTD_windowSize(params), pledgedSrcSize); + size_t const blockSize = MIN(ZSTD_resolveMaxBlockSize(params->maxBlockSize), windowSize); + size_t const maxNbSeq = ZSTD_maxNbSeq(blockSize, params->cParams.minMatch, useSequenceProducer); size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize) + ZSTD_cwksp_aligned64_alloc_size(maxNbSeq * sizeof(SeqDef)) + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE)); size_t const tmpWorkSpace = ZSTD_cwksp_alloc_size(TMP_WORKSPACE_SIZE); size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t)); - size_t const matchStateSize = ZSTD_sizeof_matchState(cParams, useRowMatchFinder, /* enableDedicatedDictSearch */ 0, /* forCCtx */ 1); + size_t const matchStateSize = ZSTD_sizeof_matchState(¶ms->cParams, params->useRowMatchFinder, /* enableDedicatedDictSearch */ 0, /* forCCtx */ 1); - size_t const ldmSpace = ZSTD_ldm_getTableSize(*ldmParams); - size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(*ldmParams, blockSize); - size_t const ldmSeqSpace = ldmParams->enableLdm == ZSTD_ps_enable ? + size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams); + size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize); + size_t const ldmSeqSpace = params->ldmParams.enableLdm == ZSTD_ps_enable ? ZSTD_cwksp_aligned64_alloc_size(maxNbLdmSeq * sizeof(rawSeq)) : 0; @@ -1753,23 +1853,22 @@ static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal( size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params) { - ZSTD_compressionParameters const cParams = - ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); - ZSTD_ParamSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder, - &cParams); + ZSTD_CCtx_params par = *params; + ZSTD_fillCParamsInCCtxParams(&par, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); + par.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(par.useRowMatchFinder, &par.cParams); - RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); + RETURN_ERROR_IF(par.nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); /* estimateCCtxSize is for one-shot compression. So no buffers should * be needed. However, we still allocate two 0-sized buffers, which can * take space under ASAN. */ return ZSTD_estimateCCtxSize_usingCCtxParams_internal( - &cParams, ¶ms->ldmParams, 1, useRowMatchFinder, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN, ZSTD_hasExtSeqProd(params), params->maxBlockSize); + &par, 1, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN); } -size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams) +static size_t ZSTD_estimateCCtxSize_usingCCtxParamsCParams(const ZSTD_CCtx_params* params) { - ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams); - if (ZSTD_rowMatchFinderSupported(cParams.strategy)) { + ZSTD_CCtx_params initialParams = *params; + if (ZSTD_rowMatchFinderSupported(initialParams.cParams.strategy)) { /* Pick bigger of not using and using row-based matchfinder for greedy and lazy strategies */ size_t noRowCCtxSize; size_t rowCCtxSize; @@ -1783,6 +1882,12 @@ size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams) } } +size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams) +{ + ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams); + return ZSTD_estimateCCtxSize_usingCCtxParamsCParams(&initialParams); +} + static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel) { int tier = 0; @@ -1790,8 +1895,8 @@ static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel) static const unsigned long long srcSizeTiers[4] = {16 KB, 128 KB, 256 KB, ZSTD_CONTENTSIZE_UNKNOWN}; for (; tier < 4; ++tier) { /* Choose the set of cParams for a given level across all srcSizes that give the largest cctxSize */ - ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeTiers[tier], 0, ZSTD_cpm_noAttachDict); - largestSize = MAX(ZSTD_estimateCCtxSize_usingCParams(cParams), largestSize); + ZSTD_CCtx_params const params = ZSTD_getCCtxParams_internal(compressionLevel, srcSizeTiers[tier], 0, ZSTD_cpm_noAttachDict); + largestSize = MAX(ZSTD_estimateCCtxSize_usingCCtxParamsCParams(¶ms), largestSize); } return largestSize; } @@ -1810,28 +1915,30 @@ size_t ZSTD_estimateCCtxSize(int compressionLevel) size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params) { - RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); - { ZSTD_compressionParameters const cParams = - ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); - size_t const blockSize = MIN(ZSTD_resolveMaxBlockSize(params->maxBlockSize), (size_t)1 << cParams.windowLog); + ZSTD_CCtx_params par = *params; + RETURN_ERROR_IF(par.nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); + ZSTD_fillCParamsInCCtxParams(&par, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); + { + size_t const windowSize = ZSTD_windowSize(&par); + size_t const blockSize = MIN(ZSTD_resolveMaxBlockSize(params->maxBlockSize), windowSize); size_t const inBuffSize = (params->inBufferMode == ZSTD_bm_buffered) - ? ((size_t)1 << cParams.windowLog) + blockSize + ? windowSize + blockSize : 0; size_t const outBuffSize = (params->outBufferMode == ZSTD_bm_buffered) ? ZSTD_compressBound(blockSize) + 1 : 0; - ZSTD_ParamSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder, ¶ms->cParams); + par.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(par.useRowMatchFinder, &par.cParams); return ZSTD_estimateCCtxSize_usingCCtxParams_internal( - &cParams, ¶ms->ldmParams, 1, useRowMatchFinder, inBuffSize, outBuffSize, - ZSTD_CONTENTSIZE_UNKNOWN, ZSTD_hasExtSeqProd(params), params->maxBlockSize); + &par, 1, inBuffSize, outBuffSize, + ZSTD_CONTENTSIZE_UNKNOWN); } } -size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams) +static size_t ZSTD_estimateCStreamSize_usingCCtxParamsCParams(const ZSTD_CCtx_params* params) { - ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams); - if (ZSTD_rowMatchFinderSupported(cParams.strategy)) { + ZSTD_CCtx_params initialParams = *params; + if (ZSTD_rowMatchFinderSupported(initialParams.cParams.strategy)) { /* Pick bigger of not using and using row-based matchfinder for greedy and lazy strategies */ size_t noRowCCtxSize; size_t rowCCtxSize; @@ -1845,10 +1952,16 @@ size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams) } } +size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams) +{ + ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams); + return ZSTD_estimateCStreamSize_usingCCtxParamsCParams(&initialParams); +} + static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel) { - ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); - return ZSTD_estimateCStreamSize_usingCParams(cParams); + ZSTD_CCtx_params params = ZSTD_getCCtxParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); + return ZSTD_estimateCStreamSize_usingCCtxParamsCParams(¶ms); } size_t ZSTD_estimateCStreamSize(int compressionLevel) @@ -1984,12 +2097,12 @@ static void ZSTD_advanceHashSalt(ZSTD_MatchState_t* ms) { static size_t ZSTD_reset_matchState(ZSTD_MatchState_t* ms, ZSTD_cwksp* ws, - const ZSTD_compressionParameters* cParams, - const ZSTD_ParamSwitch_e useRowMatchFinder, const ZSTD_compResetPolicy_e crp, const ZSTD_indexResetPolicy_e forceResetIndex, const ZSTD_resetTarget_e forWho) { + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; + const ZSTD_ParamSwitch_e useRowMatchFinder = ms->cctxParams->useRowMatchFinder; /* disable chain table allocation for fast or row-based strategies */ size_t const chainSize = ZSTD_allocateChainTable(cParams->strategy, useRowMatchFinder, ms->dedicatedDictSearch && (forWho == ZSTD_resetTarget_CDict)) @@ -2061,8 +2174,6 @@ ZSTD_reset_matchState(ZSTD_MatchState_t* ms, ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned64(ws, ZSTD_OPT_SIZE * sizeof(ZSTD_optimal_t)); } - ms->cParams = *cParams; - RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation, "failed a workspace allocation in ZSTD_reset_matchState"); return 0; @@ -2107,7 +2218,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, ZSTD_cwksp* const ws = &zc->workspace; DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u, useRowMatchFinder=%d useBlockSplitter=%d", (U32)pledgedSrcSize, params->cParams.windowLog, (int)params->useRowMatchFinder, (int)params->postBlockSplitter); - assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); + assert(!ZSTD_isError(ZSTD_checkCCtxCParams_internal(params))); zc->isFirstBlock = 1; @@ -2123,12 +2234,12 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, assert(params->maxBlockSize != 0); if (params->ldmParams.enableLdm == ZSTD_ps_enable) { /* Adjust long distance matching parameters */ - ZSTD_ldm_adjustParameters(&zc->appliedParams.ldmParams, ¶ms->cParams); + ZSTD_ldm_adjustParameters(&zc->appliedParams.ldmParams, params); assert(params->ldmParams.hashLog >= params->ldmParams.bucketSizeLog); assert(params->ldmParams.hashRateLog < 32); } - { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params->cParams.windowLog), pledgedSrcSize)); + { size_t const windowSize = MAX(1, (size_t)MIN(ZSTD_windowSize(params), pledgedSrcSize)); size_t const blockSize = MIN(params->maxBlockSize, windowSize); size_t const maxNbSeq = ZSTD_maxNbSeq(blockSize, params->cParams.minMatch, ZSTD_hasExtSeqProd(params)); size_t const buffOutSize = (zbuff == ZSTDb_buffered && params->outBufferMode == ZSTD_bm_buffered) @@ -2146,8 +2257,8 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, size_t const neededSpace = ZSTD_estimateCCtxSize_usingCCtxParams_internal( - ¶ms->cParams, ¶ms->ldmParams, zc->staticSize != 0, params->useRowMatchFinder, - buffInSize, buffOutSize, pledgedSrcSize, ZSTD_hasExtSeqProd(params), params->maxBlockSize); + params, zc->staticSize != 0, + buffInSize, buffOutSize, pledgedSrcSize); FORWARD_IF_ERROR(neededSpace, "cctx size estimate failed!"); @@ -2189,7 +2300,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, ZSTD_cwksp_clear(ws); /* init params */ - zc->blockState.matchState.cParams = params->cParams; + zc->blockState.matchState.cctxParams = params; zc->blockState.matchState.prefetchCDictTables = params->prefetchCDictTables == ZSTD_ps_enable; zc->pledgedSrcSizePlusOne = pledgedSrcSize+1; zc->consumedSrcSize = 0; @@ -2210,8 +2321,6 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, FORWARD_IF_ERROR(ZSTD_reset_matchState( &zc->blockState.matchState, ws, - ¶ms->cParams, - params->useRowMatchFinder, crp, needsIndexReset, ZSTD_resetTarget_CCtx), ""); @@ -2310,7 +2419,7 @@ static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict, const ZSTD_CCtx_params* params, U64 pledgedSrcSize) { - size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy]; + size_t cutoff = attachDictSizeCutoffs[cdict->params.cParams.strategy]; int const dedicatedDictSearch = cdict->matchState.dedicatedDictSearch; return dedicatedDictSearch || ( ( pledgedSrcSize <= cutoff @@ -2331,26 +2440,29 @@ ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx, DEBUGLOG(4, "ZSTD_resetCCtx_byAttachingCDict() pledgedSrcSize=%llu", (unsigned long long)pledgedSrcSize); { - ZSTD_compressionParameters adjusted_cdict_cParams = cdict->matchState.cParams; + ZSTD_CCtx_params adjusted_cdict_params = cdict->params; unsigned const windowLog = params.cParams.windowLog; + unsigned const windowFrac = params.windowFrac; assert(windowLog != 0); /* Resize working context table params for input only, since the dict * has its own tables. */ /* pledgedSrcSize == 0 means 0! */ if (cdict->matchState.dedicatedDictSearch) { - ZSTD_dedicatedDictSearch_revertCParams(&adjusted_cdict_cParams); + ZSTD_dedicatedDictSearch_revertCParams(&adjusted_cdict_params.cParams); } - params.cParams = ZSTD_adjustCParams_internal(adjusted_cdict_cParams, pledgedSrcSize, - cdict->dictContentSize, ZSTD_cpm_attachDict, - params.useRowMatchFinder); - params.cParams.windowLog = windowLog; - params.useRowMatchFinder = cdict->useRowMatchFinder; /* cdict overrides */ + ZSTD_adjustCParams_internal(&adjusted_cdict_params, pledgedSrcSize, + cdict->dictContentSize, ZSTD_cpm_attachDict, + params.useRowMatchFinder); + params.cParams = adjusted_cdict_params.cParams; + params.cParams.windowLog = windowLog; + params.windowFrac = windowFrac; + params.useRowMatchFinder = cdict->params.useRowMatchFinder; /* cdict overrides */ FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, ¶ms, pledgedSrcSize, /* loadedDictSize */ 0, ZSTDcrp_makeClean, zbuff), ""); - assert(cctx->appliedParams.cParams.strategy == adjusted_cdict_cParams.strategy); + assert(cctx->appliedParams.cParams.strategy == adjusted_cdict_params.cParams.strategy); } { const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc @@ -2405,18 +2517,20 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, U64 pledgedSrcSize, ZSTD_buffered_policy_e zbuff) { - const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams; + const ZSTD_compressionParameters *cdict_cParams = &cdict->params.cParams; assert(!cdict->matchState.dedicatedDictSearch); DEBUGLOG(4, "ZSTD_resetCCtx_byCopyingCDict() pledgedSrcSize=%llu", (unsigned long long)pledgedSrcSize); - { unsigned const windowLog = params.cParams.windowLog; + { unsigned const windowLog = params.cParams.windowLog; + unsigned const windowFrac = params.windowFrac; assert(windowLog != 0); /* Copy only compression parameters related to tables. */ params.cParams = *cdict_cParams; - params.cParams.windowLog = windowLog; - params.useRowMatchFinder = cdict->useRowMatchFinder; + params.cParams.windowLog = windowLog; + params.windowFrac = windowFrac; + params.useRowMatchFinder = cdict->params.useRowMatchFinder; FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, ¶ms, pledgedSrcSize, /* loadedDictSize */ 0, ZSTDcrp_leaveDirty, zbuff), ""); @@ -2429,7 +2543,7 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, assert(params.useRowMatchFinder != ZSTD_ps_auto); /* copy tables */ - { size_t const chainSize = ZSTD_allocateChainTable(cdict_cParams->strategy, cdict->useRowMatchFinder, 0 /* DDS guaranteed disabled */) + { size_t const chainSize = ZSTD_allocateChainTable(cdict_cParams->strategy, cdict->params.useRowMatchFinder, 0 /* DDS guaranteed disabled */) ? ((size_t)1 << cdict_cParams->chainLog) : 0; size_t const hSize = (size_t)1 << cdict_cParams->hashLog; @@ -2445,7 +2559,7 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, chainSize, cdict_cParams); } /* copy tag table */ - if (ZSTD_rowMatchFinderUsed(cdict_cParams->strategy, cdict->useRowMatchFinder)) { + if (ZSTD_rowMatchFinderUsed(cdict_cParams->strategy, cdict->params.useRowMatchFinder)) { size_t const tagTableSize = hSize; ZSTD_memcpy(cctx->blockState.matchState.tagTable, cdict->matchState.tagTable, @@ -2523,6 +2637,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, { ZSTD_CCtx_params params = dstCCtx->requestedParams; /* Copy only compression parameters related to tables. */ params.cParams = srcCCtx->appliedParams.cParams; + params.windowFrac = srcCCtx->appliedParams.windowFrac; assert(srcCCtx->appliedParams.useRowMatchFinder != ZSTD_ps_auto); assert(srcCCtx->appliedParams.postBlockSplitter != ZSTD_ps_auto); assert(srcCCtx->appliedParams.ldmParams.enableLdm != ZSTD_ps_auto); @@ -2535,6 +2650,7 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, /* loadedDictSize */ 0, ZSTDcrp_leaveDirty, zbuff); assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog); + assert(dstCCtx->appliedParams.windowFrac == srcCCtx->appliedParams.windowFrac); assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy); assert(dstCCtx->appliedParams.cParams.hashLog == srcCCtx->appliedParams.cParams.hashLog); assert(dstCCtx->appliedParams.cParams.chainLog == srcCCtx->appliedParams.cParams.chainLog); @@ -3266,8 +3382,7 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) ZSTD_MatchState_t* const ms = &zc->blockState.matchState; DEBUGLOG(5, "ZSTD_buildSeqStore (srcSize=%zu)", srcSize); assert(srcSize <= ZSTD_BLOCKSIZE_MAX); - /* Assert that we have correctly flushed the ctx params into the ms's copy */ - ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams); + assert(&zc->appliedParams == ms->cctxParams); /* TODO: See 3090. We reduced MIN_CBLOCK_SIZE from 3 to 2 so to compensate we are adding * additional 1. We need to revisit and change this logic to be more consistent */ if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1+1) { @@ -3354,7 +3469,7 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) ); assert(zc->appliedParams.extSeqProdFunc != NULL); - { U32 const windowSize = (U32)1 << zc->appliedParams.cParams.windowLog; + { U32 const windowSize = ZSTD_windowSize(&zc->appliedParams); size_t const nbExternalSeqs = (zc->appliedParams.extSeqProdFunc)( zc->appliedParams.extSeqProdState, @@ -4530,7 +4645,7 @@ static void ZSTD_overflowCorrectIfNeeded(ZSTD_MatchState_t* ms, void const* iend) { U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy); - U32 const maxDist = (U32)1 << params->cParams.windowLog; + U32 const maxDist = ZSTD_windowSize(params); if (ZSTD_window_needOverflowCorrection(ms->window, cycleLog, maxDist, ms->loadedDictEnd, ip, iend)) { U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip); ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); @@ -4598,10 +4713,10 @@ static size_t ZSTD_compress_frameChunk(ZSTD_CCtx* cctx, const BYTE* ip = (const BYTE*)src; BYTE* const ostart = (BYTE*)dst; BYTE* op = ostart; - U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog; + U32 const maxDist = ZSTD_windowSize(&cctx->appliedParams); S64 savings = (S64)cctx->consumedSrcSize - (S64)cctx->producedCSize; - assert(cctx->appliedParams.cParams.windowLog <= ZSTD_WINDOWLOG_MAX); + assert(cctx->appliedParams.cParams.windowLog + !!cctx->appliedParams.windowFrac <= ZSTD_WINDOWLOG_MAX); DEBUGLOG(5, "ZSTD_compress_frameChunk (srcSize=%u, blockSizeMax=%u)", (unsigned)srcSize, (unsigned)blockSizeMax); if (cctx->appliedParams.fParams.checksumFlag && srcSize) @@ -4700,9 +4815,9 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */ U32 const dictIDSizeCode = params->fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */ U32 const checksumFlag = params->fParams.checksumFlag>0; - U32 const windowSize = (U32)1 << params->cParams.windowLog; + U32 const windowSize = ZSTD_windowSize(params); U32 const singleSegment = params->fParams.contentSizeFlag && (windowSize >= pledgedSrcSize); - BYTE const windowLogByte = (BYTE)((params->cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3); + BYTE const windowByte = (BYTE)(((params->cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3) | (params->windowFrac & 7)); U32 const fcsCode = params->fParams.contentSizeFlag ? (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */ BYTE const frameHeaderDescriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) ); @@ -4718,7 +4833,7 @@ static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, pos = 4; } op[pos++] = frameHeaderDescriptionByte; - if (!singleSegment) op[pos++] = windowLogByte; + if (!singleSegment) op[pos++] = windowByte; switch(dictIDSizeCode) { default: @@ -4868,9 +4983,8 @@ size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, static size_t ZSTD_getBlockSize_deprecated(const ZSTD_CCtx* cctx) { - ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams; - assert(!ZSTD_checkCParams(cParams)); - return MIN(cctx->appliedParams.maxBlockSize, (size_t)1 << cParams.windowLog); + assert(!ZSTD_checkCCtxCParams_internal(&cctx->appliedParams)); + return MIN(cctx->appliedParams.maxBlockSize, (size_t)ZSTD_windowSize(&cctx->appliedParams)); } /* NOTE: Must just wrap ZSTD_getBlockSize_deprecated() */ @@ -4879,7 +4993,6 @@ size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) return ZSTD_getBlockSize_deprecated(cctx); } -/* NOTE: Must just wrap ZSTD_compressBlock_deprecated() */ size_t ZSTD_compressBlock_deprecated(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { DEBUGLOG(5, "ZSTD_compressBlock: srcSize = %u", (unsigned)srcSize); @@ -4912,7 +5025,7 @@ ZSTD_loadDictionaryContent(ZSTD_MatchState_t* ms, int const loadLdmDict = params->ldmParams.enableLdm == ZSTD_ps_enable && ls != NULL; /* Assert that the ms params match the params we're being given */ - ZSTD_assertEqualCParams(params->cParams, ms->cParams); + ZSTD_assertEqualCParams(params->cParams, ms->cctxParams->cParams); { /* Ensure large dictionaries can't cause index overflow */ @@ -5249,14 +5362,14 @@ static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, #endif DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params->cParams.windowLog); /* params are supposed to be fully validated at this point */ - assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); + assert(!ZSTD_isError(ZSTD_checkCCtxCParams_internal(params))); assert(!((dict) && (cdict))); /* either dict or cdict, not both */ if ( (cdict) && (cdict->dictContentSize > 0) && ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN - || cdict->compressionLevel == 0) + || cdict->params.compressionLevel == 0) && (params->attachDictPref != ZSTD_dictForceLoad) ) { return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff); } @@ -5292,7 +5405,7 @@ size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx, { DEBUGLOG(4, "ZSTD_compressBegin_advanced_internal: wlog=%u", params->cParams.windowLog); /* compression parameters verification and optimization */ - FORWARD_IF_ERROR( ZSTD_checkCParams(params->cParams) , ""); + FORWARD_IF_ERROR( ZSTD_checkCCtxCParams_internal(params) , ""); return ZSTD_compressBegin_internal(cctx, dict, dictSize, dictContentType, dtlm, cdict, @@ -5304,7 +5417,8 @@ size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx, * @return : 0, or an error code */ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, - ZSTD_parameters params, unsigned long long pledgedSrcSize) + ZSTD_parameters params, + unsigned long long pledgedSrcSize) { ZSTD_CCtx_params cctxParams; ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, ZSTD_NO_CLEVEL); @@ -5318,8 +5432,8 @@ static size_t ZSTD_compressBegin_usingDict_deprecated(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) { ZSTD_CCtx_params cctxParams; - { ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_noAttachDict); - ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel); + { ZSTD_CCtx_params const tmpParams = ZSTD_getCCtxParams_internal((compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_noAttachDict); + ZSTD_CCtxParams_init_fromCCtxParams(&cctxParams, &tmpParams); } DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize); return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, @@ -5476,9 +5590,9 @@ size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, int compressionLevel) { { - ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0, ZSTD_cpm_noAttachDict); - assert(params.fParams.contentSizeFlag == 1); - ZSTD_CCtxParams_init_internal(&cctx->simpleApiParams, ¶ms, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT: compressionLevel); + ZSTD_CCtx_params const tmpParams = ZSTD_getCCtxParams_internal((compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel, srcSize, dict ? dictSize : 0, ZSTD_cpm_noAttachDict); + assert(tmpParams.fParams.contentSizeFlag == 1); + ZSTD_CCtxParams_init_fromCCtxParams(&cctx->simpleApiParams, &tmpParams); } DEBUGLOG(4, "ZSTD_compress_usingDict (srcSize=%u)", (unsigned)srcSize); return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctx->simpleApiParams); @@ -5535,8 +5649,8 @@ size_t ZSTD_estimateCDictSize_advanced( size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel) { - ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); - return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); + ZSTD_CCtx_params const params = ZSTD_getCCtxParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); + return ZSTD_estimateCDictSize_advanced(dictSize, params.cParams, ZSTD_dlm_byCopy); } size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict) @@ -5556,8 +5670,10 @@ static size_t ZSTD_initCDict_internal( ZSTD_CCtx_params params) { DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType); - assert(!ZSTD_checkCParams(params.cParams)); - cdict->matchState.cParams = params.cParams; + + assert(!ZSTD_checkCCtxCParams_internal(¶ms)); + cdict->params = params; + cdict->matchState.cctxParams = &cdict->params; cdict->matchState.dedicatedDictSearch = params.enableDedicatedDictSearch; if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) { cdict->dictContent = dictBuffer; @@ -5578,8 +5694,6 @@ static size_t ZSTD_initCDict_internal( FORWARD_IF_ERROR(ZSTD_reset_matchState( &cdict->matchState, &cdict->workspace, - ¶ms.cParams, - params.useRowMatchFinder, ZSTDcrp_makeClean, ZSTDirp_reset, ZSTD_resetTarget_CDict), ""); @@ -5633,8 +5747,8 @@ ZSTD_createCDict_advanced_internal(size_t dictSize, assert(cdict != NULL); ZSTD_cwksp_move(&cdict->workspace, &ws); cdict->customMem = customMem; - cdict->compressionLevel = ZSTD_NO_CLEVEL; /* signals advanced API usage */ - cdict->useRowMatchFinder = useRowMatchFinder; + cdict->params.compressionLevel = ZSTD_NO_CLEVEL; /* signals advanced API usage */ + cdict->params.useRowMatchFinder = useRowMatchFinder; return cdict; } } @@ -5665,31 +5779,30 @@ ZSTD_CDict* ZSTD_createCDict_advanced2( ZSTD_customMem customMem) { ZSTD_CCtx_params cctxParams = *originalCctxParams; - ZSTD_compressionParameters cParams; ZSTD_CDict* cdict; DEBUGLOG(3, "ZSTD_createCDict_advanced2, dictSize=%u, mode=%u", (unsigned)dictSize, (unsigned)dictContentType); if (!customMem.customAlloc ^ !customMem.customFree) return NULL; if (cctxParams.enableDedicatedDictSearch) { - cParams = ZSTD_dedicatedDictSearch_getCParams( + ZSTD_CCtx_params tmpParams = ZSTD_dedicatedDictSearch_getCParams( cctxParams.compressionLevel, dictSize); - ZSTD_overrideCParams(&cParams, &cctxParams.cParams); + ZSTD_fillCParams(&cctxParams, &tmpParams); } else { - cParams = ZSTD_getCParamsFromCCtxParams( + ZSTD_fillCParamsInCCtxParams( &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); } - if (!ZSTD_dedicatedDictSearch_isSupported(&cParams)) { + if (!ZSTD_dedicatedDictSearch_isSupported(&cctxParams.cParams)) { /* Fall back to non-DDSS params */ + cctxParams = *originalCctxParams; cctxParams.enableDedicatedDictSearch = 0; - cParams = ZSTD_getCParamsFromCCtxParams( + ZSTD_fillCParamsInCCtxParams( &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); } DEBUGLOG(3, "ZSTD_createCDict_advanced2: DedicatedDictSearch=%u", cctxParams.enableDedicatedDictSearch); - cctxParams.cParams = cParams; - cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cParams); + cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cctxParams.cParams); cdict = ZSTD_createCDict_advanced_internal(dictSize, dictLoadMethod, cctxParams.cParams, @@ -5709,23 +5822,25 @@ ZSTD_CDict* ZSTD_createCDict_advanced2( ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); - ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize, - ZSTD_dlm_byCopy, ZSTD_dct_auto, - cParams, ZSTD_defaultCMem); + ZSTD_CCtx_params params = ZSTD_getCCtxParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); + ZSTD_CDict* const cdict = ZSTD_createCDict_advanced2( + dict, dictSize, + ZSTD_dlm_byCopy, ZSTD_dct_auto, + ¶ms, ZSTD_defaultCMem); if (cdict) - cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel; + cdict->params.compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel; return cdict; } ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); - ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize, - ZSTD_dlm_byRef, ZSTD_dct_auto, - cParams, ZSTD_defaultCMem); + ZSTD_CCtx_params params = ZSTD_getCCtxParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); + ZSTD_CDict* const cdict = ZSTD_createCDict_advanced2( + dict, dictSize, + ZSTD_dlm_byRef, ZSTD_dct_auto, + ¶ms, ZSTD_defaultCMem); if (cdict) - cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel; + cdict->params.compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel; return cdict; } @@ -5789,8 +5904,7 @@ const ZSTD_CDict* ZSTD_initStaticCDict( ZSTD_CCtxParams_init(¶ms, 0); params.cParams = cParams; params.useRowMatchFinder = useRowMatchFinder; - cdict->useRowMatchFinder = useRowMatchFinder; - cdict->compressionLevel = ZSTD_NO_CLEVEL; + params.compressionLevel = ZSTD_NO_CLEVEL; if (ZSTD_isError( ZSTD_initCDict_internal(cdict, dict, dictSize, @@ -5804,7 +5918,7 @@ const ZSTD_CDict* ZSTD_initStaticCDict( ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) { assert(cdict != NULL); - return cdict->matchState.cParams; + return cdict->params.cParams; } /*! ZSTD_getDictID_fromCDict() : @@ -5829,17 +5943,20 @@ static size_t ZSTD_compressBegin_usingCDict_internal( RETURN_ERROR_IF(cdict==NULL, dictionary_wrong, "NULL pointer!"); /* Initialize the cctxParams from the cdict */ { - ZSTD_parameters params; - params.fParams = fParams; - params.cParams = ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF + if ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN - || cdict->compressionLevel == 0 ) ? - ZSTD_getCParamsFromCDict(cdict) - : ZSTD_getCParams(cdict->compressionLevel, - pledgedSrcSize, - cdict->dictContentSize); - ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, cdict->compressionLevel); + || cdict->params.compressionLevel == 0 ) { + ZSTD_CCtxParams_init_fromCCtxParams(&cctxParams, &cdict->params); + } else { + ZSTD_CCtx_params tmpParams = ZSTD_getCCtxParams_internal( + cdict->params.compressionLevel, + pledgedSrcSize, + cdict->dictContentSize, + ZSTD_cpm_unknown); + ZSTD_CCtxParams_init_fromCCtxParams(&cctxParams, &tmpParams); + } + cctxParams.fParams = fParams; } /* Increase window log to fit the entire dictionary and source if the * source size is known. Limit the increase to 19, which is the @@ -5847,8 +5964,9 @@ static size_t ZSTD_compressBegin_usingCDict_internal( */ if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) { U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19); - U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1; - cctxParams.cParams.windowLog = MAX(cctxParams.cParams.windowLog, limitedSrcLog); + if (limitedSrcSize > 1 && ZSTD_windowSize(&cctxParams) < limitedSrcSize) { + ZSTD_setMinimalWindowLogAndFrac(&cctxParams, limitedSrcSize, ZSTD_WINDOWLOG_MIN); + } } return ZSTD_compressBegin_internal(cctx, NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, @@ -5991,7 +6109,7 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, DEBUGLOG(4, "ZSTD_initCStream_internal"); FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); - assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); + assert(!ZSTD_isError(ZSTD_checkCCtxCParams_internal(params))); zcs->requestedParams = *params; assert(!((dict) && (cdict))); /* either dict or cdict, not both */ if (dict) { @@ -6360,16 +6478,17 @@ static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx, * But do not take the cdict's compression level if the "cdict" is actually a localDict * generated from ZSTD_initLocalDict(). */ - params.compressionLevel = cctx->cdict->compressionLevel; + params.compressionLevel = cctx->cdict->params.compressionLevel; } DEBUGLOG(4, "ZSTD_CCtx_init_compressStream2 : transparent init stage"); if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = inSize + 1; /* auto-determine pledgedSrcSize */ - { size_t const dictSize = prefixDict.dict + { + size_t const dictSize = prefixDict.dict ? prefixDict.dictSize : (cctx->cdict ? cctx->cdict->dictContentSize : 0); ZSTD_CParamMode_e const mode = ZSTD_getCParamMode(cctx->cdict, ¶ms, cctx->pledgedSrcSizePlusOne - 1); - params.cParams = ZSTD_getCParamsFromCCtxParams( + ZSTD_fillCParamsInCCtxParams( ¶ms, cctx->pledgedSrcSizePlusOne-1, dictSize, mode); } @@ -6418,7 +6537,7 @@ static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx, } else #endif /* ZSTD_MULTITHREAD */ { U64 const pledgedSrcSize = cctx->pledgedSrcSizePlusOne - 1; - assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); + assert(!ZSTD_isError(ZSTD_checkCCtxCParams_internal(¶ms))); FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, ZSTD_dtlm_fast, cctx->cdict, @@ -6601,17 +6720,18 @@ size_t ZSTD_compress2(ZSTD_CCtx* cctx, * @returns a ZSTD error code if sequence is not valid */ static size_t -ZSTD_validateSequence(U32 offBase, U32 matchLength, U32 minMatch, - size_t posInSrc, U32 windowLog, size_t dictSize, int useSequenceProducer) +ZSTD_validateSequence( + U32 offBase, U32 matchLength, const ZSTD_CCtx_params* params, + size_t posInSrc, size_t dictSize, int useSequenceProducer) { - U32 const windowSize = 1u << windowLog; + U32 const windowSize = ZSTD_windowSize(params); /* posInSrc represents the amount of data the decoder would decode up to this point. * As long as the amount of data decoded is less than or equal to window size, offsets may be * larger than the total length of output decoded in order to reference the dict, even larger than * window size. After output surpasses windowSize, we're limited to windowSize offsets again. */ size_t const offsetBound = posInSrc > windowSize ? (size_t)windowSize : posInSrc + (size_t)dictSize; - size_t const matchLenLowerBound = (minMatch == 3 || useSequenceProducer) ? 3 : 4; + size_t const matchLenLowerBound = (params->cParams.minMatch == 3 || useSequenceProducer) ? 3 : 4; RETURN_ERROR_IF(offBase > OFFSET_TO_OFFBASE(offsetBound), externalSequences_invalid, "Offset too large!"); /* Validate maxNbSeq is large enough for the given matchLength and minMatch */ RETURN_ERROR_IF(matchLength < matchLenLowerBound, externalSequences_invalid, "Matchlength too small for the minMatch"); @@ -6681,11 +6801,10 @@ ZSTD_transferSequences_wBlockDelim(ZSTD_CCtx* cctx, DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength); if (cctx->appliedParams.validateSequences) { seqPos->posInSrc += litLength + matchLength; - FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, cctx->appliedParams.cParams.minMatch, - seqPos->posInSrc, - cctx->appliedParams.cParams.windowLog, dictSize, - ZSTD_hasExtSeqProd(&cctx->appliedParams)), - "Sequence validation failed"); + FORWARD_IF_ERROR(ZSTD_validateSequence( + offBase, matchLength, &cctx->appliedParams, + seqPos->posInSrc, dictSize, ZSTD_hasExtSeqProd(&cctx->appliedParams)), + "Sequence validation failed"); } RETURN_ERROR_IF(idx - seqPos->idx >= cctx->seqStore.maxNbSeq, externalSequences_invalid, "Not enough memory allocated. Try adjusting ZSTD_c_minMatch."); @@ -6836,9 +6955,10 @@ ZSTD_transferSequences_noDelim(ZSTD_CCtx* cctx, if (cctx->appliedParams.validateSequences) { seqPos->posInSrc += litLength + matchLength; - FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, cctx->appliedParams.cParams.minMatch, seqPos->posInSrc, - cctx->appliedParams.cParams.windowLog, dictSize, ZSTD_hasExtSeqProd(&cctx->appliedParams)), - "Sequence validation failed"); + FORWARD_IF_ERROR(ZSTD_validateSequence( + offBase, matchLength, &cctx->appliedParams, + seqPos->posInSrc, dictSize, ZSTD_hasExtSeqProd(&cctx->appliedParams)), + "Sequence validation failed"); } DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength); RETURN_ERROR_IF(idx - seqPos->idx >= cctx->seqStore.maxNbSeq, externalSequences_invalid, @@ -7674,17 +7794,17 @@ int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; } int ZSTD_defaultCLevel(void) { return ZSTD_CLEVEL_DEFAULT; } -static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams(int const compressionLevel, size_t const dictSize) +static ZSTD_CCtx_params ZSTD_dedicatedDictSearch_getCParams(int const compressionLevel, size_t const dictSize) { - ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, 0, dictSize, ZSTD_cpm_createCDict); - switch (cParams.strategy) { + ZSTD_CCtx_params params = ZSTD_getCCtxParams_internal(compressionLevel, 0, dictSize, ZSTD_cpm_createCDict); + switch (params.cParams.strategy) { case ZSTD_fast: case ZSTD_dfast: break; case ZSTD_greedy: case ZSTD_lazy: case ZSTD_lazy2: - cParams.hashLog += ZSTD_LAZY_DDSS_BUCKET_LOG; + params.cParams.hashLog += ZSTD_LAZY_DDSS_BUCKET_LOG; break; case ZSTD_btlazy2: case ZSTD_btopt: @@ -7692,7 +7812,7 @@ static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams(int const case ZSTD_btultra2: break; } - return cParams; + return params; } static int ZSTD_dedicatedDictSearch_isSupported( @@ -7751,17 +7871,23 @@ static U64 ZSTD_getCParamRowSize(U64 srcSizeHint, size_t dictSize, ZSTD_CParamMo } } -/*! ZSTD_getCParams_internal() : - * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize. +/*! ZSTD_getCCtxParams_internal() : + * @return a ZSTD_CCtx_params with the ZSTD_compressionParameters structure + * (and select other fields) populated for the selected compression level, + * srcSize and dictSize. * Note: srcSizeHint 0 means 0, use ZSTD_CONTENTSIZE_UNKNOWN for unknown. * Use dictSize == 0 for unknown or unused. * Note: `mode` controls how we treat the `dictSize`. See docs for `ZSTD_CParamMode_e`. */ -static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_CParamMode_e mode) +static ZSTD_CCtx_params ZSTD_getCCtxParams_internal( + int compressionLevel, + unsigned long long srcSizeHint, + size_t dictSize, + ZSTD_CParamMode_e mode) { U64 const rSize = ZSTD_getCParamRowSize(srcSizeHint, dictSize, mode); U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); int row; - DEBUGLOG(5, "ZSTD_getCParams_internal (cLevel=%i)", compressionLevel); + DEBUGLOG(5, "ZSTD_getCCtxParams_internal (cLevel=%i)", compressionLevel); /* row */ if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT; /* 0 == default */ @@ -7769,18 +7895,31 @@ static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, else if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL; else row = compressionLevel; - { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row]; - DEBUGLOG(5, "ZSTD_getCParams_internal selected tableID: %u row: %u strat: %u", tableID, row, (U32)cp.strategy); + { ZSTD_CCtx_params params; + ZSTD_CCtxParams_init(¶ms, compressionLevel); + params.cParams = ZSTD_defaultCParameters[tableID][row]; + DEBUGLOG(5, "ZSTD_getCCtxParams_internal selected tableID: %u row: %u strat: %u", tableID, row, (U32)params.cParams.strategy); /* acceleration factor */ if (compressionLevel < 0) { int const clampedCompressionLevel = MAX(ZSTD_minCLevel(), compressionLevel); - cp.targetLength = (unsigned)(-clampedCompressionLevel); + params.cParams.targetLength = (unsigned)(-clampedCompressionLevel); } /* refine parameters based on srcSize & dictSize */ - return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize, mode, ZSTD_ps_auto); + ZSTD_adjustCParams_internal(¶ms, srcSizeHint, dictSize, mode, ZSTD_ps_auto); + return params; } } +static ZSTD_compressionParameters ZSTD_getCParams_internal( + int compressionLevel, + unsigned long long srcSizeHint, + size_t dictSize, + ZSTD_CParamMode_e mode) +{ + ZSTD_CCtx_params const params = ZSTD_getCCtxParams_internal(compressionLevel, srcSizeHint, dictSize, mode); + return params.cParams; +} + /*! ZSTD_getCParams() : * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize. * Size values are optional, provide 0 if not known or unused */ @@ -7790,7 +7929,7 @@ ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long l return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown); } -/*! ZSTD_getParams() : +/*! ZSTD_getParams_internal() : * same idea as ZSTD_getCParams() * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`). * Fields of `ZSTD_frameParameters` are set to default values */ @@ -7798,10 +7937,9 @@ static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_CParamMode_e mode) { ZSTD_parameters params; - ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, mode); DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel); ZSTD_memset(¶ms, 0, sizeof(params)); - params.cParams = cParams; + params.cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, mode); params.fParams.contentSizeFlag = 1; return params; } diff --git a/lib/compress/zstd_compress_internal.h b/lib/compress/zstd_compress_internal.h index ca5e2a4c5bf..6c1c81fd108 100644 --- a/lib/compress/zstd_compress_internal.h +++ b/lib/compress/zstd_compress_internal.h @@ -298,7 +298,9 @@ struct ZSTD_MatchState_t { */ optState_t opt; /* optimal parser state */ const ZSTD_MatchState_t* dictMatchState; - ZSTD_compressionParameters cParams; + + const ZSTD_CCtx_params* cctxParams; + const RawSeqStore_t* ldmSeqStore; /* Controls prefetching in some dictMatchState matchfinders. @@ -348,8 +350,9 @@ typedef struct { U32 hashLog; /* Log size of hashTable */ U32 bucketSizeLog; /* Log bucket size for collision resolution, at most 8 */ U32 minMatchLength; /* Minimum match length */ - U32 hashRateLog; /* Log number of entries to skip */ + U32 hashRateLog; /* Log number of entries to skip */ U32 windowLog; /* Window log for the LDM */ + U32 windowFrac; /* Window log for the LDM */ } ldmParams_t; typedef struct { @@ -362,6 +365,7 @@ typedef struct { struct ZSTD_CCtx_params_s { ZSTD_format_e format; ZSTD_compressionParameters cParams; + unsigned windowFrac; /* Additional CParam controlling sub-power-of-two window sizing. */ ZSTD_frameParameters fParams; int compressionLevel; @@ -1077,6 +1081,88 @@ MEM_STATIC ZSTD_dictMode_e ZSTD_matchState_dictMode(const ZSTD_MatchState_t *ms) ZSTD_noDict; } +/** + * Fractional window sizes can always be picked by the user explicitly + * setting ZSTD_c_windowFrac. This macro controls whether, when Zstd is + * picking a window size itself, it is allowed to pick a non-power-of-two + * window size. + * + * For now, this defaults to false. + */ +#ifndef ZSTD_WINDOW_ALLOW_PICKING_FRACTIONAL_SIZES +#define ZSTD_WINDOW_ALLOW_PICKING_FRACTIONAL_SIZES 0 +#endif + +/** + * Return the window size described by the windowLog and windowFrac in the + * provided CParams. + */ +MEM_STATIC U32 ZSTD_windowSize(const ZSTD_CCtx_params* params) { + return (U32)(((8ull + params->windowFrac) << params->cParams.windowLog) >> 3); +} +MEM_STATIC U32 ZSTD_windowSizeLDM(const ldmParams_t* ldmParams) { + return (U32)(((8ull + ldmParams->windowFrac) << ldmParams->windowLog) >> 3); +} + +/** + * Checks that the selected windowSize satisfies the inequality + * `srcSize <= windowSize <= srcSize * margin`, in the range where the window + * isn't pressed up against one of the hard bounds, where `margin` is either + * 1.125 or 2, depending on whether we're allowed to pick fractional window + * sizes. + */ +MEM_STATIC int ZSTD_windowLogAndFracAreMinimal(const ZSTD_CCtx_params* params, const U32 srcSize) { + const U32 lowerBound = MIN(srcSize, 1u << ZSTD_WINDOWLOG_MAX); +#if ZSTD_WINDOW_ALLOW_PICKING_FRACTIONAL_SIZES + const U32 upperBound = MAX(lowerBound + (lowerBound >> 3), 1u << ZSTD_WINDOWLOG_ABSOLUTEMIN); +#else + const U32 upperBound = MAX(2 * lowerBound - 1, 1u << ZSTD_WINDOWLOG_ABSOLUTEMIN); +#endif + const U32 windowSize = ZSTD_windowSize(params); + if (windowSize < lowerBound) { + return 0; + } + if (windowSize > upperBound) { + return 0; + } + return 1; +} + +/** + * Calculates the minimum legal window log and fraction that contain the + * provided source size. + */ +MEM_STATIC void ZSTD_setMinimalWindowLogAndFrac(ZSTD_CCtx_params* params, const U32 srcSize, const U32 minWindowLog) { + const U32 minSize = 1u << minWindowLog; +#if ZSTD_WINDOW_ALLOW_PICKING_FRACTIONAL_SIZES + if (srcSize < minSize) { + params->cParams.windowLog = minWindowLog; + params->windowFrac = 0; + } else { + const U32 srcSizeMinusOne = srcSize - 1; + params->cParams.windowLog = ZSTD_highbit32(srcSizeMinusOne); + params->windowFrac = ((srcSizeMinusOne >> (params->cParams.windowLog - 3)) & 7) + 1; + if (params->windowFrac == 8) { + params->windowFrac = 0; + params->cParams.windowLog++; + } + } +#else + if (srcSize < minSize) { + params->cParams.windowLog = minWindowLog; + params->windowFrac = 0; + } else { + params->cParams.windowLog = ZSTD_highbit32(srcSize - 1) + 1; + params->windowFrac = 0; + } +#endif + if (params->cParams.windowLog + !!params->windowFrac > ZSTD_WINDOWLOG_MAX) { + params->cParams.windowLog = ZSTD_WINDOWLOG_MAX; + params->windowFrac = 0; + } + assert(ZSTD_windowLogAndFracAreMinimal(params, srcSize)); +} + /* Defining this macro to non-zero tells zstd to run the overflow correction * code much more frequently. This is very inefficient, and should only be * used for tests and fuzzers. @@ -1100,10 +1186,12 @@ MEM_STATIC U32 ZSTD_window_canOverflowCorrect(ZSTD_window_t const window, U32 loadedDictEnd, void const* src) { + /* overflow correction only handles power-of-two index moves. */ + U32 const roundedMaxDist = 1u << (ZSTD_highbit32(maxDist - 1) + 1); U32 const cycleSize = 1u << cycleLog; U32 const curr = (U32)((BYTE const*)src - window.base); U32 const minIndexToOverflowCorrect = cycleSize - + MAX(maxDist, cycleSize) + + MAX(roundedMaxDist, cycleSize) + ZSTD_WINDOW_START_INDEX; /* Adjust the min index to backoff the overflow correction frequency, @@ -1178,23 +1266,29 @@ U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog, * 3. (cctx->lowLimit + 1< 3<<29 + 1<base); U32 const currentCycle = curr & cycleMask; - /* Ensure newCurrent - maxDist >= ZSTD_WINDOW_START_INDEX. */ + /* Ensure newCurrent - roundedMaxDist >= ZSTD_WINDOW_START_INDEX. */ U32 const currentCycleCorrection = currentCycle < ZSTD_WINDOW_START_INDEX ? MAX(cycleSize, ZSTD_WINDOW_START_INDEX) : 0; U32 const newCurrent = currentCycle + currentCycleCorrection - + MAX(maxDist, cycleSize); + + MAX(roundedMaxDist, cycleSize); U32 const correction = curr - newCurrent; /* maxDist must be a power of two so that: * (newCurrent & cycleMask) == (curr & cycleMask) * This is required to not corrupt the chains / binary tree. + * + * Now that window sizes can be non-power-of-two, we round it up to the + * next power of two. */ - assert((maxDist & (maxDist - 1)) == 0); + assert(roundedMaxDist >= maxDist); + assert(roundedMaxDist < maxDist + 7 * (maxDist >> 3)); + assert((roundedMaxDist & (roundedMaxDist - 1)) == 0); assert((curr & cycleMask) == (newCurrent & cycleMask)); assert(curr > newCurrent); if (!ZSTD_WINDOW_OVERFLOW_CORRECT_FREQUENTLY) { @@ -1392,9 +1486,9 @@ U32 ZSTD_window_update(ZSTD_window_t* window, /** * Returns the lowest allowed match index. It may either be in the ext-dict or the prefix. */ -MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_MatchState_t* ms, U32 curr, unsigned windowLog) +MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_MatchState_t* ms, U32 curr) { - U32 const maxDistance = 1U << windowLog; + U32 const maxDistance = ZSTD_windowSize(ms->cctxParams); U32 const lowestValid = ms->window.lowLimit; U32 const withinWindow = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; U32 const isDictionary = (ms->loadedDictEnd != 0); @@ -1409,9 +1503,9 @@ MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_MatchState_t* ms, U32 curr, u /** * Returns the lowest allowed match index in the prefix. */ -MEM_STATIC U32 ZSTD_getLowestPrefixIndex(const ZSTD_MatchState_t* ms, U32 curr, unsigned windowLog) +MEM_STATIC U32 ZSTD_getLowestPrefixIndex(const ZSTD_MatchState_t* ms, U32 curr) { - U32 const maxDistance = 1U << windowLog; + U32 const maxDistance = ZSTD_windowSize(ms->cctxParams); U32 const lowestValid = ms->window.dictLimit; U32 const withinWindow = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; U32 const isDictionary = (ms->loadedDictEnd != 0); @@ -1538,13 +1632,13 @@ BlockSummary ZSTD_get1BlockSummary(const ZSTD_Sequence* seqs, size_t nbSeqs); * These prototypes shall only be called from within lib/compress * ============================================================== */ -/* ZSTD_getCParamsFromCCtxParams() : +/* ZSTD_fillCParamsInCCtxParams() : * cParams are built depending on compressionLevel, src size hints, * LDM and manually set compression parameters. * Note: srcSizeHint == 0 means 0! */ -ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( - const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize, ZSTD_CParamMode_e mode); +void ZSTD_fillCParamsInCCtxParams( + ZSTD_CCtx_params* cctxParams, U64 srcSizeHint, size_t dictSize, ZSTD_CParamMode_e mode); /*! ZSTD_initCStream_internal() : * Private use only. Init streaming operation. @@ -1562,6 +1656,11 @@ void ZSTD_resetSeqStore(SeqStore_t* ssPtr); * as the name implies */ ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict); +/*! ZSTD_checkCCtxCParams_internal() : + * Checks the CParams in the CCtxParams (including related parameters not + * *actually* stored in the CParams struct). */ +size_t ZSTD_checkCCtxCParams_internal(const ZSTD_CCtx_params* params); + /* ZSTD_compressBegin_advanced_internal() : * Private use only. To be called from zstdmt_compress.c. */ size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx, diff --git a/lib/compress/zstd_double_fast.c b/lib/compress/zstd_double_fast.c index 1a266e7d955..51b55afaf82 100644 --- a/lib/compress/zstd_double_fast.c +++ b/lib/compress/zstd_double_fast.c @@ -18,7 +18,7 @@ ZSTD_ALLOW_POINTER_OVERFLOW_ATTR void ZSTD_fillDoubleHashTableForCDict(ZSTD_MatchState_t* ms, void const* end, ZSTD_dictTableLoadMethod_e dtlm) { - const ZSTD_compressionParameters* const cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; U32* const hashLarge = ms->hashTable; U32 const hBitsL = cParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS; U32 const mls = cParams->minMatch; @@ -56,7 +56,7 @@ ZSTD_ALLOW_POINTER_OVERFLOW_ATTR void ZSTD_fillDoubleHashTableForCCtx(ZSTD_MatchState_t* ms, void const* end, ZSTD_dictTableLoadMethod_e dtlm) { - const ZSTD_compressionParameters* const cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; U32* const hashLarge = ms->hashTable; U32 const hBitsL = cParams->hashLog; U32 const mls = cParams->minMatch; @@ -106,7 +106,7 @@ size_t ZSTD_compressBlock_doubleFast_noDict_generic( ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize, U32 const mls /* template */) { - ZSTD_compressionParameters const* cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; U32* const hashLong = ms->hashTable; const U32 hBitsL = cParams->hashLog; U32* const hashSmall = ms->chainTable; @@ -116,7 +116,7 @@ size_t ZSTD_compressBlock_doubleFast_noDict_generic( const BYTE* anchor = istart; const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); /* presumes that, if there is a dictionary, it must be using Attach mode */ - const U32 prefixLowestIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog); + const U32 prefixLowestIndex = ZSTD_getLowestPrefixIndex(ms, endIndex); const BYTE* const prefixLowest = base + prefixLowestIndex; const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - HASH_READ_SIZE; @@ -157,7 +157,7 @@ size_t ZSTD_compressBlock_doubleFast_noDict_generic( ip += ((ip - prefixLowest) == 0); { U32 const current = (U32)(ip - base); - U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current, cParams->windowLog); + U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, current); U32 const maxRep = current - windowLow; if (offset_2 > maxRep) offsetSaved2 = offset_2, offset_2 = 0; if (offset_1 > maxRep) offsetSaved1 = offset_1, offset_1 = 0; @@ -330,7 +330,7 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( void const* src, size_t srcSize, U32 const mls /* template */) { - ZSTD_compressionParameters const* cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; U32* const hashLong = ms->hashTable; const U32 hBitsL = cParams->hashLog; U32* const hashSmall = ms->chainTable; @@ -341,14 +341,14 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( const BYTE* anchor = istart; const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); /* presumes that, if there is a dictionary, it must be using Attach mode */ - const U32 prefixLowestIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog); + const U32 prefixLowestIndex = ZSTD_getLowestPrefixIndex(ms, endIndex); const BYTE* const prefixLowest = base + prefixLowestIndex; const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - HASH_READ_SIZE; U32 offset_1=rep[0], offset_2=rep[1]; const ZSTD_MatchState_t* const dms = ms->dictMatchState; - const ZSTD_compressionParameters* const dictCParams = &dms->cParams; + const ZSTD_compressionParameters* const dictCParams = &dms->cctxParams->cParams; const U32* const dictHashLong = dms->hashTable; const U32* const dictHashSmall = dms->chainTable; const U32 dictStartIndex = dms->window.dictLimit; @@ -363,7 +363,7 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic( DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_dictMatchState_generic"); /* if a dictionary is attached, it must be within window range */ - assert(ms->window.dictLimit + (1U << cParams->windowLog) >= endIndex); + assert(ms->window.dictLimit + ZSTD_windowSize(ms->cctxParams) >= endIndex); if (ms->prefetchCDictTables) { size_t const hashTableBytes = (((size_t)1) << dictCParams->hashLog) * sizeof(U32); @@ -569,7 +569,7 @@ size_t ZSTD_compressBlock_doubleFast( ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { - const U32 mls = ms->cParams.minMatch; + const U32 mls = ms->cctxParams->cParams.minMatch; switch(mls) { default: /* includes case 3 */ @@ -589,7 +589,7 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState( ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { - const U32 mls = ms->cParams.minMatch; + const U32 mls = ms->cctxParams->cParams.minMatch; switch(mls) { default: /* includes case 3 */ @@ -612,7 +612,7 @@ size_t ZSTD_compressBlock_doubleFast_extDict_generic( void const* src, size_t srcSize, U32 const mls /* template */) { - ZSTD_compressionParameters const* cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; U32* const hashLong = ms->hashTable; U32 const hBitsL = cParams->hashLog; U32* const hashSmall = ms->chainTable; @@ -624,7 +624,7 @@ size_t ZSTD_compressBlock_doubleFast_extDict_generic( const BYTE* const ilimit = iend - 8; const BYTE* const base = ms->window.base; const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); - const U32 lowLimit = ZSTD_getLowestMatchIndex(ms, endIndex, cParams->windowLog); + const U32 lowLimit = ZSTD_getLowestMatchIndex(ms, endIndex); const U32 dictStartIndex = lowLimit; const U32 dictLimit = ms->window.dictLimit; const U32 prefixStartIndex = (dictLimit > lowLimit) ? dictLimit : lowLimit; @@ -760,7 +760,7 @@ size_t ZSTD_compressBlock_doubleFast_extDict( ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { - U32 const mls = ms->cParams.minMatch; + U32 const mls = ms->cctxParams->cParams.minMatch; switch(mls) { default: /* includes case 3 */ diff --git a/lib/compress/zstd_fast.c b/lib/compress/zstd_fast.c index ee25bcbac8d..82cc40886b4 100644 --- a/lib/compress/zstd_fast.c +++ b/lib/compress/zstd_fast.c @@ -17,7 +17,7 @@ void ZSTD_fillHashTableForCDict(ZSTD_MatchState_t* ms, const void* const end, ZSTD_dictTableLoadMethod_e dtlm) { - const ZSTD_compressionParameters* const cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; U32* const hashTable = ms->hashTable; U32 const hBits = cParams->hashLog + ZSTD_SHORT_CACHE_TAG_BITS; U32 const mls = cParams->minMatch; @@ -54,7 +54,7 @@ void ZSTD_fillHashTableForCCtx(ZSTD_MatchState_t* ms, const void* const end, ZSTD_dictTableLoadMethod_e dtlm) { - const ZSTD_compressionParameters* const cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; U32* const hashTable = ms->hashTable; U32 const hBits = cParams->hashLog; U32 const mls = cParams->minMatch; @@ -194,14 +194,14 @@ size_t ZSTD_compressBlock_fast_noDict_generic( void const* src, size_t srcSize, U32 const mls, int useCmov) { - const ZSTD_compressionParameters* const cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; U32* const hashTable = ms->hashTable; U32 const hlog = cParams->hashLog; size_t const stepSize = cParams->targetLength + !(cParams->targetLength) + 1; /* min 2 */ const BYTE* const base = ms->window.base; const BYTE* const istart = (const BYTE*)src; const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); - const U32 prefixStartIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog); + const U32 prefixStartIndex = ZSTD_getLowestPrefixIndex(ms, endIndex); const BYTE* const prefixStart = base + prefixStartIndex; const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - HASH_READ_SIZE; @@ -237,7 +237,7 @@ size_t ZSTD_compressBlock_fast_noDict_generic( DEBUGLOG(5, "ZSTD_compressBlock_fast_generic"); ip0 += (ip0 == prefixStart); { U32 const curr = (U32)(ip0 - base); - U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, curr, cParams->windowLog); + U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, curr); U32 const maxRep = curr - windowLow; if (rep_offset2 > maxRep) offsetSaved2 = rep_offset2, rep_offset2 = 0; if (rep_offset1 > maxRep) offsetSaved1 = rep_offset1, rep_offset1 = 0; @@ -444,9 +444,9 @@ size_t ZSTD_compressBlock_fast( ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { - U32 const mml = ms->cParams.minMatch; + U32 const mml = ms->cctxParams->cParams.minMatch; /* use cmov when "candidate in range" branch is likely unpredictable */ - int const useCmov = ms->cParams.windowLog < 19; + int const useCmov = ms->cctxParams->cParams.windowLog < 19; assert(ms->dictMatchState == NULL); if (useCmov) { switch(mml) @@ -484,7 +484,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic( ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize, U32 const mls, U32 const hasStep) { - const ZSTD_compressionParameters* const cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; U32* const hashTable = ms->hashTable; U32 const hlog = cParams->hashLog; /* support stepSize of 0 */ @@ -501,7 +501,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic( U32 offset_1=rep[0], offset_2=rep[1]; const ZSTD_MatchState_t* const dms = ms->dictMatchState; - const ZSTD_compressionParameters* const dictCParams = &dms->cParams ; + const ZSTD_compressionParameters* const dictCParams = &dms->cctxParams->cParams; const U32* const dictHashTable = dms->hashTable; const U32 dictStartIndex = dms->window.dictLimit; const BYTE* const dictBase = dms->window.base; @@ -513,7 +513,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic( /* if a dictionary is still attached, it necessarily means that * it is within window size. So we just check it. */ - const U32 maxDistance = 1U << cParams->windowLog; + const U32 maxDistance = ZSTD_windowSize(ms->cctxParams); const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); assert(endIndex - prefixStartIndex <= maxDistance); (void)maxDistance; (void)endIndex; /* these variables are not used when assert() is disabled */ @@ -687,7 +687,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState( ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { - U32 const mls = ms->cParams.minMatch; + U32 const mls = ms->cctxParams->cParams.minMatch; assert(ms->dictMatchState != NULL); switch(mls) { @@ -710,7 +710,7 @@ size_t ZSTD_compressBlock_fast_extDict_generic( ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize, U32 const mls, U32 const hasStep) { - const ZSTD_compressionParameters* const cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; U32* const hashTable = ms->hashTable; U32 const hlog = cParams->hashLog; /* support stepSize of 0 */ @@ -720,7 +720,7 @@ size_t ZSTD_compressBlock_fast_extDict_generic( const BYTE* const istart = (const BYTE*)src; const BYTE* anchor = istart; const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); - const U32 lowLimit = ZSTD_getLowestMatchIndex(ms, endIndex, cParams->windowLog); + const U32 lowLimit = ZSTD_getLowestMatchIndex(ms, endIndex); const U32 dictStartIndex = lowLimit; const BYTE* const dictStart = dictBase + dictStartIndex; const U32 dictLimit = ms->window.dictLimit; @@ -968,7 +968,7 @@ size_t ZSTD_compressBlock_fast_extDict( ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], void const* src, size_t srcSize) { - U32 const mls = ms->cParams.minMatch; + U32 const mls = ms->cctxParams->cParams.minMatch; assert(ms->dictMatchState == NULL); switch(mls) { diff --git a/lib/compress/zstd_lazy.c b/lib/compress/zstd_lazy.c index 272ebe0ece7..d08afff79cf 100644 --- a/lib/compress/zstd_lazy.c +++ b/lib/compress/zstd_lazy.c @@ -30,7 +30,7 @@ void ZSTD_updateDUBT(ZSTD_MatchState_t* ms, const BYTE* ip, const BYTE* iend, U32 mls) { - const ZSTD_compressionParameters* const cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; U32* const hashTable = ms->hashTable; U32 const hashLog = cParams->hashLog; @@ -76,7 +76,7 @@ void ZSTD_insertDUBT1(const ZSTD_MatchState_t* ms, U32 nbCompares, U32 btLow, const ZSTD_dictMode_e dictMode) { - const ZSTD_compressionParameters* const cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; U32* const bt = ms->chainTable; U32 const btLog = cParams->chainLog - 1; U32 const btMask = (1 << btLog) - 1; @@ -94,7 +94,7 @@ void ZSTD_insertDUBT1(const ZSTD_MatchState_t* ms, U32 matchIndex = *smallerPtr; /* this candidate is unsorted : next sorted candidate is reached through *smallerPtr, while *largerPtr contains previous unsorted candidate (which is already saved and can be overwritten) */ U32 dummy32; /* to be nullified at the end */ U32 const windowValid = ms->window.lowLimit; - U32 const maxDistance = 1U << cParams->windowLog; + U32 const maxDistance = ZSTD_windowSize(ms->cctxParams); U32 const windowLow = (curr - windowValid > maxDistance) ? curr - maxDistance : windowValid; @@ -171,7 +171,7 @@ size_t ZSTD_DUBT_findBetterDictMatch ( const ZSTD_dictMode_e dictMode) { const ZSTD_MatchState_t * const dms = ms->dictMatchState; - const ZSTD_compressionParameters* const dmsCParams = &dms->cParams; + const ZSTD_compressionParameters* const dmsCParams = &dms->cctxParams->cParams; const U32 * const dictHashTable = dms->hashTable; U32 const hashLog = dmsCParams->hashLog; size_t const h = ZSTD_hashPtr(ip, hashLog, mls); @@ -246,7 +246,7 @@ size_t ZSTD_DUBT_findBestMatch(ZSTD_MatchState_t* ms, U32 const mls, const ZSTD_dictMode_e dictMode) { - const ZSTD_compressionParameters* const cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; U32* const hashTable = ms->hashTable; U32 const hashLog = cParams->hashLog; size_t const h = ZSTD_hashPtr(ip, hashLog, mls); @@ -254,7 +254,7 @@ size_t ZSTD_DUBT_findBestMatch(ZSTD_MatchState_t* ms, const BYTE* const base = ms->window.base; U32 const curr = (U32)(ip-base); - U32 const windowLow = ZSTD_getLowestMatchIndex(ms, curr, cParams->windowLog); + U32 const windowLow = ZSTD_getLowestMatchIndex(ms, curr); U32* const bt = ms->chainTable; U32 const btLog = cParams->chainLog - 1; @@ -410,16 +410,17 @@ size_t ZSTD_BtFindBestMatch( ZSTD_MatchState_t* ms, void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_MatchState_t* ms, const BYTE* const ip) { + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; const BYTE* const base = ms->window.base; U32 const target = (U32)(ip - base); U32* const hashTable = ms->hashTable; U32* const chainTable = ms->chainTable; - U32 const chainSize = 1 << ms->cParams.chainLog; + U32 const chainSize = 1 << cParams->chainLog; U32 idx = ms->nextToUpdate; U32 const minChain = chainSize < target - idx ? target - chainSize : idx; U32 const bucketSize = 1 << ZSTD_LAZY_DDSS_BUCKET_LOG; U32 const cacheSize = bucketSize - 1; - U32 const chainAttempts = (1 << ms->cParams.searchLog) - cacheSize; + U32 const chainAttempts = (1 << cParams->searchLog) - cacheSize; U32 const chainLimit = chainAttempts > 255 ? 255 : chainAttempts; /* We know the hashtable is oversized by a factor of `bucketSize`. @@ -427,21 +428,21 @@ void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_MatchState_t* ms, const B * single entry. We will use the rest of the space to construct a temporary * chaintable. */ - U32 const hashLog = ms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG; + U32 const hashLog = cParams->hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG; U32* const tmpHashTable = hashTable; U32* const tmpChainTable = hashTable + ((size_t)1 << hashLog); U32 const tmpChainSize = (U32)((1 << ZSTD_LAZY_DDSS_BUCKET_LOG) - 1) << hashLog; U32 const tmpMinChain = tmpChainSize < target ? target - tmpChainSize : idx; U32 hashIdx; - assert(ms->cParams.chainLog <= 24); - assert(ms->cParams.hashLog > ms->cParams.chainLog); + assert(cParams->chainLog <= 24); + assert(cParams->hashLog > cParams->chainLog); assert(idx != 0); assert(tmpMinChain <= minChain); /* fill conventional hash table and conventional chain table */ for ( ; idx < target; idx++) { - U32 const h = (U32)ZSTD_hashPtr(base + idx, hashLog, ms->cParams.minMatch); + U32 const h = (U32)ZSTD_hashPtr(base + idx, hashLog, cParams->minMatch); if (idx >= tmpMinChain) { tmpChainTable[idx - tmpMinChain] = hashTable[h]; } @@ -510,7 +511,7 @@ void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_MatchState_t* ms, const B /* fill the buckets of the hash table */ for (idx = ms->nextToUpdate; idx < target; idx++) { - U32 const h = (U32)ZSTD_hashPtr(base + idx, hashLog, ms->cParams.minMatch) + U32 const h = (U32)ZSTD_hashPtr(base + idx, hashLog, cParams->minMatch) << ZSTD_LAZY_DDSS_BUCKET_LOG; U32 i; /* Shift hash cache down 1. */ @@ -657,8 +658,8 @@ U32 ZSTD_insertAndFindFirstIndex_internal( } U32 ZSTD_insertAndFindFirstIndex(ZSTD_MatchState_t* ms, const BYTE* ip) { - const ZSTD_compressionParameters* const cParams = &ms->cParams; - return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, ms->cParams.minMatch, /* lazySkipping*/ 0); + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; + return ZSTD_insertAndFindFirstIndex_internal(ms, cParams, ip, cParams->minMatch, /* lazySkipping*/ 0); } /* inlining is important to hardwire a hot branch (template emulation) */ @@ -670,7 +671,7 @@ size_t ZSTD_HcFindBestMatch( size_t* offsetPtr, const U32 mls, const ZSTD_dictMode_e dictMode) { - const ZSTD_compressionParameters* const cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; U32* const chainTable = ms->chainTable; const U32 chainSize = (1 << cParams->chainLog); const U32 chainMask = chainSize-1; @@ -680,7 +681,7 @@ size_t ZSTD_HcFindBestMatch( const BYTE* const prefixStart = base + dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; const U32 curr = (U32)(ip-base); - const U32 maxDistance = 1U << cParams->windowLog; + const U32 maxDistance = ZSTD_windowSize(ms->cctxParams); const U32 lowestValid = ms->window.lowLimit; const U32 withinMaxDistance = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; const U32 isDictionary = (ms->loadedDictEnd != 0); @@ -691,7 +692,7 @@ size_t ZSTD_HcFindBestMatch( const ZSTD_MatchState_t* const dms = ms->dictMatchState; const U32 ddsHashLog = dictMode == ZSTD_dedicatedDictSearch - ? dms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG : 0; + ? dms->cctxParams->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG : 0; const size_t ddsIdx = dictMode == ZSTD_dedicatedDictSearch ? ZSTD_hashPtr(ip, ddsHashLog, mls) << ZSTD_LAZY_DDSS_BUCKET_LOG : 0; @@ -737,7 +738,7 @@ size_t ZSTD_HcFindBestMatch( ip, iLimit, prefixStart, curr, dictLimit, ddsIdx); } else if (dictMode == ZSTD_dictMatchState) { const U32* const dmsChainTable = dms->chainTable; - const U32 dmsChainSize = (1 << dms->cParams.chainLog); + const U32 dmsChainSize = (1 << dms->cctxParams->cParams.chainLog); const U32 dmsChainMask = dmsChainSize - 1; const U32 dmsLowestIndex = dms->window.dictLimit; const BYTE* const dmsBase = dms->window.base; @@ -746,7 +747,7 @@ size_t ZSTD_HcFindBestMatch( const U32 dmsIndexDelta = dictLimit - dmsSize; const U32 dmsMinChain = dmsSize > dmsChainSize ? dmsSize - dmsChainSize : 0; - matchIndex = dms->hashTable[ZSTD_hashPtr(ip, dms->cParams.hashLog, mls)]; + matchIndex = dms->hashTable[ZSTD_hashPtr(ip, dms->cctxParams->cParams.hashLog, mls)]; for ( ; (matchIndex>=dmsLowestIndex) & (nbAttempts>0) ; nbAttempts--) { size_t currentMl=0; @@ -947,9 +948,9 @@ void ZSTD_row_update_internal(ZSTD_MatchState_t* ms, const BYTE* ip, * processing. */ void ZSTD_row_update(ZSTD_MatchState_t* const ms, const BYTE* ip) { - const U32 rowLog = BOUNDED(4, ms->cParams.searchLog, 6); + const U32 rowLog = BOUNDED(4, ms->cctxParams->cParams.searchLog, 6); const U32 rowMask = (1u << rowLog) - 1; - const U32 mls = MIN(ms->cParams.minMatch, 6 /* mls caps out at 6 */); + const U32 mls = MIN(ms->cctxParams->cParams.minMatch, 6 /* mls caps out at 6 */); DEBUGLOG(5, "ZSTD_row_update(), rowLog=%u", rowLog); ZSTD_row_update_internal(ms, ip, mls, rowLog, rowMask, 0 /* don't use cache */); @@ -1149,14 +1150,14 @@ size_t ZSTD_RowFindBestMatch( BYTE* const tagTable = ms->tagTable; U32* const hashCache = ms->hashCache; const U32 hashLog = ms->rowHashLog; - const ZSTD_compressionParameters* const cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; const BYTE* const base = ms->window.base; const BYTE* const dictBase = ms->window.dictBase; const U32 dictLimit = ms->window.dictLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; const U32 curr = (U32)(ip-base); - const U32 maxDistance = 1U << cParams->windowLog; + const U32 maxDistance = ZSTD_windowSize(ms->cctxParams); const U32 lowestValid = ms->window.lowLimit; const U32 withinMaxDistance = (curr - lowestValid > maxDistance) ? curr - maxDistance : lowestValid; const U32 isDictionary = (ms->loadedDictEnd != 0); @@ -1181,7 +1182,7 @@ size_t ZSTD_RowFindBestMatch( BYTE* dmsTagRow = NULL; if (dictMode == ZSTD_dedicatedDictSearch) { - const U32 ddsHashLog = dms->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG; + const U32 ddsHashLog = dms->cctxParams->cParams.hashLog - ZSTD_LAZY_DDSS_BUCKET_LOG; { /* Prefetch DDS hashtable entry */ ddsIdx = ZSTD_hashPtr(ip, ddsHashLog, mls) << ZSTD_LAZY_DDSS_BUCKET_LOG; PREFETCH_L1(&dms->hashTable[ddsIdx]); @@ -1368,7 +1369,7 @@ size_t ZSTD_RowFindBestMatch( const BYTE* ip, const BYTE* const iLimit, \ size_t* offBasePtr) \ { \ - assert(MAX(4, MIN(6, ms->cParams.minMatch)) == mls); \ + assert(MAX(4, MIN(6, ms->cctxParams->cParams.minMatch)) == mls); \ return ZSTD_BtFindBestMatch(ms, ip, iLimit, offBasePtr, mls, ZSTD_##dictMode); \ } \ @@ -1378,7 +1379,7 @@ size_t ZSTD_RowFindBestMatch( const BYTE* ip, const BYTE* const iLimit, \ size_t* offsetPtr) \ { \ - assert(MAX(4, MIN(6, ms->cParams.minMatch)) == mls); \ + assert(MAX(4, MIN(6, ms->cctxParams->cParams.minMatch)) == mls); \ return ZSTD_HcFindBestMatch(ms, ip, iLimit, offsetPtr, mls, ZSTD_##dictMode); \ } \ @@ -1388,8 +1389,8 @@ size_t ZSTD_RowFindBestMatch( const BYTE* ip, const BYTE* const iLimit, \ size_t* offsetPtr) \ { \ - assert(MAX(4, MIN(6, ms->cParams.minMatch)) == mls); \ - assert(MAX(4, MIN(6, ms->cParams.searchLog)) == rowLog); \ + assert(MAX(4, MIN(6, ms->cctxParams->cParams.minMatch)) == mls); \ + assert(MAX(4, MIN(6, ms->cctxParams->cParams.searchLog)) == rowLog); \ return ZSTD_RowFindBestMatch(ms, ip, iLimit, offsetPtr, mls, ZSTD_##dictMode, rowLog); \ } \ @@ -1528,8 +1529,8 @@ size_t ZSTD_compressBlock_lazy_generic( const BYTE* const base = ms->window.base; const U32 prefixLowestIndex = ms->window.dictLimit; const BYTE* const prefixLowest = base + prefixLowestIndex; - const U32 mls = BOUNDED(4, ms->cParams.minMatch, 6); - const U32 rowLog = BOUNDED(4, ms->cParams.searchLog, 6); + const U32 mls = BOUNDED(4, ms->cctxParams->cParams.minMatch, 6); + const U32 rowLog = BOUNDED(4, ms->cctxParams->cParams.searchLog, 6); U32 offset_1 = rep[0], offset_2 = rep[1]; U32 offsetSaved1 = 0, offsetSaved2 = 0; @@ -1551,7 +1552,7 @@ size_t ZSTD_compressBlock_lazy_generic( ip += (dictAndPrefixLength == 0); if (dictMode == ZSTD_noDict) { U32 const curr = (U32)(ip - base); - U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, curr, ms->cParams.windowLog); + U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, curr); U32 const maxRep = curr - windowLow; if (offset_2 > maxRep) offsetSaved2 = offset_2, offset_2 = 0; if (offset_1 > maxRep) offsetSaved1 = offset_1, offset_1 = 0; @@ -1951,9 +1952,8 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( const BYTE* const dictBase = ms->window.dictBase; const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const dictStart = dictBase + ms->window.lowLimit; - const U32 windowLog = ms->cParams.windowLog; - const U32 mls = BOUNDED(4, ms->cParams.minMatch, 6); - const U32 rowLog = BOUNDED(4, ms->cParams.searchLog, 6); + const U32 mls = BOUNDED(4, ms->cctxParams->cParams.minMatch, 6); + const U32 rowLog = BOUNDED(4, ms->cctxParams->cParams.searchLog, 6); U32 offset_1 = rep[0], offset_2 = rep[1]; @@ -1982,7 +1982,7 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( U32 curr = (U32)(ip-base); /* check repCode */ - { const U32 windowLow = ZSTD_getLowestMatchIndex(ms, curr+1, windowLog); + { const U32 windowLow = ZSTD_getLowestMatchIndex(ms, curr+1); const U32 repIndex = (U32)(curr+1 - offset_1); const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; @@ -2023,7 +2023,7 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( curr++; /* check repCode */ if (offBase) { - const U32 windowLow = ZSTD_getLowestMatchIndex(ms, curr, windowLog); + const U32 windowLow = ZSTD_getLowestMatchIndex(ms, curr); const U32 repIndex = (U32)(curr - offset_1); const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; @@ -2055,7 +2055,7 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( curr++; /* check repCode */ if (offBase) { - const U32 windowLow = ZSTD_getLowestMatchIndex(ms, curr, windowLog); + const U32 windowLow = ZSTD_getLowestMatchIndex(ms, curr); const U32 repIndex = (U32)(curr - offset_1); const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; @@ -2109,7 +2109,7 @@ size_t ZSTD_compressBlock_lazy_extDict_generic( /* check immediate repcode */ while (ip <= ilimit) { const U32 repCurrent = (U32)(ip-base); - const U32 windowLow = ZSTD_getLowestMatchIndex(ms, repCurrent, windowLog); + const U32 windowLow = ZSTD_getLowestMatchIndex(ms, repCurrent); const U32 repIndex = repCurrent - offset_2; const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; diff --git a/lib/compress/zstd_ldm.c b/lib/compress/zstd_ldm.c index 070551cad81..ad9aadb5c7c 100644 --- a/lib/compress/zstd_ldm.c +++ b/lib/compress/zstd_ldm.c @@ -133,9 +133,10 @@ static size_t ZSTD_ldm_gear_feed(ldmRollingHashState_t* state, } void ZSTD_ldm_adjustParameters(ldmParams_t* params, - const ZSTD_compressionParameters* cParams) + const ZSTD_CCtx_params* cctxParams) { - params->windowLog = cParams->windowLog; + params->windowLog = cctxParams->cParams.windowLog; + params->windowFrac = cctxParams->windowFrac; ZSTD_STATIC_ASSERT(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX); DEBUGLOG(4, "ZSTD_ldm_adjustParameters"); if (params->hashRateLog == 0) { @@ -146,9 +147,9 @@ void ZSTD_ldm_adjustParameters(ldmParams_t* params, params->hashRateLog = params->windowLog - params->hashLog; } } else { - assert(1 <= (int)cParams->strategy && (int)cParams->strategy <= 9); + assert(1 <= (int)cctxParams->cParams.strategy && (int)cctxParams->cParams.strategy <= 9); /* mapping from [fast, rate7] to [btultra2, rate4] */ - params->hashRateLog = 7 - (cParams->strategy/3); + params->hashRateLog = 7 - (cctxParams->cParams.strategy/3); } } if (params->hashLog == 0) { @@ -156,12 +157,12 @@ void ZSTD_ldm_adjustParameters(ldmParams_t* params, } if (params->minMatchLength == 0) { params->minMatchLength = LDM_MIN_MATCH_LENGTH; - if (cParams->strategy >= ZSTD_btultra) + if (cctxParams->cParams.strategy >= ZSTD_btultra) params->minMatchLength /= 2; } if (params->bucketSizeLog==0) { - assert(1 <= (int)cParams->strategy && (int)cParams->strategy <= 9); - params->bucketSizeLog = BOUNDED(LDM_BUCKET_SIZE_LOG, (U32)cParams->strategy, ZSTD_LDM_BUCKETSIZELOG_MAX); + assert(1 <= (int)cctxParams->cParams.strategy && (int)cctxParams->cParams.strategy <= 9); + params->bucketSizeLog = BOUNDED(LDM_BUCKET_SIZE_LOG, (U32)cctxParams->cParams.strategy, ZSTD_LDM_BUCKETSIZELOG_MAX); } params->bucketSizeLog = MIN(params->bucketSizeLog, params->hashLog); } @@ -253,7 +254,7 @@ static size_t ZSTD_ldm_fillFastTables(ZSTD_MatchState_t* ms, { const BYTE* const iend = (const BYTE*)end; - switch(ms->cParams.strategy) + switch(ms->cctxParams->cParams.strategy) { case ZSTD_fast: ZSTD_fillHashTable(ms, iend, ZSTD_dtlm_fast, ZSTD_tfp_forCCtx); @@ -527,7 +528,7 @@ size_t ZSTD_ldm_generateSequences( ldmState_t* ldmState, RawSeqStore_t* sequences, ldmParams_t const* params, void const* src, size_t srcSize) { - U32 const maxDist = 1U << params->windowLog; + U32 const maxDist = ZSTD_windowSizeLDM(params); BYTE const* const istart = (BYTE const*)src; BYTE const* const iend = istart + srcSize; size_t const kMaxChunkSize = 1 << 20; @@ -683,7 +684,7 @@ size_t ZSTD_ldm_blockCompress(RawSeqStore_t* rawSeqStore, ZSTD_ParamSwitch_e useRowMatchFinder, void const* src, size_t srcSize) { - const ZSTD_compressionParameters* const cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; unsigned const minMatch = cParams->minMatch; ZSTD_BlockCompressor_f const blockCompressor = ZSTD_selectBlockCompressor(cParams->strategy, useRowMatchFinder, ZSTD_matchState_dictMode(ms)); diff --git a/lib/compress/zstd_ldm.h b/lib/compress/zstd_ldm.h index 42736231aa8..f06b537866d 100644 --- a/lib/compress/zstd_ldm.h +++ b/lib/compress/zstd_ldm.h @@ -104,6 +104,6 @@ size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize); * Ensures that the minMatchLength >= targetLength during optimal parsing. */ void ZSTD_ldm_adjustParameters(ldmParams_t* params, - ZSTD_compressionParameters const* cParams); + const ZSTD_CCtx_params* cctxParams); #endif /* ZSTD_FAST_H */ diff --git a/lib/compress/zstd_opt.c b/lib/compress/zstd_opt.c index 3d7171b755b..8485accfb5e 100644 --- a/lib/compress/zstd_opt.c +++ b/lib/compress/zstd_opt.c @@ -445,7 +445,7 @@ U32 ZSTD_insertBt1( U32 const target, U32 const mls, const int extDict) { - const ZSTD_compressionParameters* const cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; U32* const hashTable = ms->hashTable; U32 const hashLog = cParams->hashLog; size_t const h = ZSTD_hashPtr(ip, hashLog, mls); @@ -468,7 +468,7 @@ U32 ZSTD_insertBt1( /* windowLow is based on target because * we only need positions that will be in the window at the end of the tree update. */ - U32 const windowLow = ZSTD_getLowestMatchIndex(ms, target, cParams->windowLog); + U32 const windowLow = ZSTD_getLowestMatchIndex(ms, target); U32 matchEndIdx = curr+8+1; size_t bestLength = 8; U32 nbCompares = 1U << cParams->searchLog; @@ -581,7 +581,7 @@ void ZSTD_updateTree_internal( } void ZSTD_updateTree(ZSTD_MatchState_t* ms, const BYTE* ip, const BYTE* iend) { - ZSTD_updateTree_internal(ms, ip, iend, ms->cParams.minMatch, ZSTD_noDict); + ZSTD_updateTree_internal(ms, ip, iend, ms->cctxParams->cParams.minMatch, ZSTD_noDict); } FORCE_INLINE_TEMPLATE @@ -598,7 +598,7 @@ ZSTD_insertBtAndGetAllMatches ( const U32 lengthToBeat, const U32 mls /* template */) { - const ZSTD_compressionParameters* const cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1); const BYTE* const base = ms->window.base; U32 const curr = (U32)(ip-base); @@ -616,7 +616,7 @@ ZSTD_insertBtAndGetAllMatches ( const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; U32 const btLow = (btMask >= curr) ? 0 : curr - btMask; - U32 const windowLow = ZSTD_getLowestMatchIndex(ms, curr, cParams->windowLog); + U32 const windowLow = ZSTD_getLowestMatchIndex(ms, curr); U32 const matchLow = windowLow ? windowLow : 1; U32* smallerPtr = bt + 2*(curr&btMask); U32* largerPtr = bt + 2*(curr&btMask) + 1; @@ -627,7 +627,7 @@ ZSTD_insertBtAndGetAllMatches ( const ZSTD_MatchState_t* dms = dictMode == ZSTD_dictMatchState ? ms->dictMatchState : NULL; const ZSTD_compressionParameters* const dmsCParams = - dictMode == ZSTD_dictMatchState ? &dms->cParams : NULL; + dictMode == ZSTD_dictMatchState ? &dms->cctxParams->cParams : NULL; const BYTE* const dmsBase = dictMode == ZSTD_dictMatchState ? dms->window.base : NULL; const BYTE* const dmsEnd = dictMode == ZSTD_dictMatchState ? dms->window.nextSrc : NULL; U32 const dmsHighLimit = dictMode == ZSTD_dictMatchState ? (U32)(dmsEnd - dmsBase) : 0; @@ -841,7 +841,7 @@ U32 ZSTD_btGetAllMatches_internal( const ZSTD_dictMode_e dictMode, const U32 mls) { - assert(BOUNDED(3, ms->cParams.minMatch, 6) == mls); + assert(BOUNDED(3, ms->cctxParams->cParams.minMatch, 6) == mls); DEBUGLOG(8, "ZSTD_BtGetAllMatches(dictMode=%d, mls=%u)", (int)dictMode, mls); if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */ @@ -893,7 +893,7 @@ ZSTD_selectBtGetAllMatches(ZSTD_MatchState_t const* ms, ZSTD_dictMode_e const di ZSTD_BT_GET_ALL_MATCHES_ARRAY(extDict), ZSTD_BT_GET_ALL_MATCHES_ARRAY(dictMatchState) }; - U32 const mls = BOUNDED(3, ms->cParams.minMatch, 6); + U32 const mls = BOUNDED(3, ms->cctxParams->cParams.minMatch, 6); assert((U32)dictMode < 3); assert(mls - 3 < 4); return getAllMatchesFns[(int)dictMode][mls - 3]; @@ -1089,7 +1089,7 @@ ZSTD_compressBlock_opt_generic(ZSTD_MatchState_t* ms, const BYTE* const ilimit = iend - 8; const BYTE* const base = ms->window.base; const BYTE* const prefixStart = base + ms->window.dictLimit; - const ZSTD_compressionParameters* const cParams = &ms->cParams; + const ZSTD_compressionParameters* const cParams = &ms->cctxParams->cParams; ZSTD_getAllMatchesFn getAllMatches = ZSTD_selectBtGetAllMatches(ms, dictMode); diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 0f1fe6d7469..19b26c02e73 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -494,8 +494,8 @@ ZSTDMT_serialState_reset(SerialState* serialState, { /* Adjust parameters */ if (params.ldmParams.enableLdm == ZSTD_ps_enable) { - DEBUGLOG(4, "LDM window size = %u KB", (1U << params.cParams.windowLog) >> 10); - ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams); + DEBUGLOG(4, "LDM window size = %u KB", ZSTD_windowSize(¶ms) >> 10); + ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms); assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog); assert(params.ldmParams.hashRateLog < 32); } else { @@ -1095,14 +1095,19 @@ static size_t ZSTDMT_resize(ZSTDMT_CCtx* mtctx, unsigned nbWorkers) * New parameters will be applied to next compression job. */ void ZSTDMT_updateCParams_whileCompressing(ZSTDMT_CCtx* mtctx, const ZSTD_CCtx_params* cctxParams) { - U32 const saved_wlog = mtctx->params.cParams.windowLog; /* Do not modify windowLog while compressing */ + U32 const saved_wlog = mtctx->params.cParams.windowLog; /* Do not modify windowLog while compressing */ + U32 const saved_wfrac = mtctx->params.windowFrac; /* Do not modify windowFrac while compressing */ int const compressionLevel = cctxParams->compressionLevel; DEBUGLOG(5, "ZSTDMT_updateCParams_whileCompressing (level:%i)", compressionLevel); mtctx->params.compressionLevel = compressionLevel; - { ZSTD_compressionParameters cParams = ZSTD_getCParamsFromCCtxParams(cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); - cParams.windowLog = saved_wlog; - mtctx->params.cParams = cParams; + { + ZSTD_CCtx_params params = *cctxParams; + ZSTD_fillCParamsInCCtxParams(¶ms, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); + params.cParams.windowLog = saved_wlog; + params.windowFrac = saved_wfrac; + mtctx->params.cParams = params.cParams; + mtctx->params.windowFrac = params.windowFrac; } } @@ -1256,7 +1261,7 @@ size_t ZSTDMT_initCStream_internal( (U32)pledgedSrcSize, params.nbWorkers, mtctx->cctxPool->totalCCtx); /* params supposed partially fully validated at this point */ - assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); + assert(!ZSTD_isError(ZSTD_checkCCtxCParams_internal(¶ms))); assert(!((dict) && (cdict))); /* either dict or cdict, not both */ /* init */ @@ -1276,9 +1281,10 @@ size_t ZSTDMT_initCStream_internal( mtctx->frameContentSize = pledgedSrcSize; ZSTD_freeCDict(mtctx->cdictLocal); if (dict) { - mtctx->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, - ZSTD_dlm_byCopy, dictContentType, /* note : a loadPrefix becomes an internal CDict */ - params.cParams, mtctx->cMem); + mtctx->cdictLocal = ZSTD_createCDict_advanced( + dict, dictSize, + ZSTD_dlm_byCopy, dictContentType, /* note : a loadPrefix becomes an internal CDict */ + params.cParams, mtctx->cMem); mtctx->cdict = mtctx->cdictLocal; if (mtctx->cdictLocal == NULL) return ERROR(memory_allocation); } else { @@ -1312,7 +1318,7 @@ size_t ZSTDMT_initCStream_internal( ZSTDMT_setBufferSize(mtctx->bufPool, ZSTD_compressBound(mtctx->targetSectionSize)); { /* If ldm is enabled we need windowSize space. */ - size_t const windowSize = mtctx->params.ldmParams.enableLdm == ZSTD_ps_enable ? (1U << mtctx->params.cParams.windowLog) : 0; + size_t const windowSize = mtctx->params.ldmParams.enableLdm == ZSTD_ps_enable ? ZSTD_windowSize(&mtctx->params) : 0; /* Two buffers of slack, plus extra space for the overlap * This is the minimum slack that LDM works with. One extra because * flush might waste up to targetSectionSize-1 bytes. Another extra @@ -1358,9 +1364,10 @@ size_t ZSTDMT_initCStream_internal( mtctx->inBuff.prefix.size = dictSize; } else { /* note : a loadPrefix becomes an internal CDict */ - mtctx->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, - ZSTD_dlm_byRef, dictContentType, - params.cParams, mtctx->cMem); + mtctx->cdictLocal = ZSTD_createCDict_advanced( + dict, dictSize, + ZSTD_dlm_byRef, dictContentType, + params.cParams, mtctx->cMem); mtctx->cdict = mtctx->cdictLocal; if (mtctx->cdictLocal == NULL) return ERROR(memory_allocation); } diff --git a/lib/zstd.h b/lib/zstd.h index b8c0644a7ec..222e1793dc3 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -372,7 +372,10 @@ typedef enum { * Must be clamped between ZSTD_WINDOWLOG_MIN and ZSTD_WINDOWLOG_MAX. * Special: value 0 means "use default windowLog". * Note: Using a windowLog greater than ZSTD_WINDOWLOG_LIMIT_DEFAULT - * requires explicitly allowing such size at streaming decompression stage. */ + * requires explicitly allowing such size at streaming + * decompression stage. + * Note: The ZSTD_c_windowFrac parameter allows finer-grained + * tweaking of the window size set by this parameter. */ ZSTD_c_hashLog=102, /* Size of the initial probe table, as a power of 2. * Resulting memory usage is (1 << (hashLog+2)). * Must be clamped between ZSTD_HASHLOG_MIN and ZSTD_HASHLOG_MAX. @@ -538,7 +541,8 @@ typedef enum { ZSTD_c_experimentalParam17=1014, ZSTD_c_experimentalParam18=1015, ZSTD_c_experimentalParam19=1016, - ZSTD_c_experimentalParam20=1017 + ZSTD_c_experimentalParam20=1017, + ZSTD_c_experimentalParam21=1018 } ZSTD_cParameter; typedef struct { @@ -2355,6 +2359,19 @@ ZSTDLIB_STATIC_API size_t ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx* cctx, const vo #define ZSTD_c_repcodeResolution ZSTD_c_experimentalParam19 #define ZSTD_c_searchForExternalRepcodes ZSTD_c_experimentalParam19 /* older name */ +/* ZSTD_c_windowFrac + * The Zstandard format allows expressing window sizes in a more fine-grained + * way than just the power-of-two sizes captured by the windowLog parameter. + * The window size is `(1 + WF / 8) * 2 ^ WL` bytes, where WL is the windowLog + * and WF is the windowFrac. + * + * The valid range of values for this parameter is 0 to 7. The default value + * is 0. The value configured only takes effect if the windowLog has also + * explicitly been set. The windowFrac is ignored when the windowLog is + * ZSTD_WINDOWLOG_MAX (you can't select a window size larger than + * `2 ^ ZSTD_WINDOWLOG_MAX`). + */ +#define ZSTD_c_windowFrac ZSTD_c_experimentalParam21 /*! ZSTD_CCtx_getParameter() : * Get the requested compression parameter value, selected by enum ZSTD_cParameter, diff --git a/programs/fileio.c b/programs/fileio.c index 0ecca40d2ab..593e9b402e7 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -308,6 +308,7 @@ FIO_prefs_t* FIO_createPreferences(void) ret->allowBlockDevices = 0; ret->asyncIO = AIO_supported(); ret->passThrough = -1; + ret->windowFrac = 0; return ret; } @@ -427,6 +428,10 @@ void FIO_setLiteralCompressionMode( prefs->literalCompressionMode = mode; } +void FIO_setWindowFrac(FIO_prefs_t* const prefs, int windowFrac) { + prefs->windowFrac = windowFrac; +} + void FIO_setAdaptMin(FIO_prefs_t* const prefs, int minCLevel) { #ifndef ZSTD_NOCOMPRESS @@ -1171,6 +1176,7 @@ static cRess_t FIO_createCResources(FIO_prefs_t* const prefs, CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_c_useRowMatchFinder, prefs->useRowMatchFinder)); /* compression parameters */ CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_c_windowLog, (int)comprParams.windowLog) ); + CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_c_windowFrac, prefs->windowFrac) ); CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_c_chainLog, (int)comprParams.chainLog) ); CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_c_hashLog, (int)comprParams.hashLog) ); CHECK( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_c_searchLog, (int)comprParams.searchLog) ); diff --git a/programs/fileio.h b/programs/fileio.h index cb53ef53781..bb36922cf96 100644 --- a/programs/fileio.h +++ b/programs/fileio.h @@ -91,6 +91,7 @@ void FIO_setTestMode(FIO_prefs_t* const prefs, int testMode); void FIO_setLiteralCompressionMode( FIO_prefs_t* const prefs, ZSTD_ParamSwitch_e mode); +void FIO_setWindowFrac(FIO_prefs_t* const prefs, int windowFrac); void FIO_setProgressSetting(FIO_progressSetting_e progressSetting); void FIO_setNotificationLevel(int level); diff --git a/programs/fileio_types.h b/programs/fileio_types.h index 23bda4168d8..6b573da4837 100644 --- a/programs/fileio_types.h +++ b/programs/fileio_types.h @@ -54,6 +54,7 @@ typedef struct FIO_prefs_s { int srcSizeHint; int testMode; ZSTD_ParamSwitch_e literalCompressionMode; + int windowFrac; /* IO preferences */ int removeSrcFile; diff --git a/programs/zstd.1.md b/programs/zstd.1.md index e5c1b7fd215..e602c106990 100644 --- a/programs/zstd.1.md +++ b/programs/zstd.1.md @@ -387,6 +387,18 @@ The list of available _options_: Note: If `windowLog` is set to larger than 27, `--long=windowLog` or `--memory=windowSize` needs to be passed to the decompressor. +- `windowFrac`=_wfrac_, `wfrac`=_wfrac_: + Set the window size to a non-power-of-two value, as an adjustment to the + power-of-two window size set by the `windowLog` parameter. + + The Zstd format supports expressing window sizes as + `(1 + wfrac / 8) * (2 ^ wlog)` where `wfrac` has an integer value between + 0 and 7 inclusive and `wlog` has an integer value between 10 and 41. + (Although see the documentation on `windowLog` above.) + + This parameter has no effect unless the `windowLog` is also set. It also + has no effect when the `windowLog` is set to its maximum supported value. + - `hashLog`=_hlog_, `hlog`=_hlog_: Specify the maximum number of bits for a hash table. diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 83d9b881e50..03291d59879 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -616,10 +616,11 @@ static unsigned parseAdaptParameters(const char* stringPtr, int* adaptMinPtr, in * @return 1 means that compression parameters were correct * @return 0 in case of malformed parameters */ -static unsigned parseCompressionParameters(const char* stringPtr, ZSTD_compressionParameters* params) +static unsigned parseCompressionParameters(const char* stringPtr, ZSTD_compressionParameters* params, int* windowFrac) { for ( ; ;) { if (longCommandWArg(&stringPtr, "windowLog=") || longCommandWArg(&stringPtr, "wlog=")) { params->windowLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } + if (longCommandWArg(&stringPtr, "windowFrac=") || longCommandWArg(&stringPtr, "wfrac=")) { *windowFrac = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } if (longCommandWArg(&stringPtr, "chainLog=") || longCommandWArg(&stringPtr, "clog=")) { params->chainLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } if (longCommandWArg(&stringPtr, "hashLog=") || longCommandWArg(&stringPtr, "hlog=")) { params->hashLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } if (longCommandWArg(&stringPtr, "searchLog=") || longCommandWArg(&stringPtr, "slog=")) { params->searchLog = readU32FromChar(&stringPtr); if (stringPtr[0]==',') { stringPtr++; continue; } else break; } @@ -878,6 +879,7 @@ int main(int argCount, const char* argv[]) FIO_progressSetting_e progress = FIO_ps_auto; zstd_operation_mode operation = zom_compress; ZSTD_compressionParameters compressionParams; + int windowFrac = 0; int cLevel = init_cLevel(); int cLevelLast = MINCLEVEL - 1; /* lower than minimum */ unsigned recursive = 0; @@ -1076,7 +1078,7 @@ int main(int argCount, const char* argv[]) if (longCommandWArg(&argument, "--block-size")) { NEXT_TSIZE(blockSize); continue; } if (longCommandWArg(&argument, "--maxdict")) { NEXT_UINT32(maxDictSize); continue; } if (longCommandWArg(&argument, "--dictID")) { NEXT_UINT32(dictID); continue; } - if (longCommandWArg(&argument, "--zstd=")) { if (!parseCompressionParameters(argument, &compressionParams)) { badUsage(programName, originalArgument); CLEAN_RETURN(1); } ; cType = FIO_zstdCompression; continue; } + if (longCommandWArg(&argument, "--zstd=")) { if (!parseCompressionParameters(argument, &compressionParams, &windowFrac)) { badUsage(programName, originalArgument); CLEAN_RETURN(1); } ; cType = FIO_zstdCompression; continue; } if (longCommandWArg(&argument, "--stream-size")) { NEXT_TSIZE(streamSrcSize); continue; } if (longCommandWArg(&argument, "--target-compressed-block-size")) { NEXT_TSIZE(targetCBlockSize); continue; } if (longCommandWArg(&argument, "--size-hint")) { NEXT_TSIZE(srcSizeHint); continue; } @@ -1600,6 +1602,7 @@ int main(int argCount, const char* argv[]) FIO_setSrcSizeHint(prefs, srcSizeHint); FIO_setLiteralCompressionMode(prefs, literalCompressionMode); FIO_setSparseWrite(prefs, 0); + FIO_setWindowFrac(prefs, windowFrac); if (adaptMin > cLevel) cLevel = adaptMin; if (adaptMax < cLevel) cLevel = adaptMax; diff --git a/tests/cli-tests/compression/window-frac.sh b/tests/cli-tests/compression/window-frac.sh new file mode 100755 index 00000000000..507f6036480 --- /dev/null +++ b/tests/cli-tests/compression/window-frac.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +set -e + +zstd --zstd=wlog=21,wfrac=5 < file > file.zst +zstd -vv -l file.zst diff --git a/tests/cli-tests/compression/window-frac.sh.stderr.ignore b/tests/cli-tests/compression/window-frac.sh.stderr.ignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/cli-tests/compression/window-frac.sh.stdout.glob b/tests/cli-tests/compression/window-frac.sh.stdout.glob new file mode 100644 index 00000000000..d26dbedfa06 --- /dev/null +++ b/tests/cli-tests/compression/window-frac.sh.stdout.glob @@ -0,0 +1,5 @@ +file.zst +# Zstandard Frames: 1 +... +Window Size: 3407872 B (3407872 B) +... \ No newline at end of file diff --git a/tests/fuzz/sequence_compression_api.c b/tests/fuzz/sequence_compression_api.c index 9295d248ccd..f2ad92a7b11 100644 --- a/tests/fuzz/sequence_compression_api.c +++ b/tests/fuzz/sequence_compression_api.c @@ -142,10 +142,11 @@ static size_t decodeSequences(void* dst, size_t nbSequences, */ static size_t generateRandomSequences(FUZZ_dataProducer_t* producer, size_t literalsSizeLimit, size_t dictSize, - size_t windowLog, ZSTD_SequenceFormat_e mode) + uint32_t windowLog, uint32_t windowFrac, + ZSTD_SequenceFormat_e mode) { const uint32_t repCode = 0; /* not used by sequence ingestion api */ - size_t windowSize = 1ULL << windowLog; + uint64_t windowSize = ((8ULL + windowFrac) << windowLog) >> 3; size_t blockSizeMax = MIN(ZSTD_BLOCKSIZE_MAX, windowSize); uint32_t matchLengthMax = ZSTD_FUZZ_MATCHLENGTH_MAXSIZE; uint32_t bytesGenerated = 0; @@ -346,6 +347,7 @@ int LLVMFuzzerTestOneInput(const uint8_t* src, size_t size) size_t dictSize = 0; unsigned hasDict; unsigned wLog; + unsigned wFrac; int cLevel; ZSTD_SequenceFormat_e mode; @@ -361,8 +363,12 @@ int LLVMFuzzerTestOneInput(const uint8_t* src, size_t size) FUZZ_ASSERT(dctx); } - /* Generate window log first so we don't generate offsets too large */ + /* Generate window size first so we don't generate offsets too large */ wLog = FUZZ_dataProducer_uint32Range(producer, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); + wFrac = FUZZ_dataProducer_uint32Range(producer, 0, 7); + if (wLog == ZSTD_WINDOWLOG_MAX) { + wFrac = 0; + } cLevel = FUZZ_dataProducer_int32Range(producer, -3, 22); mode = (ZSTD_SequenceFormat_e)FUZZ_dataProducer_int32Range(producer, 0, 1); @@ -370,6 +376,7 @@ int LLVMFuzzerTestOneInput(const uint8_t* src, size_t size) ZSTD_CCtx_setParameter(cctx, ZSTD_c_nbWorkers, 0); ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, cLevel); ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, (int)wLog); + ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowFrac, (int)wFrac); ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, ZSTD_MINMATCH_MIN); ZSTD_CCtx_setParameter(cctx, ZSTD_c_validateSequences, 1); ZSTD_CCtx_setParameter(cctx, ZSTD_c_blockDelimiters, (int)mode); @@ -415,7 +422,7 @@ int LLVMFuzzerTestOneInput(const uint8_t* src, size_t size) generatedSrc = FUZZ_malloc(ZSTD_FUZZ_GENERATED_SRC_MAXSIZE); } - nbSequences = generateRandomSequences(producer, ZSTD_FUZZ_GENERATED_LITERALS_SIZE, dictSize, wLog, mode); + nbSequences = generateRandomSequences(producer, ZSTD_FUZZ_GENERATED_LITERALS_SIZE, dictSize, wLog, wFrac, mode); generatedSrcSize = decodeSequences(generatedSrc, nbSequences, ZSTD_FUZZ_GENERATED_LITERALS_SIZE, dictBuffer, dictSize, mode); /* Note : in explicit block delimiters mode, diff --git a/tests/fuzz/zstd_helpers.c b/tests/fuzz/zstd_helpers.c index f3b2e6fba4c..755b81b6c26 100644 --- a/tests/fuzz/zstd_helpers.c +++ b/tests/fuzz/zstd_helpers.c @@ -102,6 +102,7 @@ void FUZZ_setRandomParameters(ZSTD_CCtx *cctx, size_t srcSize, FUZZ_dataProducer { ZSTD_compressionParameters cParams = FUZZ_randomCParams(srcSize, producer); set(cctx, ZSTD_c_windowLog, cParams.windowLog); + setRand(cctx, ZSTD_c_windowFrac, 0, 7, producer); set(cctx, ZSTD_c_hashLog, cParams.hashLog); set(cctx, ZSTD_c_chainLog, cParams.chainLog); set(cctx, ZSTD_c_searchLog, cParams.searchLog); diff --git a/tests/fuzzer.c b/tests/fuzzer.c index b74460bb573..213cfd9ba90 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -43,6 +43,7 @@ #include "timefn.h" /* SEC_TO_MICRO, UTIL_time_t, UTIL_TIME_INITIALIZER, UTIL_clockSpanMicro, UTIL_getTime */ /* must be included after util.h, due to ERROR macro redefinition issue on Visual Studio */ #include "zstd_internal.h" /* ZSTD_WORKSPACETOOLARGE_MAXDURATION, ZSTD_WORKSPACETOOLARGE_FACTOR, KB, MB */ +#include "zstd_compress_internal.h" /* ZSTD_WINDOW_ALLOW_PICKING_FRACTIONAL_SIZES */ #include "threading.h" /* ZSTD_pthread_create, ZSTD_pthread_join */ @@ -707,8 +708,8 @@ static int basicUnitTests(U32 const seed, double compressibility) params.hashLog = 19; params.chainLog = 19; params = ZSTD_adjustCParams(params, 1000, 100000); - if (params.hashLog != 18) goto _output_error; - if (params.chainLog != 17) goto _output_error; + CHECK_EQ(params.chainLog, 17); + CHECK_EQ(params.hashLog, 18); } DISPLAYLEVEL(3, "OK \n"); @@ -1771,6 +1772,8 @@ static int basicUnitTests(U32 const seed, double compressibility) CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_windowLog, &value)); CHECK_EQ(value, 0); + CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_windowFrac, &value)); + CHECK_EQ(value, 0); CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_chainLog, &value)); CHECK_EQ(value, 0); CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_hashLog, &value)); @@ -1789,6 +1792,8 @@ static int basicUnitTests(U32 const seed, double compressibility) CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_windowLog, &value)); CHECK_EQ(value, (int)cparams.windowLog); + CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_windowFrac, &value)); + CHECK_EQ(value, 0); CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_chainLog, &value)); CHECK_EQ(value, (int)cparams.chainLog); CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_hashLog, &value)); @@ -1839,6 +1844,8 @@ static int basicUnitTests(U32 const seed, double compressibility) CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_windowLog, &value)); CHECK_EQ(value, 0); + CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_windowFrac, &value)); + CHECK_EQ(value, 0); CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_chainLog, &value)); CHECK_EQ(value, 0); CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_hashLog, &value)); @@ -1866,6 +1873,8 @@ static int basicUnitTests(U32 const seed, double compressibility) CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_windowLog, &value)); CHECK_EQ(value, (int)params.cParams.windowLog); + CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_windowFrac, &value)); + CHECK_EQ(value, 0); CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_chainLog, &value)); CHECK_EQ(value, (int)params.cParams.chainLog); CHECK_Z(ZSTD_CCtx_getParameter(cctx, ZSTD_c_hashLog, &value)); @@ -3377,6 +3386,108 @@ static int basicUnitTests(U32 const seed, double compressibility) } DISPLAYLEVEL(3, "OK \n"); + DISPLAYLEVEL(3, "test%3i : check fractional window sizes : \n", testNb++); + { + int windowLog; + int windowFrac; + + for (windowLog = 0; windowLog <= ZSTD_WINDOWLOG_MAX; windowLog++) { + if (windowLog == 1) { + windowLog = ZSTD_WINDOWLOG_MIN; + } + for (windowFrac = 0; windowFrac <= 7; windowFrac++) { + int hint; + for (hint = 0; hint <= 1; hint++) { + unsigned long long inputSize; + for (inputSize = 100; inputSize < (3ull << ZSTD_WINDOWLOG_MAX); inputSize += (1ull << (ZSTD_highbit32((U32)(inputSize >> 4))))) { + ZSTD_inBuffer input = {CNBuffer, CNBuffSize, 0}; + ZSTD_outBuffer compressed = {compressedBuffer, compressedBufferSize, 0}; + ZSTD_FrameHeader zfh; + unsigned long long maxWindowSize; + + DISPLAYLEVEL(5, + "Checking %s input = 0x%16llx, windowLog = %2d, windowFrac = %d: ", + hint ? "hinted" : " fixed", + inputSize, windowLog, windowFrac); + + if (input.size > 16) { + /* We don't have to compress too much. */ + input.size = 16; + } + if (input.size > inputSize) { + input.size = (size_t)inputSize; + } + + ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters); + CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, 1)); + CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, windowLog)); + CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowFrac, windowFrac)); + if (hint) { + if (inputSize >= (1ull << 31)) { + CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_srcSizeHint, (int)((1ull << 31) - 1))); + } else { + CHECK_Z(ZSTD_CCtx_setParameter(cctx, ZSTD_c_srcSizeHint, (int)inputSize)); + } + } else { + CHECK_Z(ZSTD_CCtx_setPledgedSrcSize(cctx, inputSize)); + } + + CHECK_Z(ZSTD_compressStream2(cctx, &compressed, &input, inputSize == 0 ? ZSTD_e_end : ZSTD_e_flush)); + CHECK_LT(0, compressed.size); + + CHECK_Z(ZSTD_getFrameHeader(&zfh, compressed.dst, compressed.pos)); + if (!hint) { + CHECK_EQ(zfh.frameContentSize, inputSize); + } + + DISPLAYLEVEL(5, + "got frame size = 0x%16llx, window size = 0x%8llx, ", + zfh.frameContentSize, zfh.windowSize); + + maxWindowSize = 1ull << ZSTD_WINDOWLOG_MAX; + + if (windowLog != 0 && maxWindowSize > (1ull << windowLog)) { + maxWindowSize = ((8ull + windowFrac) << windowLog) >> 3; + } + + if (!hint) { + if (maxWindowSize > inputSize) { + maxWindowSize = inputSize; + } + } else { + int winLogAndFrac; + for (winLogAndFrac = ZSTD_WINDOWLOG_MIN << 3; winLogAndFrac < (ZSTD_WINDOWLOG_MAX << 3); winLogAndFrac++) { + unsigned long long candidateWindowSize = ((8ull + (winLogAndFrac & 7)) << (winLogAndFrac >> 3)) >> 3; + if (candidateWindowSize >= inputSize && (windowLog == 0 || maxWindowSize > candidateWindowSize)) { + maxWindowSize = candidateWindowSize; + break; + } +#if !ZSTD_WINDOW_ALLOW_PICKING_FRACTIONAL_SIZES + winLogAndFrac += 7; /* skip over fractional windows */ +#endif + } + } + + if (hint && (maxWindowSize < (1ull << ZSTD_WINDOWLOG_MIN))) { + maxWindowSize = 1ull << ZSTD_WINDOWLOG_MIN; + } + + DISPLAYLEVEL(5, + "expected window size = 0x%16llx\n", + maxWindowSize); + + if (windowLog != 0) { + CHECK_EQ(zfh.windowSize, maxWindowSize); + } else { + CHECK_LT(zfh.windowSize, maxWindowSize + 1); + } + } + } + } + } + } + DISPLAYLEVEL(3, "OK \n"); + ZSTD_freeCCtx(cctx); free(dictBuffer); free(samplesSizes); @@ -3670,7 +3781,7 @@ static int basicUnitTests(U32 const seed, double compressibility) { ZSTD_CCtx* const cctx = ZSTD_createCCtx(); ZSTD_DCtx* const dctx = ZSTD_createDCtx(); static const size_t dictSize = 65 KB; - static const size_t blockSize = 100 KB; /* won't cause pb with small dict size */ + static const size_t blockSize = 71 KB; /* won't cause pb with small dict size */ size_t cSize2; assert(cctx != NULL); assert(dctx != NULL); @@ -3734,6 +3845,7 @@ static int basicUnitTests(U32 const seed, double compressibility) { ZSTD_CDict* const cdict = ZSTD_createCDict(CNBuffer, dictSize, 3); if (cdict==NULL) goto _output_error; CHECK_Z( ZSTD_compressBegin_usingCDict(cctx, cdict) ); + CHECK_Z( ZSTD_getBlockSize(cctx) >= blockSize); CHECK_Z( ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), (char*)CNBuffer+dictSize, blockSize) ); ZSTD_freeCDict(cdict); }