From c71568fd447320f3b2170af03185dddb55915086 Mon Sep 17 00:00:00 2001 From: inikep Date: Sat, 30 Jan 2016 12:15:56 +0100 Subject: [PATCH 001/113] ZSTD_opt --- .gitignore | 2 ++ lib/zstd_compress.c | 22 +++++++++++++++++++--- lib/zstd_static.h | 4 ++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 8641d7f99..9c7737f4c 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,5 @@ ipch/ # Other files .directory +_codelite +_zstdbench diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 6e3d6ca5a..c2becc5ff 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -153,7 +153,7 @@ static unsigned ZSTD_highbit(U32 val); optimize for srcSize if srcSize > 0 */ void ZSTD_validateParams(ZSTD_parameters* params) { - const U32 btPlus = (params->strategy == ZSTD_btlazy2); + const U32 btPlus = (params->strategy == ZSTD_btlazy2) || (params->strategy == ZSTD_opt_bt); /* validate params */ if (MEM_32bits()) if (params->windowLog > 25) params->windowLog = 25; /* 32 bits mode cannot flush > 24 bits */ @@ -175,7 +175,7 @@ void ZSTD_validateParams(ZSTD_parameters* params) if (params->searchLog < ZSTD_SEARCHLOG_MIN) params->searchLog = ZSTD_SEARCHLOG_MIN; if (params->searchLength> ZSTD_SEARCHLENGTH_MAX) params->searchLength = ZSTD_SEARCHLENGTH_MAX; if (params->searchLength< ZSTD_SEARCHLENGTH_MIN) params->searchLength = ZSTD_SEARCHLENGTH_MIN; - if ((U32)params->strategy>(U32)ZSTD_btlazy2) params->strategy = ZSTD_btlazy2; + if ((U32)params->strategy>(U32)ZSTD_opt_bt) params->strategy = ZSTD_opt_bt; } @@ -1977,7 +1977,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc, /* preemptive overflow correction */ if (zc->lowLimit > (1<<30)) { - U32 btplus = (zc->params.strategy == ZSTD_btlazy2); + U32 btplus = (zc->params.strategy == ZSTD_btlazy2) || (zc->params.strategy == ZSTD_opt_bt); U32 contentMask = (1 << (zc->params.contentLog - btplus)) - 1; U32 newLowLimit = zc->lowLimit & contentMask; /* preserve position % contentSize */ U32 correction = zc->lowLimit - newLowLimit; @@ -2280,6 +2280,10 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 25, 24, 23, 5, 5, ZSTD_btlazy2 }, /* level 18 */ { 0, 25, 26, 23, 5, 5, ZSTD_btlazy2 }, /* level 19 */ { 0, 26, 27, 25, 9, 5, ZSTD_btlazy2 }, /* level 20 */ + { 0, 23, 21, 22, 5, 5, ZSTD_opt }, /* level 21 */ + { 0, 23, 24, 23, 4, 5, ZSTD_opt }, /* level 22 */ + { 0, 25, 26, 23, 5, 5, ZSTD_opt }, /* level 23 */ + { 0, 26, 27, 25, 9, 5, ZSTD_opt }, /* level 24 */ }, { /* for srcSize <= 256 KB */ /* W, C, H, S, L, strat */ @@ -2304,6 +2308,10 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 18, 18, 18, 11, 4, ZSTD_lazy2 }, /* level 18 */ { 0, 18, 18, 18, 12, 4, ZSTD_lazy2 }, /* level 19 */ { 0, 18, 18, 18, 13, 4, ZSTD_lazy2 }, /* level 20 */ + { 0, 18, 18, 18, 10, 4, ZSTD_lazy2 }, /* level 17 */ + { 0, 18, 18, 18, 11, 4, ZSTD_lazy2 }, /* level 18 */ + { 0, 18, 18, 18, 12, 4, ZSTD_lazy2 }, /* level 19 */ + { 0, 18, 18, 18, 13, 4, ZSTD_lazy2 }, /* level 20 */ }, { /* for srcSize <= 128 KB */ /* W, C, H, S, L, strat */ @@ -2328,6 +2336,10 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 17, 18, 16, 9, 4, ZSTD_btlazy2 }, /* level 18 */ { 0, 17, 18, 16, 10, 4, ZSTD_btlazy2 }, /* level 19 */ { 0, 17, 18, 18, 12, 4, ZSTD_btlazy2 }, /* level 20 */ + { 0, 17, 18, 16, 8, 4, ZSTD_btlazy2 }, /* level 17 */ + { 0, 17, 18, 16, 9, 4, ZSTD_btlazy2 }, /* level 18 */ + { 0, 17, 18, 16, 10, 4, ZSTD_btlazy2 }, /* level 19 */ + { 0, 17, 18, 18, 12, 4, ZSTD_btlazy2 }, /* level 20 */ }, { /* for srcSize <= 16 KB */ /* W, C, H, S, L, strat */ @@ -2352,6 +2364,10 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 14, 15, 15, 13, 4, ZSTD_btlazy2 }, /* level 18 */ { 0, 14, 15, 15, 14, 4, ZSTD_btlazy2 }, /* level 19 */ { 0, 14, 15, 15, 15, 4, ZSTD_btlazy2 }, /* level 20 */ + { 0, 14, 15, 15, 12, 4, ZSTD_btlazy2 }, /* level 17 */ + { 0, 14, 15, 15, 13, 4, ZSTD_btlazy2 }, /* level 18 */ + { 0, 14, 15, 15, 14, 4, ZSTD_btlazy2 }, /* level 19 */ + { 0, 14, 15, 15, 15, 4, ZSTD_btlazy2 }, /* level 20 */ }, }; diff --git a/lib/zstd_static.h b/lib/zstd_static.h index de2212d9d..9997d67d9 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -65,7 +65,7 @@ extern "C" { #define ZSTD_SEARCHLENGTH_MIN 4 /** from faster to stronger */ -typedef enum { ZSTD_fast, ZSTD_greedy, ZSTD_lazy, ZSTD_lazy2, ZSTD_btlazy2 } ZSTD_strategy; +typedef enum { ZSTD_fast, ZSTD_greedy, ZSTD_lazy, ZSTD_lazy2, ZSTD_btlazy2, ZSTD_opt, ZSTD_opt_bt } ZSTD_strategy; typedef struct { @@ -243,7 +243,7 @@ size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const /* ************************************* * Pre-defined compression levels ***************************************/ -#define ZSTD_MAX_CLEVEL 20 +#define ZSTD_MAX_CLEVEL 24 ZSTDLIB_API unsigned ZSTD_maxCLevel (void); From e2bfe2407a580e212990635355d8e10ba8f2e716 Mon Sep 17 00:00:00 2001 From: inikep Date: Sun, 31 Jan 2016 11:25:48 +0100 Subject: [PATCH 002/113] GetAllMatches --- lib/zstd_compress.c | 40 +- lib/zstd_opt.c | 1329 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1360 insertions(+), 9 deletions(-) create mode 100644 lib/zstd_opt.c diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index c2becc5ff..c0fce45f5 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -1654,6 +1654,18 @@ _storeSequence: } } +#include "zstd_opt.c" + +static void ZSTD_compressBlock_opt_bt(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +{ + ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1, 2); +} + +static void ZSTD_compressBlock_opt(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +{ + ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0, 2); +} + static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2); @@ -1868,14 +1880,24 @@ static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2); } +static void ZSTD_compressBlock_opt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +{ + ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2); +} + +static void ZSTD_compressBlock_opt_bt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) +{ + ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2); +} + typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize); static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict) { - static const ZSTD_blockCompressor blockCompressor[2][5] = { - { ZSTD_compressBlock_fast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy,ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2 }, - { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict } + static const ZSTD_blockCompressor blockCompressor[2][7] = { + { ZSTD_compressBlock_fast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy,ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_opt, ZSTD_compressBlock_opt_bt }, + { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict, ZSTD_compressBlock_opt_extDict, ZSTD_compressBlock_opt_bt_extDict } }; return blockCompressor[extDict][(U32)strat]; @@ -2270,20 +2292,20 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 21, 19, 20, 3, 5, ZSTD_lazy }, /* level 8 */ { 0, 21, 20, 20, 3, 5, ZSTD_lazy2 }, /* level 9 */ { 0, 21, 19, 21, 4, 5, ZSTD_lazy2 }, /* level 10 */ - { 0, 22, 20, 22, 4, 5, ZSTD_lazy2 }, /* level 11 */ + { 0, 22, 20, 22, 4, 5, ZSTD_lazy2 }, /* level 11 */ // 42498419 { 0, 22, 20, 22, 5, 5, ZSTD_lazy2 }, /* level 12 */ { 0, 22, 21, 22, 5, 5, ZSTD_lazy2 }, /* level 13 */ { 0, 22, 22, 23, 5, 5, ZSTD_lazy2 }, /* level 14 */ { 0, 23, 23, 23, 5, 5, ZSTD_lazy2 }, /* level 15 */ - { 0, 23, 21, 22, 5, 5, ZSTD_btlazy2 }, /* level 16 */ + { 0, 23, 21, 22, 5, 5, ZSTD_btlazy2 }, /* level 16 */ // 42113689 { 0, 23, 24, 23, 4, 5, ZSTD_btlazy2 }, /* level 17 */ { 0, 25, 24, 23, 5, 5, ZSTD_btlazy2 }, /* level 18 */ { 0, 25, 26, 23, 5, 5, ZSTD_btlazy2 }, /* level 19 */ { 0, 26, 27, 25, 9, 5, ZSTD_btlazy2 }, /* level 20 */ - { 0, 23, 21, 22, 5, 5, ZSTD_opt }, /* level 21 */ - { 0, 23, 24, 23, 4, 5, ZSTD_opt }, /* level 22 */ - { 0, 25, 26, 23, 5, 5, ZSTD_opt }, /* level 23 */ - { 0, 26, 27, 25, 9, 5, ZSTD_opt }, /* level 24 */ + { 0, 22, 20, 22, 4, 4, ZSTD_lazy2 }, /* level 11 + L=4 */ // 41902762 + { 0, 23, 21, 22, 5, 4, ZSTD_btlazy2 }, /* level 16 + L=4 */ // 41233150 + { 0, 23, 21, 22, 5, 4, ZSTD_opt }, /* level 23 */ + { 0, 23, 21, 22, 5, 4, ZSTD_opt_bt }, /* level 23 */ }, { /* for srcSize <= 256 KB */ /* W, C, H, S, L, strat */ diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c new file mode 100644 index 000000000..caef8065d --- /dev/null +++ b/lib/zstd_opt.c @@ -0,0 +1,1329 @@ +typedef struct +{ + int off; + int len; + int back; +} LZ5HC_match_t; + +typedef struct +{ + int price; + int off; + int mlen; + int litlen; + int rep; +} LZ5HC_optimal_t; + + +#define LZ5HC_DEBUG(fmt, args...) ;//printf(fmt, ##args) +#define LZ5_LOG_PARSER(fmt, args...) ;//printf(fmt, ##args) +#define LZ5_LOG_PRICE(fmt, args...) ;//printf(fmt, ##args) +#define LZ5_LOG_ENCODE(fmt, args...) ;//printf(fmt, ##args) + +#define LZ5_OPT_NUM (1<<12) + +#define LZ5_SHORT_OFFSET_BITS 10 +#define LZ5_SHORT_OFFSET_DISTANCE (1< LZ5_MID_OFFSET_DISTANCE) || (offsethashTable; + const U32 hashLog = zc->params.hashLog; + const size_t h = ZSTD_hashPtr(ip, hashLog, mls); + U32* const bt = zc->contentTable; + const U32 btLog = zc->params.contentLog - 1; + const U32 btMask= (1 << btLog) - 1; + U32 matchIndex = hashTable[h]; + size_t commonLengthSmaller=0, commonLengthLarger=0; + const BYTE* const base = zc->base; + const BYTE* const dictBase = zc->dictBase; + const U32 dictLimit = zc->dictLimit; + const BYTE* const dictEnd = dictBase + dictLimit; + const BYTE* const prefixStart = base + dictLimit; + const U32 current = (U32)(ip-base); + const U32 btLow = btMask >= current ? 0 : current - btMask; + const U32 windowLow = zc->lowLimit; + U32* smallerPtr = bt + 2*(current&btMask); + U32* largerPtr = bt + 2*(current&btMask) + 1; + size_t bestLength = 0; + U32 matchEndIdx = current+8; + U32 dummy32; /* to be nullified at the end */ + size_t mnum = 0; + + hashTable[h] = current; /* Update Hash Table */ + + while (nbCompares-- && (matchIndex > windowLow)) { + U32* nextPtr = bt + 2*(matchIndex & btMask); + size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ + const BYTE* match; + + if ((!extDict) || (matchIndex+matchLength >= dictLimit)) { + match = base + matchIndex; + if (match[matchLength] == ip[matchLength]) + matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1; + } else { + match = dictBase + matchIndex; + matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart); + if (matchIndex+matchLength >= dictLimit) + match = base + matchIndex; /* to prepare for next usage of match[matchLength] */ + } + + if (matchLength > bestLength) { + if (matchLength > matchEndIdx - matchIndex) + matchEndIdx = matchIndex + (U32)matchLength; +#if 0 + if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) ) + bestLength = matchLength, *offsetPtr = current - matchIndex; +#else + if (mnum == 0 || (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)matches[mnum-1].off+1)) ) + { + bestLength = matchLength; + matches[mnum].off = current - matchIndex; + matches[mnum].len = matchLength; + matches[mnum].back = 0; + mnum++; + if (matchLength > LZ5_OPT_NUM) break; + } +#endif + if (ip+matchLength == iend) /* equal : no way to know if inf or sup */ + break; /* drop, to guarantee consistency (miss a little bit of compression) */ + } + + if (match[matchLength] < ip[matchLength]) { + /* match is smaller than current */ + *smallerPtr = matchIndex; /* update smaller idx */ + commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */ + if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */ + smallerPtr = nextPtr+1; /* new "smaller" => larger of match */ + matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */ + } else { + /* match is larger than current */ + *largerPtr = matchIndex; + commonLengthLarger = matchLength; + if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */ + largerPtr = nextPtr; + matchIndex = nextPtr[0]; + } + } + + *smallerPtr = *largerPtr = 0; + + zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1; + return mnum; +} + + +/** Tree updater, providing best match */ +FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ +size_t ZSTD_BtGetAllMatches ( + ZSTD_CCtx* zc, + const BYTE* const ip, const BYTE* const iLimit, + const U32 maxNbAttempts, const U32 mls, LZ5HC_match_t* matches) +{ + if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */ + ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls); + return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 0, matches); +} + + +FORCE_INLINE size_t ZSTD_BtGetAllMatches_selectMLS ( + ZSTD_CCtx* zc, /* Index table will be updated */ + const BYTE* ip, const BYTE* const iLimit, + const U32 maxNbAttempts, const U32 matchLengthSearch, LZ5HC_match_t* matches) +{ + switch(matchLengthSearch) + { + default : + case 4 : return ZSTD_BtGetAllMatches(zc, ip, iLimit, maxNbAttempts, 4, matches); + case 5 : return ZSTD_BtGetAllMatches(zc, ip, iLimit, maxNbAttempts, 5, matches); + case 6 : return ZSTD_BtGetAllMatches(zc, ip, iLimit, maxNbAttempts, 6, matches); + } +} + + +FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ +size_t ZSTD_HcGetAllMatches_generic ( + ZSTD_CCtx* zc, /* Index table will be updated */ + const BYTE* const ip, const BYTE* const iLimit, + const U32 maxNbAttempts, const U32 mls, const U32 extDict, LZ5HC_match_t* matches) +{ + U32* const chainTable = zc->contentTable; + const U32 chainSize = (1 << zc->params.contentLog); + const U32 chainMask = chainSize-1; + const BYTE* const base = zc->base; + const BYTE* const dictBase = zc->dictBase; + const U32 dictLimit = zc->dictLimit; + const BYTE* const prefixStart = base + dictLimit; + const BYTE* const dictEnd = dictBase + dictLimit; + const U32 lowLimit = zc->lowLimit; + const U32 current = (U32)(ip-base); + const U32 minChain = current > chainSize ? current - chainSize : 0; + U32 matchIndex; + const BYTE* match; + int nbAttempts=maxNbAttempts; + size_t ml=MINMATCH-1; + size_t mnum = 0; + + /* HC4 match finder */ + matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls); + + while ((matchIndex>lowLimit) && (nbAttempts)) { + size_t currentMl=0; + nbAttempts--; + if ((!extDict) || matchIndex >= dictLimit) { + match = base + matchIndex; + if (match[ml] == ip[ml]) /* potentially better */ + currentMl = ZSTD_count(ip, match, iLimit); + } else { + match = dictBase + matchIndex; + if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */ + currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH; + } + + /* save best solution */ + if (currentMl > ml) { + ml = currentMl; + matches[mnum].off = current - matchIndex; + matches[mnum].len = currentMl; + matches[mnum].back = 0; + mnum++; + if (currentMl > LZ5_OPT_NUM) break; + if (ip+currentMl == iLimit) break; /* best possible, and avoid read overflow*/ + } + + if (matchIndex <= minChain) break; + matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask); + } + + return mnum; +} + + +FORCE_INLINE size_t ZSTD_HcGetAllMatches_selectMLS ( + ZSTD_CCtx* zc, + const BYTE* ip, const BYTE* const iLimit, + const U32 maxNbAttempts, const U32 matchLengthSearch, LZ5HC_match_t* matches) +{ + switch(matchLengthSearch) + { + default : + case 4 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLimit, maxNbAttempts, 4, 0, matches); + case 5 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLimit, maxNbAttempts, 5, 0, matches); + case 6 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLimit, maxNbAttempts, 6, 0, matches); + } +} + + + +/* ******************************* +* Common parser - lazy strategy +*********************************/ +FORCE_INLINE +void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, + const void* src, size_t srcSize, + const U32 searchMethod, const U32 depth) +{ + seqStore_t* seqStorePtr = &(ctx->seqStore); + const BYTE* const istart = (const BYTE*)src; + const BYTE* ip = istart; + const BYTE* anchor = istart; + const BYTE* const iend = istart + srcSize; + const BYTE* const ilimit = iend - 8; + const BYTE* const base = ctx->base + ctx->dictLimit; + + size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE; + const U32 maxSearches = 1 << ctx->params.searchLog; + const U32 mls = ctx->params.searchLength; + + typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, + size_t* offsetPtr, + U32 maxNbAttempts, U32 matchLengthSearch); + typedef size_t (*getAllMatches_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, + U32 maxNbAttempts, U32 matchLengthSearch, LZ5HC_match_t* matches); + searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS; + getAllMatches_f getAllMatches = searchMethod ? ZSTD_BtGetAllMatches_selectMLS : ZSTD_HcGetAllMatches_selectMLS; + + LZ5HC_match_t matches[LZ5_OPT_NUM+1]; + + /* init */ + ZSTD_resetSeqStore(seqStorePtr); + if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE; + + /* Match Loop */ + while (ip < ilimit) { + size_t matchLength=0; + size_t offset=0; + const BYTE* start=ip+1; + +#if 1 + /* check repCode */ + if (MEM_read32(start) == MEM_read32(start - offset_1)) { + /* repcode : we take it */ + matchLength = ZSTD_count(start+MINMATCH, start+MINMATCH-offset_1, iend) + MINMATCH; + if (depth==0) goto _storeSequence; + } +#endif + + { + /* first search (depth 0) */ +#if 0 + size_t offsetFound = 99999999; + size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls); + if (ml2 > matchLength) + matchLength = ml2, start = ip, offset=offsetFound; +#else + size_t mnum = getAllMatches(ctx, ip, iend, maxSearches, mls, matches); + if (mnum > 0) { + if (matches[mnum-1].len > matchLength) + matchLength = matches[mnum-1].len, start = ip, offset=matches[mnum-1].off; + } +#endif + } + + if (matchLength < MINMATCH) { + // ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */ + ip++; + continue; + } + + /* let's try to find a better solution */ + if (depth>=1) + while (ip= MINMATCH) && (gain2 > gain1)) + matchLength = mlRep, offset = 0, start = ip; + } + { + size_t offset2=999999; + size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls); + int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */ + int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4); + if ((ml2 >= MINMATCH) && (gain2 > gain1)) { + matchLength = ml2, offset = offset2, start = ip; + continue; /* search a better one */ + } } + + break; /* nothing found : store previous solution */ + } + + /* catch up */ + if (offset) { + while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) /* only search for offset within prefix */ + { start--; matchLength++; } + offset_2 = offset_1; offset_1 = offset; + } + + /* store sequence */ +_storeSequence: + { + size_t litLength = start - anchor; + ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH); + anchor = ip = start + matchLength; + } + +#if 1 /* check immediate repcode */ + while ( (ip <= ilimit) + && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) { + /* store sequence */ + matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend); + offset = offset_2; + offset_2 = offset_1; + offset_1 = offset; + ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength); + ip += matchLength+MINMATCH; + anchor = ip; + continue; /* faster when present ... (?) */ + } +#endif + } + + /* Last Literals */ + { + size_t lastLLSize = iend - anchor; + memcpy(seqStorePtr->lit, anchor, lastLLSize); + seqStorePtr->lit += lastLLSize; + } +} + +#if 0 +/* ******************************* +* Optimal parser +*********************************/ +FORCE_INLINE +void ZSTD_compressBlock_opt2_generic(ZSTD_CCtx* ctx, + const void* src, size_t srcSize, + const U32 searchMethod, const U32 depth) +{ + seqStore_t* seqStorePtr = &(ctx->seqStore); + const BYTE* const istart = (const BYTE*)src; + const BYTE* ip = istart; + const BYTE* anchor = istart; + const BYTE* const iend = istart + srcSize; + const BYTE* const ilimit = iend - 8; + const BYTE* const base = ctx->base + ctx->dictLimit; + + size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE; + const U32 maxSearches = 1 << ctx->params.searchLog; + const U32 mls = ctx->params.searchLength; + + typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, + size_t* offsetPtr, + U32 maxNbAttempts, U32 matchLengthSearch); + searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS; + + /* init */ + ZSTD_resetSeqStore(seqStorePtr); + if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE; + + LZ5HC_optimal_t opt[LZ5_OPT_NUM+4]; + LZ5HC_match_t matches[LZ5_OPT_NUM+1]; + const uint8_t *inr; + int res, cur, cur2, cur_min, skip_num = 0; + int rep = 1, llen, litlen, mlen, best_mlen, price, offset, best_off, match_num, last_pos; + + const int sufficient_len = 64; //ctx->params.sufficientLength; + const bool faster_get_matches = (ctx->params.strategy == ZSTD_opt); + + + /* Match Loop */ + while (ip < ilimit) { + size_t mlen=0; + size_t offset=0; + const BYTE* start=ip+1; + + memset(opt, 0, sizeof(LZ5HC_optimal_t)); + last_pos = 0; + llen = ip - anchor; + inr = ip; + + + /* check repCode */ + if (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1)) { + /* repcode : we take it */ + mlen = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend) + MINMATCH; + + LZ5_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)((char*)ip-source), rep, mlen); + if (mlen > sufficient_len || mlen >= LZ5_OPT_NUM) + { + best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; + goto _storeSequence; + } + + do + { + litlen = 0; + price = LZ5HC_get_price(llen, 0, mlen - MINMATCH) - llen; + if (mlen > last_pos || price < opt[mlen].price) + SET_PRICE(mlen, mlen, 0, litlen, price); + mlen--; + } + while (mlen >= MINMATCH); + + if (depth==0) goto _storeSequence; + } + +/* + { + // first search (depth 0) + size_t offsetFound = 99999999; + size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls); + if (ml2 > mlen) + mlen = ml2, start = ip, offset=offsetFound; + } +*/ +/* + if (mlen < MINMATCH) { + ip += ((ip-anchor) >> g_searchStrength) + 1; // jump faster over incompressible sections + continue; + } +*/ +/* // let's try to find a better solution + if (depth>=1) + while (ip= MINMATCH) && (gain2 > gain1)) + mlen = mlRep, offset = 0, start = ip; + } + { + size_t offset2=999999; + size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls); + int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); // raw approx + int gain1 = (int)(mlen*4 - ZSTD_highbit((U32)offset+1) + 4); + if ((ml2 >= MINMATCH) && (gain2 > gain1)) { + mlen = ml2, offset = offset2, start = ip; + continue; // search a better one + } } + + break; // nothing found : store previous solution + } +*/ + + best_mlen = (last_pos) ? last_pos : MINMATCH; + + if (faster_get_matches && last_pos) + match_num = 0; + else + { + if (ctx->params.strategy == LZ5HC_optimal_price) + { + LZ5HC_Insert(ctx, ip); + match_num = LZ5HC_GetAllMatches(ctx, ip, ip, matchlimit, best_mlen, matches); + } + else + { + LZ5HC_BinTree_Insert(ctx, ip); + match_num = LZ5HC_BinTree_GetAllMatches(ctx, ip, matchlimit, best_mlen, matches); + } + } + + LZ5_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)((char*)ip-source), match_num, last_pos); + if (!last_pos && !match_num) { ip++; continue; } + + if (match_num && matches[match_num-1].len > sufficient_len) + { + best_mlen = matches[match_num-1].len; + best_off = matches[match_num-1].off; + cur = 0; + last_pos = 1; + goto encode; + } + + // set prices using matches at position = 0 + for (int i = 0; i < match_num; i++) + { + mlen = (i>0) ? matches[i-1].len+1 : best_mlen; + best_mlen = (matches[i].len < LZ5_OPT_NUM) ? matches[i].len : LZ5_OPT_NUM; + LZ5_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)((char*)ip-source), matches[i].len, matches[i].off, best_mlen, last_pos); + while (mlen <= best_mlen) + { + litlen = 0; + price = LZ5HC_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - llen; + if (mlen > last_pos || price < opt[mlen].price) + SET_PRICE(mlen, mlen, matches[i].off, litlen, price); + mlen++; + } + } + + if (!last_pos) { ip++; continue; } + + opt[0].rep = rep; + opt[0].mlen = 1; + + // check further positions + for (skip_num = 0, cur = 1; cur <= last_pos; cur++) + { + inr = ip + cur; + + if (opt[cur-1].mlen == 1) + { + litlen = opt[cur-1].litlen + 1; + + if (cur != litlen) + { + price = opt[cur - litlen].price + LZ5_LIT_ONLY_COST(litlen); + LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)((char*)inr-source), cur - litlen, opt[cur - litlen].price, price, cur, litlen); + } + else + { + price = LZ5_LIT_ONLY_COST(llen + litlen) - llen; + LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)((char*)inr-source), price, cur, litlen, llen); + } + } + else + { + litlen = 1; + price = opt[cur - 1].price + LZ5_LIT_ONLY_COST(litlen); + LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)((char*)inr-source), price, cur, litlen, LZ5_LIT_ONLY_COST(litlen)); + } + + mlen = 1; + best_mlen = 0; + LZ5_LOG_PARSER("%d: TRY price=%d opt[%d].price=%d\n", (int)((char*)inr-source), price, cur, opt[cur].price); + + if (cur > last_pos || price <= opt[cur].price) // || ((price == opt[cur].price) && (opt[cur-1].mlen == 1) && (cur != litlen))) + SET_PRICE(cur, mlen, best_mlen, litlen, price); + + if (cur == last_pos) break; + + if (opt[cur].mlen > 1) + { + mlen = opt[cur].mlen; + offset = opt[cur].off; + if (offset < 1) + { + opt[cur].rep = opt[cur-mlen].rep; + LZ5_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d\n", (int)((char*)inr-source), cur, mlen, opt[cur-mlen].rep); + } + else + { + opt[cur].rep = offset; + LZ5_LOG_PARSER("%d: COPYREP2 cur=%d offset=%d rep=%d\n", (int)((char*)inr-source), cur, offset, opt[cur].rep); + } + } + else + { + opt[cur].rep = opt[cur-1].rep; // copy rep + } + + + LZ5_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)inr-source), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); + + // check rep + // best_mlen = 0; + mlen = MEM_count(inr, inr - opt[cur].rep, matchlimit); + if (mlen >= MINMATCH && mlen > best_mlen) + { + LZ5_LOG_PARSER("%d: try REP rep=%d mlen=%d\n", (int)((char*)inr-source), opt[cur].rep, mlen); + LZ5_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)((char*)inr-source), mlen, 0, opt[cur].rep, cur, opt[cur].off); + + if (mlen > sufficient_len || cur + mlen >= LZ5_OPT_NUM) + { + best_mlen = mlen; + best_off = 0; + LZ5_LOG_PARSER("%d: REP sufficient_len=%d best_mlen=%d best_off=%d last_pos=%d\n", (int)((char*)inr-source), sufficient_len, best_mlen, best_off, last_pos); + last_pos = cur + 1; + goto encode; + } + + if (opt[cur].mlen == 1) + { + litlen = opt[cur].litlen; + + if (cur != litlen) + { + price = opt[cur - litlen].price + LZ5HC_get_price(litlen, 0, mlen - MINMATCH); + LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)((char*)inr-source), cur - litlen, opt[cur - litlen].price, price, cur, litlen); + } + else + { + price = LZ5HC_get_price(llen + litlen, 0, mlen - MINMATCH) - llen; + LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)((char*)inr-source), price, cur, litlen, llen); + } + } + else + { + litlen = 0; + price = opt[cur].price + LZ5HC_get_price(litlen, 0, mlen - MINMATCH); + LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d getprice=%d\n", (int)((char*)inr-source), price, cur, litlen, LZ5HC_get_price(litlen, 0, mlen - MINMATCH)); + } + + best_mlen = mlen; + if (faster_get_matches) + skip_num = best_mlen; + + LZ5_LOG_PARSER("%d: Found REP mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)((char*)inr-source), mlen, 0, price, litlen, cur - litlen, opt[cur - litlen].price); + + do + { + if (cur + mlen > last_pos || price <= opt[cur + mlen].price) // || ((price == opt[cur + mlen].price) && (opt[cur].mlen == 1) && (cur != litlen))) // at equal price prefer REP instead of MATCH + SET_PRICE(cur + mlen, mlen, 0, litlen, price); + mlen--; + } + while (mlen >= MINMATCH); + } + + if (faster_get_matches && skip_num > 0) + { + skip_num--; + continue; + } + + + best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; + + if (ctx->params.strategy == LZ5HC_optimal_price) + { + LZ5HC_Insert(ctx, inr); + match_num = LZ5HC_GetAllMatches(ctx, inr, ip, matchlimit, best_mlen, matches); + LZ5_LOG_PARSER("%d: LZ5HC_GetAllMatches match_num=%d\n", (int)((char*)inr-source), match_num); + } + else + { + LZ5HC_BinTree_Insert(ctx, inr); + match_num = LZ5HC_BinTree_GetAllMatches(ctx, inr, matchlimit, best_mlen, matches); + LZ5_LOG_PARSER("%d: LZ5HC_BinTree_GetAllMatches match_num=%d\n", (int)((char*)inr-source), match_num); + } + + + if (match_num > 0 && matches[match_num-1].len > sufficient_len) + { + cur -= matches[match_num-1].back; + best_mlen = matches[match_num-1].len; + best_off = matches[match_num-1].off; + last_pos = cur + 1; + goto encode; + } + + cur_min = cur; + + // set prices using matches at position = cur + for (int i = 0; i < match_num; i++) + { + mlen = (i>0) ? matches[i-1].len+1 : best_mlen; + cur2 = cur - matches[i].back; + best_mlen = (cur2 + matches[i].len < LZ5_OPT_NUM) ? matches[i].len : LZ5_OPT_NUM - cur2; + LZ5_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)((char*)inr-source), cur, cur2, matches[i].len, matches[i].off, best_mlen, last_pos); + + while (mlen <= best_mlen) + { + if (opt[cur2].mlen == 1) + { + litlen = opt[cur2].litlen; + + if (cur2 != litlen) + price = opt[cur2 - litlen].price + LZ5HC_get_price(litlen, matches[i].off, mlen - MINMATCH); + else + price = LZ5HC_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - llen; + } + else + { + litlen = 0; + price = opt[cur2].price + LZ5HC_get_price(litlen, matches[i].off, mlen - MINMATCH); + } + + LZ5_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)((char*)inr-source), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); + if (cur2 + mlen > last_pos || price < opt[cur2 + mlen].price) + { + SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); + + opt[cur2 + mlen].rep = matches[i].off; // update reps + if (cur2 < cur_min) cur_min = cur2; + } + + mlen++; + } + } + + if (cur_min < cur) + { + for (int i=cur_min-1; i<=last_pos; i++) + { + LZ5_LOG_PARSER("%d: BEFORE price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + } + + for (int i=cur_min+1; i<=last_pos; i++) + if (opt[i].price < (1<<30) && (opt[i].off) < 1 && i - opt[i].mlen > cur_min) // invalidate reps + { + if (opt[i-1].mlen == 1) + { + litlen = opt[i-1].litlen + 1; + + if (i != litlen) + { + price = opt[i - litlen].price + LZ5_LIT_ONLY_COST(litlen); + // LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), i - litlen, opt[i - litlen].price, price, i, litlen); + } + else + { + price = LZ5_LIT_ONLY_COST(llen + litlen) - llen; + // LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, i, litlen, llen); + } + } + else + { + litlen = 1; + price = opt[i - 1].price + LZ5_LIT_ONLY_COST(litlen); + // LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d\n", (int)(inr-base), price, i, litlen); + } + + mlen = 1; + best_mlen = 0; + SET_PRICE(i, mlen, best_mlen, litlen, price); + + opt[i].rep = opt[i-1].rep; // copy reps + + LZ5_LOG_PARSER("%d: INVALIDATE pred=%d price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)inr-source), cur-cur_min, i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + } + + for (int i=cur_min-1; i<=last_pos; i++) + { + LZ5_LOG_PARSER("%d: AFTER price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + } + + } + } // for (skip_num = 0, cur = 1; cur <= last_pos; cur++) + + + best_mlen = opt[last_pos].mlen; + best_off = opt[last_pos].off; + cur = last_pos - best_mlen; + + /* catch up */ + if (offset) { + // while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) // only search for offset within prefix + // { start--; mlen++; } + offset_2 = offset_1; offset_1 = offset; + } + + /* store sequence */ +_storeSequence: // cur, last_pos, best_mlen, best_off have to be set + for (int i = 1; i <= last_pos; i++) + { + LZ5_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + } + + LZ5_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)((char*)ip-source+cur), cur, last_pos, best_mlen, best_off, opt[cur].rep); + + opt[0].mlen = 1; + + while (cur >= 0) + { + mlen = opt[cur].mlen; + offset = opt[cur].off; + opt[cur].mlen = best_mlen; + opt[cur].off = best_off; + best_mlen = mlen; + best_off = offset; + cur -= mlen; + } + + for (int i = 0; i <= last_pos;) + { + LZ5_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + i += opt[i].mlen; + } + + cur = 0; + + while (cur < last_pos) + { + LZ5_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); + mlen = opt[cur].mlen; + if (mlen == 1) { ip++; cur++; continue; } + offset = opt[cur].off; + cur += mlen; + + LZ5_LOG_ENCODE("%d: ENCODE literals=%d off=%d mlen=%d ", (int)((char*)ip-source), (int)(ip-anchor), (int)(offset), mlen); + if (offset == 0) + { + res = LZ5HC_encodeSequence(ctx, &ip, &op, &anchor, mlen, ip - rep, limit, oend); + } + else + { + res = LZ5HC_encodeSequence(ctx, &ip, &op, &anchor, mlen, ip - offset, limit, oend); + rep = offset; + } + LZ5_LOG_ENCODE("out=%d\n", (int)((char*)op - dest)); + + if (res) return 0; + + LZ5_LOG_PARSER("%d: offset=%d rep=%d\n", (int)((char*)ip-source), offset, rep); + } + + { + size_t litLength = start - anchor; + ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); + anchor = ip = start + mlen; + } + + /* check immediate repcode */ + while ( (ip <= ilimit) + && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) { + /* store sequence */ + mlen = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend); + offset = offset_2; + offset_2 = offset_1; + offset_1 = offset; + ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, mlen); + ip += mlen+MINMATCH; + anchor = ip; + continue; /* faster when present ... (?) */ + } } + + /* Last Literals */ + { + size_t lastLLSize = iend - anchor; + memcpy(seqStorePtr->lit, anchor, lastLLSize); + seqStorePtr->lit += lastLLSize; + } +} +#endif + + +#if 0 +static int LZ5HC_compress_optimal_price ( + LZ5HC_Data_Structure* ctx, + const char* source, + char* dest, + int inputSize, + int maxOutputSize, + limitedOutput_directive limit + ) +{ + ctx->inputBuffer = (const BYTE*) source; + ctx->outputBuffer = (const BYTE*) dest; + const BYTE* ip = (const BYTE*) source; + const BYTE* anchor = ip; + const BYTE* const iend = ip + inputSize; + const BYTE* const mflimit = iend - MFLIMIT; + const BYTE* const matchlimit = (iend - LASTLITERALS); + BYTE* op = (BYTE*) dest; + BYTE* const oend = op + maxOutputSize; + const int sufficient_len = ctx->params.sufficientLength; + const bool faster_get_matches = (ctx->params.fullSearch == 0); + + LZ5HC_optimal_t opt[LZ5_OPT_NUM+4]; + LZ5HC_match_t matches[LZ5_OPT_NUM+1]; + const uint8_t *inr; + int res, cur, cur2, cur_min, skip_num = 0; + int rep, llen, litlen, mlen, best_mlen, price, offset, best_off, match_num, last_pos; + + rep = 1; + + + /* init */ + ctx->end += inputSize; + ip++; + + /* Main Loop */ + while (ip < mflimit) + { + memset(opt, 0, sizeof(LZ5HC_optimal_t)); + last_pos = 0; + llen = ip - anchor; + inr = ip; + + + // check rep + mlen = MEM_count(ip, ip - rep, matchlimit); + if (mlen >= MINMATCH) + { + LZ5_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)((char*)ip-source), rep, mlen); + if (mlen > sufficient_len || mlen >= LZ5_OPT_NUM) + { + best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; + goto encode; + } + + do + { + litlen = 0; + price = LZ5HC_get_price(llen, 0, mlen - MINMATCH) - llen; + if (mlen > last_pos || price < opt[mlen].price) + SET_PRICE(mlen, mlen, 0, litlen, price); + mlen--; + } + while (mlen >= MINMATCH); + } + + + best_mlen = (last_pos) ? last_pos : MINMATCH; + + if (faster_get_matches && last_pos) + match_num = 0; + else + { + if (ctx->params.strategy == LZ5HC_optimal_price) + { + LZ5HC_Insert(ctx, ip); + match_num = LZ5HC_GetAllMatches(ctx, ip, ip, matchlimit, best_mlen, matches); + } + else + { + if (ctx->params.fullSearch < 2) + LZ5HC_BinTree_Insert(ctx, ip); + else + LZ5HC_BinTree_InsertFull(ctx, ip, matchlimit); + match_num = LZ5HC_BinTree_GetAllMatches(ctx, ip, matchlimit, best_mlen, matches); + } + } + + LZ5_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)((char*)ip-source), match_num, last_pos); + if (!last_pos && !match_num) { ip++; continue; } + + if (match_num && matches[match_num-1].len > sufficient_len) + { + best_mlen = matches[match_num-1].len; + best_off = matches[match_num-1].off; + cur = 0; + last_pos = 1; + goto encode; + } + + // set prices using matches at position = 0 + for (int i = 0; i < match_num; i++) + { + mlen = (i>0) ? matches[i-1].len+1 : best_mlen; + best_mlen = (matches[i].len < LZ5_OPT_NUM) ? matches[i].len : LZ5_OPT_NUM; + LZ5_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)((char*)ip-source), matches[i].len, matches[i].off, best_mlen, last_pos); + while (mlen <= best_mlen) + { + litlen = 0; + price = LZ5HC_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - llen; + if (mlen > last_pos || price < opt[mlen].price) + SET_PRICE(mlen, mlen, matches[i].off, litlen, price); + mlen++; + } + } + + if (!last_pos) { ip++; continue; } + + opt[0].rep = rep; + opt[0].mlen = 1; + + // check further positions + for (skip_num = 0, cur = 1; cur <= last_pos; cur++) + { + inr = ip + cur; + + if (opt[cur-1].mlen == 1) + { + litlen = opt[cur-1].litlen + 1; + + if (cur != litlen) + { + price = opt[cur - litlen].price + LZ5_LIT_ONLY_COST(litlen); + LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)((char*)inr-source), cur - litlen, opt[cur - litlen].price, price, cur, litlen); + } + else + { + price = LZ5_LIT_ONLY_COST(llen + litlen) - llen; + LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)((char*)inr-source), price, cur, litlen, llen); + } + } + else + { + litlen = 1; + price = opt[cur - 1].price + LZ5_LIT_ONLY_COST(litlen); + LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)((char*)inr-source), price, cur, litlen, LZ5_LIT_ONLY_COST(litlen)); + } + + mlen = 1; + best_mlen = 0; + LZ5_LOG_PARSER("%d: TRY price=%d opt[%d].price=%d\n", (int)((char*)inr-source), price, cur, opt[cur].price); + + if (cur > last_pos || price <= opt[cur].price) // || ((price == opt[cur].price) && (opt[cur-1].mlen == 1) && (cur != litlen))) + SET_PRICE(cur, mlen, best_mlen, litlen, price); + + if (cur == last_pos) break; + + if (opt[cur].mlen > 1) + { + mlen = opt[cur].mlen; + offset = opt[cur].off; + if (offset < 1) + { + opt[cur].rep = opt[cur-mlen].rep; + LZ5_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d\n", (int)((char*)inr-source), cur, mlen, opt[cur-mlen].rep); + } + else + { + opt[cur].rep = offset; + LZ5_LOG_PARSER("%d: COPYREP2 cur=%d offset=%d rep=%d\n", (int)((char*)inr-source), cur, offset, opt[cur].rep); + } + } + else + { + opt[cur].rep = opt[cur-1].rep; // copy rep + } + + + LZ5_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)inr-source), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); + + // check rep + // best_mlen = 0; + mlen = MEM_count(inr, inr - opt[cur].rep, matchlimit); + if (mlen >= MINMATCH && mlen > best_mlen) + { + LZ5_LOG_PARSER("%d: try REP rep=%d mlen=%d\n", (int)((char*)inr-source), opt[cur].rep, mlen); + LZ5_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)((char*)inr-source), mlen, 0, opt[cur].rep, cur, opt[cur].off); + + if (mlen > sufficient_len || cur + mlen >= LZ5_OPT_NUM) + { + best_mlen = mlen; + best_off = 0; + LZ5_LOG_PARSER("%d: REP sufficient_len=%d best_mlen=%d best_off=%d last_pos=%d\n", (int)((char*)inr-source), sufficient_len, best_mlen, best_off, last_pos); + last_pos = cur + 1; + goto encode; + } + + if (opt[cur].mlen == 1) + { + litlen = opt[cur].litlen; + + if (cur != litlen) + { + price = opt[cur - litlen].price + LZ5HC_get_price(litlen, 0, mlen - MINMATCH); + LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)((char*)inr-source), cur - litlen, opt[cur - litlen].price, price, cur, litlen); + } + else + { + price = LZ5HC_get_price(llen + litlen, 0, mlen - MINMATCH) - llen; + LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)((char*)inr-source), price, cur, litlen, llen); + } + } + else + { + litlen = 0; + price = opt[cur].price + LZ5HC_get_price(litlen, 0, mlen - MINMATCH); + LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d getprice=%d\n", (int)((char*)inr-source), price, cur, litlen, LZ5HC_get_price(litlen, 0, mlen - MINMATCH)); + } + + best_mlen = mlen; + if (faster_get_matches) + skip_num = best_mlen; + + LZ5_LOG_PARSER("%d: Found REP mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)((char*)inr-source), mlen, 0, price, litlen, cur - litlen, opt[cur - litlen].price); + + do + { + if (cur + mlen > last_pos || price <= opt[cur + mlen].price) // || ((price == opt[cur + mlen].price) && (opt[cur].mlen == 1) && (cur != litlen))) // at equal price prefer REP instead of MATCH + SET_PRICE(cur + mlen, mlen, 0, litlen, price); + mlen--; + } + while (mlen >= MINMATCH); + } + + if (faster_get_matches && skip_num > 0) + { + skip_num--; + continue; + } + + + best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; + + if (ctx->params.strategy == LZ5HC_optimal_price) + { + LZ5HC_Insert(ctx, inr); + match_num = LZ5HC_GetAllMatches(ctx, inr, ip, matchlimit, best_mlen, matches); + LZ5_LOG_PARSER("%d: LZ5HC_GetAllMatches match_num=%d\n", (int)((char*)inr-source), match_num); + } + else + { + if (ctx->params.fullSearch < 2) + LZ5HC_BinTree_Insert(ctx, inr); + else + LZ5HC_BinTree_InsertFull(ctx, inr, matchlimit); + match_num = LZ5HC_BinTree_GetAllMatches(ctx, inr, matchlimit, best_mlen, matches); + LZ5_LOG_PARSER("%d: LZ5HC_BinTree_GetAllMatches match_num=%d\n", (int)((char*)inr-source), match_num); + } + + + if (match_num > 0 && matches[match_num-1].len > sufficient_len) + { + cur -= matches[match_num-1].back; + best_mlen = matches[match_num-1].len; + best_off = matches[match_num-1].off; + last_pos = cur + 1; + goto encode; + } + + cur_min = cur; + + // set prices using matches at position = cur + for (int i = 0; i < match_num; i++) + { + mlen = (i>0) ? matches[i-1].len+1 : best_mlen; + cur2 = cur - matches[i].back; + best_mlen = (cur2 + matches[i].len < LZ5_OPT_NUM) ? matches[i].len : LZ5_OPT_NUM - cur2; + LZ5_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)((char*)inr-source), cur, cur2, matches[i].len, matches[i].off, best_mlen, last_pos); + + while (mlen <= best_mlen) + { + if (opt[cur2].mlen == 1) + { + litlen = opt[cur2].litlen; + + if (cur2 != litlen) + price = opt[cur2 - litlen].price + LZ5HC_get_price(litlen, matches[i].off, mlen - MINMATCH); + else + price = LZ5HC_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - llen; + } + else + { + litlen = 0; + price = opt[cur2].price + LZ5HC_get_price(litlen, matches[i].off, mlen - MINMATCH); + } + + LZ5_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)((char*)inr-source), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); + if (cur2 + mlen > last_pos || price < opt[cur2 + mlen].price) + { + SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); + + opt[cur2 + mlen].rep = matches[i].off; // update reps + if (cur2 < cur_min) cur_min = cur2; + } + + mlen++; + } + } + + if (cur_min < cur) + { + for (int i=cur_min-1; i<=last_pos; i++) + { + LZ5_LOG_PARSER("%d: BEFORE price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + } + + for (int i=cur_min+1; i<=last_pos; i++) + if (opt[i].price < (1<<30) && (opt[i].off) < 1 && i - opt[i].mlen > cur_min) // invalidate reps + { + if (opt[i-1].mlen == 1) + { + litlen = opt[i-1].litlen + 1; + + if (i != litlen) + { + price = opt[i - litlen].price + LZ5_LIT_ONLY_COST(litlen); + // LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), i - litlen, opt[i - litlen].price, price, i, litlen); + } + else + { + price = LZ5_LIT_ONLY_COST(llen + litlen) - llen; + // LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, i, litlen, llen); + } + } + else + { + litlen = 1; + price = opt[i - 1].price + LZ5_LIT_ONLY_COST(litlen); + // LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d\n", (int)(inr-base), price, i, litlen); + } + + mlen = 1; + best_mlen = 0; + SET_PRICE(i, mlen, best_mlen, litlen, price); + + opt[i].rep = opt[i-1].rep; // copy reps + + LZ5_LOG_PARSER("%d: INVALIDATE pred=%d price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)inr-source), cur-cur_min, i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + } + + for (int i=cur_min-1; i<=last_pos; i++) + { + LZ5_LOG_PARSER("%d: AFTER price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + } + + } + } // for (skip_num = 0, cur = 1; cur <= last_pos; cur++) + + + best_mlen = opt[last_pos].mlen; + best_off = opt[last_pos].off; + cur = last_pos - best_mlen; + +encode: // cur, last_pos, best_mlen, best_off have to be set + for (int i = 1; i <= last_pos; i++) + { + LZ5_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + } + + LZ5_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)((char*)ip-source+cur), cur, last_pos, best_mlen, best_off, opt[cur].rep); + + opt[0].mlen = 1; + + while (cur >= 0) + { + mlen = opt[cur].mlen; + offset = opt[cur].off; + opt[cur].mlen = best_mlen; + opt[cur].off = best_off; + best_mlen = mlen; + best_off = offset; + cur -= mlen; + } + + for (int i = 0; i <= last_pos;) + { + LZ5_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + i += opt[i].mlen; + } + + cur = 0; + + while (cur < last_pos) + { + LZ5_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); + mlen = opt[cur].mlen; + if (mlen == 1) { ip++; cur++; continue; } + offset = opt[cur].off; + cur += mlen; + + LZ5_LOG_ENCODE("%d: ENCODE literals=%d off=%d mlen=%d ", (int)((char*)ip-source), (int)(ip-anchor), (int)(offset), mlen); + if (offset == 0) + { + res = LZ5HC_encodeSequence(ctx, &ip, &op, &anchor, mlen, ip - rep, limit, oend); + } + else + { + res = LZ5HC_encodeSequence(ctx, &ip, &op, &anchor, mlen, ip - offset, limit, oend); + rep = offset; + } + LZ5_LOG_ENCODE("out=%d\n", (int)((char*)op - dest)); + + if (res) return 0; + + LZ5_LOG_PARSER("%d: offset=%d rep=%d\n", (int)((char*)ip-source), offset, rep); + } + } + + /* Encode Last Literals */ + { + int lastRun = (int)(iend - anchor); + // if (inputSize > LASTLITERALS && lastRun < LASTLITERALS) { printf("ERROR: lastRun=%d\n", lastRun); } + if ((limit) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0; /* Check output limit */ + if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK< 254 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; } + else *op++ = (BYTE)(lastRun< Date: Sun, 31 Jan 2016 11:57:01 +0100 Subject: [PATCH 003/113] ZSTD_compressBlock_opt_generic --- lib/zstd_opt.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 2 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index caef8065d..285bebb8c 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -260,10 +260,10 @@ FORCE_INLINE size_t ZSTD_HcGetAllMatches_selectMLS ( /* ******************************* -* Common parser - lazy strategy +* Optimal parser OLD *********************************/ FORCE_INLINE -void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, +void ZSTD_compressBlock_opt_generic_OLD(ZSTD_CCtx* ctx, const void* src, size_t srcSize, const U32 searchMethod, const U32 depth) { @@ -393,6 +393,131 @@ _storeSequence: } } + + + +/* ******************************* +* Optimal parser +*********************************/ +FORCE_INLINE +void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, + const void* src, size_t srcSize, + const U32 searchMethod, const U32 depth) +{ + seqStore_t* seqStorePtr = &(ctx->seqStore); + const BYTE* const istart = (const BYTE*)src; + const BYTE* ip = istart; + const BYTE* anchor = istart; + const BYTE* const iend = istart + srcSize; + const BYTE* const ilimit = iend - 8; + const BYTE* const base = ctx->base + ctx->dictLimit; + + size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE; + const U32 maxSearches = 1 << ctx->params.searchLog; + const U32 mls = ctx->params.searchLength; + + typedef size_t (*getAllMatches_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, + U32 maxNbAttempts, U32 matchLengthSearch, LZ5HC_match_t* matches); + getAllMatches_f getAllMatches = searchMethod ? ZSTD_BtGetAllMatches_selectMLS : ZSTD_HcGetAllMatches_selectMLS; + + LZ5HC_match_t matches[LZ5_OPT_NUM+1]; + + /* init */ + ZSTD_resetSeqStore(seqStorePtr); + if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE; + + /* Match Loop */ + while (ip < ilimit) { + size_t matchLength=0; + size_t offset=0; + const BYTE* start=ip+1; + + /* check repCode */ + if (MEM_read32(start) == MEM_read32(start - offset_1)) { + /* repcode : we take it */ + matchLength = ZSTD_count(start+MINMATCH, start+MINMATCH-offset_1, iend) + MINMATCH; + if (depth==0) goto _storeSequence; + } + + { + /* first search (depth 0) */ + size_t mnum = getAllMatches(ctx, ip, iend, maxSearches, mls, matches); + if (mnum > 0 && matches[mnum-1].len > matchLength) + matchLength = matches[mnum-1].len, start = ip, offset=matches[mnum-1].off; + } + + if (matchLength < MINMATCH) { + // ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */ + ip++; + continue; + } + + /* let's try to find a better solution */ + if (depth>=1) + while (ip= MINMATCH) && (gain2 > gain1)) + matchLength = mlRep, offset = 0, start = ip; + } + { + size_t mnum = getAllMatches(ctx, ip, iend, maxSearches, mls, matches); + if (mnum > 0) { + int gain2 = (int)(matches[mnum-1].len*4 - ZSTD_highbit((U32)matches[mnum-1].off+1)); /* raw approx */ + int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4); + if ((matches[mnum-1].len >= MINMATCH) && (gain2 > gain1)) { + matchLength = matches[mnum-1].len, offset = matches[mnum-1].off, start = ip; + continue; /* search a better one */ + } + } + } + + break; /* nothing found : store previous solution */ + } + + /* catch up */ + if (offset) { + while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) /* only search for offset within prefix */ + { start--; matchLength++; } + offset_2 = offset_1; offset_1 = offset; + } + + /* store sequence */ +_storeSequence: + { + size_t litLength = start - anchor; + ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH); + anchor = ip = start + matchLength; + } + + /* check immediate repcode */ + while ( (ip <= ilimit) + && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) { + /* store sequence */ + matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend); + offset = offset_2; + offset_2 = offset_1; + offset_1 = offset; + ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength); + ip += matchLength+MINMATCH; + anchor = ip; + continue; /* faster when present ... (?) */ + } } + + /* Last Literals */ + { + size_t lastLLSize = iend - anchor; + memcpy(seqStorePtr->lit, anchor, lastLLSize); + seqStorePtr->lit += lastLLSize; + } +} + + + + #if 0 /* ******************************* * Optimal parser From 9bfb1a3357818b45f1584b95fd5036ecc2d97985 Mon Sep 17 00:00:00 2001 From: inikep Date: Sun, 31 Jan 2016 12:17:16 +0100 Subject: [PATCH 004/113] working --- lib/zstd_opt.c | 580 +++++-------------------------------------------- 1 file changed, 55 insertions(+), 525 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 285bebb8c..eda048490 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -412,7 +412,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, const BYTE* const ilimit = iend - 8; const BYTE* const base = ctx->base + ctx->dictLimit; - size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE; + size_t rep_2=REPCODE_STARTVALUE, rep_1=REPCODE_STARTVALUE; const U32 maxSearches = 1 << ctx->params.searchLog; const U32 mls = ctx->params.searchLength; @@ -420,33 +420,62 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, U32 maxNbAttempts, U32 matchLengthSearch, LZ5HC_match_t* matches); getAllMatches_f getAllMatches = searchMethod ? ZSTD_BtGetAllMatches_selectMLS : ZSTD_HcGetAllMatches_selectMLS; + LZ5HC_optimal_t opt[LZ5_OPT_NUM+4]; LZ5HC_match_t matches[LZ5_OPT_NUM+1]; - + const uint8_t *inr; + int res, cur, cur2, cur_min, skip_num = 0; + int rep = 1, llen, litlen, price, offset, best_off, match_num, last_pos; + + const int sufficient_len = 128; //ctx->params.sufficientLength; + const int faster_get_matches = (ctx->params.strategy == ZSTD_opt); + /* init */ ZSTD_resetSeqStore(seqStorePtr); if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE; /* Match Loop */ while (ip < ilimit) { - size_t matchLength=0; + size_t mlen=0; + size_t best_mlen=0; size_t offset=0; const BYTE* start=ip+1; + memset(opt, 0, sizeof(LZ5HC_optimal_t)); + last_pos = 0; + llen = ip - anchor; + inr = ip; /* check repCode */ - if (MEM_read32(start) == MEM_read32(start - offset_1)) { + if (MEM_read32(start) == MEM_read32(start - rep_1)) { /* repcode : we take it */ - matchLength = ZSTD_count(start+MINMATCH, start+MINMATCH-offset_1, iend) + MINMATCH; - if (depth==0) goto _storeSequence; + best_mlen = ZSTD_count(start+MINMATCH, start+MINMATCH-rep_1, iend) + MINMATCH; + + LZ5_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)((char*)ip-source), rep, best_mlen); + if (depth==0 || best_mlen > sufficient_len || best_mlen >= LZ5_OPT_NUM) { + best_off = 0; cur = 0; last_pos = 1; + goto _storeSequence; + } + + mlen = best_mlen; + do + { + litlen = 0; + price = LZ5HC_get_price(llen, 0, mlen - MINMATCH) - llen; + if (mlen > last_pos || price < opt[mlen].price) + SET_PRICE(mlen, mlen, 0, litlen, price); + mlen--; + } + while (mlen >= MINMATCH); } + { /* first search (depth 0) */ size_t mnum = getAllMatches(ctx, ip, iend, maxSearches, mls, matches); - if (mnum > 0 && matches[mnum-1].len > matchLength) - matchLength = matches[mnum-1].len, start = ip, offset=matches[mnum-1].off; + if (mnum > 0 && matches[mnum-1].len > best_mlen) + best_mlen = matches[mnum-1].len, start = ip, offset=matches[mnum-1].off; } - if (matchLength < MINMATCH) { + if (best_mlen < MINMATCH) { // ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */ ip++; continue; @@ -456,20 +485,20 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (depth>=1) while (ip= MINMATCH) && (gain2 > gain1)) - matchLength = mlRep, offset = 0, start = ip; + best_mlen = mlRep, offset = 0, start = ip; } { size_t mnum = getAllMatches(ctx, ip, iend, maxSearches, mls, matches); if (mnum > 0) { int gain2 = (int)(matches[mnum-1].len*4 - ZSTD_highbit((U32)matches[mnum-1].off+1)); /* raw approx */ - int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4); + int gain1 = (int)(best_mlen*4 - ZSTD_highbit((U32)offset+1) + 4); if ((matches[mnum-1].len >= MINMATCH) && (gain2 > gain1)) { - matchLength = matches[mnum-1].len, offset = matches[mnum-1].off, start = ip; + best_mlen = matches[mnum-1].len, offset = matches[mnum-1].off, start = ip; continue; /* search a better one */ } } @@ -481,28 +510,28 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, /* catch up */ if (offset) { while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) /* only search for offset within prefix */ - { start--; matchLength++; } - offset_2 = offset_1; offset_1 = offset; + { start--; best_mlen++; } + rep_2 = rep_1; rep_1 = offset; } /* store sequence */ _storeSequence: { size_t litLength = start - anchor; - ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH); - anchor = ip = start + matchLength; + ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, best_mlen-MINMATCH); + anchor = ip = start + best_mlen; } /* check immediate repcode */ while ( (ip <= ilimit) - && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) { + && (MEM_read32(ip) == MEM_read32(ip - rep_2)) ) { /* store sequence */ - matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend); - offset = offset_2; - offset_2 = offset_1; - offset_1 = offset; - ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength); - ip += matchLength+MINMATCH; + best_mlen = ZSTD_count(ip+MINMATCH, ip+MINMATCH-rep_2, iend); + offset = rep_2; + rep_2 = rep_1; + rep_1 = offset; + ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, best_mlen); + ip += best_mlen+MINMATCH; anchor = ip; continue; /* faster when present ... (?) */ } } @@ -518,505 +547,6 @@ _storeSequence: -#if 0 -/* ******************************* -* Optimal parser -*********************************/ -FORCE_INLINE -void ZSTD_compressBlock_opt2_generic(ZSTD_CCtx* ctx, - const void* src, size_t srcSize, - const U32 searchMethod, const U32 depth) -{ - seqStore_t* seqStorePtr = &(ctx->seqStore); - const BYTE* const istart = (const BYTE*)src; - const BYTE* ip = istart; - const BYTE* anchor = istart; - const BYTE* const iend = istart + srcSize; - const BYTE* const ilimit = iend - 8; - const BYTE* const base = ctx->base + ctx->dictLimit; - - size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE; - const U32 maxSearches = 1 << ctx->params.searchLog; - const U32 mls = ctx->params.searchLength; - - typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, - size_t* offsetPtr, - U32 maxNbAttempts, U32 matchLengthSearch); - searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS; - - /* init */ - ZSTD_resetSeqStore(seqStorePtr); - if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE; - - LZ5HC_optimal_t opt[LZ5_OPT_NUM+4]; - LZ5HC_match_t matches[LZ5_OPT_NUM+1]; - const uint8_t *inr; - int res, cur, cur2, cur_min, skip_num = 0; - int rep = 1, llen, litlen, mlen, best_mlen, price, offset, best_off, match_num, last_pos; - - const int sufficient_len = 64; //ctx->params.sufficientLength; - const bool faster_get_matches = (ctx->params.strategy == ZSTD_opt); - - - /* Match Loop */ - while (ip < ilimit) { - size_t mlen=0; - size_t offset=0; - const BYTE* start=ip+1; - - memset(opt, 0, sizeof(LZ5HC_optimal_t)); - last_pos = 0; - llen = ip - anchor; - inr = ip; - - - /* check repCode */ - if (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1)) { - /* repcode : we take it */ - mlen = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend) + MINMATCH; - - LZ5_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)((char*)ip-source), rep, mlen); - if (mlen > sufficient_len || mlen >= LZ5_OPT_NUM) - { - best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; - goto _storeSequence; - } - - do - { - litlen = 0; - price = LZ5HC_get_price(llen, 0, mlen - MINMATCH) - llen; - if (mlen > last_pos || price < opt[mlen].price) - SET_PRICE(mlen, mlen, 0, litlen, price); - mlen--; - } - while (mlen >= MINMATCH); - - if (depth==0) goto _storeSequence; - } - -/* - { - // first search (depth 0) - size_t offsetFound = 99999999; - size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls); - if (ml2 > mlen) - mlen = ml2, start = ip, offset=offsetFound; - } -*/ -/* - if (mlen < MINMATCH) { - ip += ((ip-anchor) >> g_searchStrength) + 1; // jump faster over incompressible sections - continue; - } -*/ -/* // let's try to find a better solution - if (depth>=1) - while (ip= MINMATCH) && (gain2 > gain1)) - mlen = mlRep, offset = 0, start = ip; - } - { - size_t offset2=999999; - size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls); - int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); // raw approx - int gain1 = (int)(mlen*4 - ZSTD_highbit((U32)offset+1) + 4); - if ((ml2 >= MINMATCH) && (gain2 > gain1)) { - mlen = ml2, offset = offset2, start = ip; - continue; // search a better one - } } - - break; // nothing found : store previous solution - } -*/ - - best_mlen = (last_pos) ? last_pos : MINMATCH; - - if (faster_get_matches && last_pos) - match_num = 0; - else - { - if (ctx->params.strategy == LZ5HC_optimal_price) - { - LZ5HC_Insert(ctx, ip); - match_num = LZ5HC_GetAllMatches(ctx, ip, ip, matchlimit, best_mlen, matches); - } - else - { - LZ5HC_BinTree_Insert(ctx, ip); - match_num = LZ5HC_BinTree_GetAllMatches(ctx, ip, matchlimit, best_mlen, matches); - } - } - - LZ5_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)((char*)ip-source), match_num, last_pos); - if (!last_pos && !match_num) { ip++; continue; } - - if (match_num && matches[match_num-1].len > sufficient_len) - { - best_mlen = matches[match_num-1].len; - best_off = matches[match_num-1].off; - cur = 0; - last_pos = 1; - goto encode; - } - - // set prices using matches at position = 0 - for (int i = 0; i < match_num; i++) - { - mlen = (i>0) ? matches[i-1].len+1 : best_mlen; - best_mlen = (matches[i].len < LZ5_OPT_NUM) ? matches[i].len : LZ5_OPT_NUM; - LZ5_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)((char*)ip-source), matches[i].len, matches[i].off, best_mlen, last_pos); - while (mlen <= best_mlen) - { - litlen = 0; - price = LZ5HC_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - llen; - if (mlen > last_pos || price < opt[mlen].price) - SET_PRICE(mlen, mlen, matches[i].off, litlen, price); - mlen++; - } - } - - if (!last_pos) { ip++; continue; } - - opt[0].rep = rep; - opt[0].mlen = 1; - - // check further positions - for (skip_num = 0, cur = 1; cur <= last_pos; cur++) - { - inr = ip + cur; - - if (opt[cur-1].mlen == 1) - { - litlen = opt[cur-1].litlen + 1; - - if (cur != litlen) - { - price = opt[cur - litlen].price + LZ5_LIT_ONLY_COST(litlen); - LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)((char*)inr-source), cur - litlen, opt[cur - litlen].price, price, cur, litlen); - } - else - { - price = LZ5_LIT_ONLY_COST(llen + litlen) - llen; - LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)((char*)inr-source), price, cur, litlen, llen); - } - } - else - { - litlen = 1; - price = opt[cur - 1].price + LZ5_LIT_ONLY_COST(litlen); - LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)((char*)inr-source), price, cur, litlen, LZ5_LIT_ONLY_COST(litlen)); - } - - mlen = 1; - best_mlen = 0; - LZ5_LOG_PARSER("%d: TRY price=%d opt[%d].price=%d\n", (int)((char*)inr-source), price, cur, opt[cur].price); - - if (cur > last_pos || price <= opt[cur].price) // || ((price == opt[cur].price) && (opt[cur-1].mlen == 1) && (cur != litlen))) - SET_PRICE(cur, mlen, best_mlen, litlen, price); - - if (cur == last_pos) break; - - if (opt[cur].mlen > 1) - { - mlen = opt[cur].mlen; - offset = opt[cur].off; - if (offset < 1) - { - opt[cur].rep = opt[cur-mlen].rep; - LZ5_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d\n", (int)((char*)inr-source), cur, mlen, opt[cur-mlen].rep); - } - else - { - opt[cur].rep = offset; - LZ5_LOG_PARSER("%d: COPYREP2 cur=%d offset=%d rep=%d\n", (int)((char*)inr-source), cur, offset, opt[cur].rep); - } - } - else - { - opt[cur].rep = opt[cur-1].rep; // copy rep - } - - - LZ5_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)inr-source), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); - - // check rep - // best_mlen = 0; - mlen = MEM_count(inr, inr - opt[cur].rep, matchlimit); - if (mlen >= MINMATCH && mlen > best_mlen) - { - LZ5_LOG_PARSER("%d: try REP rep=%d mlen=%d\n", (int)((char*)inr-source), opt[cur].rep, mlen); - LZ5_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)((char*)inr-source), mlen, 0, opt[cur].rep, cur, opt[cur].off); - - if (mlen > sufficient_len || cur + mlen >= LZ5_OPT_NUM) - { - best_mlen = mlen; - best_off = 0; - LZ5_LOG_PARSER("%d: REP sufficient_len=%d best_mlen=%d best_off=%d last_pos=%d\n", (int)((char*)inr-source), sufficient_len, best_mlen, best_off, last_pos); - last_pos = cur + 1; - goto encode; - } - - if (opt[cur].mlen == 1) - { - litlen = opt[cur].litlen; - - if (cur != litlen) - { - price = opt[cur - litlen].price + LZ5HC_get_price(litlen, 0, mlen - MINMATCH); - LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)((char*)inr-source), cur - litlen, opt[cur - litlen].price, price, cur, litlen); - } - else - { - price = LZ5HC_get_price(llen + litlen, 0, mlen - MINMATCH) - llen; - LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)((char*)inr-source), price, cur, litlen, llen); - } - } - else - { - litlen = 0; - price = opt[cur].price + LZ5HC_get_price(litlen, 0, mlen - MINMATCH); - LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d getprice=%d\n", (int)((char*)inr-source), price, cur, litlen, LZ5HC_get_price(litlen, 0, mlen - MINMATCH)); - } - - best_mlen = mlen; - if (faster_get_matches) - skip_num = best_mlen; - - LZ5_LOG_PARSER("%d: Found REP mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)((char*)inr-source), mlen, 0, price, litlen, cur - litlen, opt[cur - litlen].price); - - do - { - if (cur + mlen > last_pos || price <= opt[cur + mlen].price) // || ((price == opt[cur + mlen].price) && (opt[cur].mlen == 1) && (cur != litlen))) // at equal price prefer REP instead of MATCH - SET_PRICE(cur + mlen, mlen, 0, litlen, price); - mlen--; - } - while (mlen >= MINMATCH); - } - - if (faster_get_matches && skip_num > 0) - { - skip_num--; - continue; - } - - - best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; - - if (ctx->params.strategy == LZ5HC_optimal_price) - { - LZ5HC_Insert(ctx, inr); - match_num = LZ5HC_GetAllMatches(ctx, inr, ip, matchlimit, best_mlen, matches); - LZ5_LOG_PARSER("%d: LZ5HC_GetAllMatches match_num=%d\n", (int)((char*)inr-source), match_num); - } - else - { - LZ5HC_BinTree_Insert(ctx, inr); - match_num = LZ5HC_BinTree_GetAllMatches(ctx, inr, matchlimit, best_mlen, matches); - LZ5_LOG_PARSER("%d: LZ5HC_BinTree_GetAllMatches match_num=%d\n", (int)((char*)inr-source), match_num); - } - - - if (match_num > 0 && matches[match_num-1].len > sufficient_len) - { - cur -= matches[match_num-1].back; - best_mlen = matches[match_num-1].len; - best_off = matches[match_num-1].off; - last_pos = cur + 1; - goto encode; - } - - cur_min = cur; - - // set prices using matches at position = cur - for (int i = 0; i < match_num; i++) - { - mlen = (i>0) ? matches[i-1].len+1 : best_mlen; - cur2 = cur - matches[i].back; - best_mlen = (cur2 + matches[i].len < LZ5_OPT_NUM) ? matches[i].len : LZ5_OPT_NUM - cur2; - LZ5_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)((char*)inr-source), cur, cur2, matches[i].len, matches[i].off, best_mlen, last_pos); - - while (mlen <= best_mlen) - { - if (opt[cur2].mlen == 1) - { - litlen = opt[cur2].litlen; - - if (cur2 != litlen) - price = opt[cur2 - litlen].price + LZ5HC_get_price(litlen, matches[i].off, mlen - MINMATCH); - else - price = LZ5HC_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - llen; - } - else - { - litlen = 0; - price = opt[cur2].price + LZ5HC_get_price(litlen, matches[i].off, mlen - MINMATCH); - } - - LZ5_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)((char*)inr-source), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); - if (cur2 + mlen > last_pos || price < opt[cur2 + mlen].price) - { - SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); - - opt[cur2 + mlen].rep = matches[i].off; // update reps - if (cur2 < cur_min) cur_min = cur2; - } - - mlen++; - } - } - - if (cur_min < cur) - { - for (int i=cur_min-1; i<=last_pos; i++) - { - LZ5_LOG_PARSER("%d: BEFORE price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); - } - - for (int i=cur_min+1; i<=last_pos; i++) - if (opt[i].price < (1<<30) && (opt[i].off) < 1 && i - opt[i].mlen > cur_min) // invalidate reps - { - if (opt[i-1].mlen == 1) - { - litlen = opt[i-1].litlen + 1; - - if (i != litlen) - { - price = opt[i - litlen].price + LZ5_LIT_ONLY_COST(litlen); - // LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), i - litlen, opt[i - litlen].price, price, i, litlen); - } - else - { - price = LZ5_LIT_ONLY_COST(llen + litlen) - llen; - // LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, i, litlen, llen); - } - } - else - { - litlen = 1; - price = opt[i - 1].price + LZ5_LIT_ONLY_COST(litlen); - // LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d\n", (int)(inr-base), price, i, litlen); - } - - mlen = 1; - best_mlen = 0; - SET_PRICE(i, mlen, best_mlen, litlen, price); - - opt[i].rep = opt[i-1].rep; // copy reps - - LZ5_LOG_PARSER("%d: INVALIDATE pred=%d price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)inr-source), cur-cur_min, i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); - } - - for (int i=cur_min-1; i<=last_pos; i++) - { - LZ5_LOG_PARSER("%d: AFTER price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); - } - - } - } // for (skip_num = 0, cur = 1; cur <= last_pos; cur++) - - - best_mlen = opt[last_pos].mlen; - best_off = opt[last_pos].off; - cur = last_pos - best_mlen; - - /* catch up */ - if (offset) { - // while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) // only search for offset within prefix - // { start--; mlen++; } - offset_2 = offset_1; offset_1 = offset; - } - - /* store sequence */ -_storeSequence: // cur, last_pos, best_mlen, best_off have to be set - for (int i = 1; i <= last_pos; i++) - { - LZ5_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); - } - - LZ5_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)((char*)ip-source+cur), cur, last_pos, best_mlen, best_off, opt[cur].rep); - - opt[0].mlen = 1; - - while (cur >= 0) - { - mlen = opt[cur].mlen; - offset = opt[cur].off; - opt[cur].mlen = best_mlen; - opt[cur].off = best_off; - best_mlen = mlen; - best_off = offset; - cur -= mlen; - } - - for (int i = 0; i <= last_pos;) - { - LZ5_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); - i += opt[i].mlen; - } - - cur = 0; - - while (cur < last_pos) - { - LZ5_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); - mlen = opt[cur].mlen; - if (mlen == 1) { ip++; cur++; continue; } - offset = opt[cur].off; - cur += mlen; - - LZ5_LOG_ENCODE("%d: ENCODE literals=%d off=%d mlen=%d ", (int)((char*)ip-source), (int)(ip-anchor), (int)(offset), mlen); - if (offset == 0) - { - res = LZ5HC_encodeSequence(ctx, &ip, &op, &anchor, mlen, ip - rep, limit, oend); - } - else - { - res = LZ5HC_encodeSequence(ctx, &ip, &op, &anchor, mlen, ip - offset, limit, oend); - rep = offset; - } - LZ5_LOG_ENCODE("out=%d\n", (int)((char*)op - dest)); - - if (res) return 0; - - LZ5_LOG_PARSER("%d: offset=%d rep=%d\n", (int)((char*)ip-source), offset, rep); - } - - { - size_t litLength = start - anchor; - ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); - anchor = ip = start + mlen; - } - - /* check immediate repcode */ - while ( (ip <= ilimit) - && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) { - /* store sequence */ - mlen = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend); - offset = offset_2; - offset_2 = offset_1; - offset_1 = offset; - ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, mlen); - ip += mlen+MINMATCH; - anchor = ip; - continue; /* faster when present ... (?) */ - } } - - /* Last Literals */ - { - size_t lastLLSize = iend - anchor; - memcpy(seqStorePtr->lit, anchor, lastLLSize); - seqStorePtr->lit += lastLLSize; - } -} -#endif - - #if 0 static int LZ5HC_compress_optimal_price ( LZ5HC_Data_Structure* ctx, From c0dc4c361dd00d81af211ebfe6173aa2b9c7e133 Mon Sep 17 00:00:00 2001 From: inikep Date: Sun, 31 Jan 2016 12:36:41 +0100 Subject: [PATCH 005/113] best_off --- lib/zstd_opt.c | 78 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 17 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index eda048490..9ef2aa709 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -424,7 +424,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, LZ5HC_match_t matches[LZ5_OPT_NUM+1]; const uint8_t *inr; int res, cur, cur2, cur_min, skip_num = 0; - int rep = 1, llen, litlen, price, offset, best_off, match_num, last_pos; + int rep = 1, llen, litlen, price, match_num, last_pos; const int sufficient_len = 128; //ctx->params.sufficientLength; const int faster_get_matches = (ctx->params.strategy == ZSTD_opt); @@ -437,7 +437,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, while (ip < ilimit) { size_t mlen=0; size_t best_mlen=0; - size_t offset=0; + size_t best_off=0; const BYTE* start=ip+1; memset(opt, 0, sizeof(LZ5HC_optimal_t)); last_pos = 0; @@ -472,7 +472,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, /* first search (depth 0) */ size_t mnum = getAllMatches(ctx, ip, iend, maxSearches, mls, matches); if (mnum > 0 && matches[mnum-1].len > best_mlen) - best_mlen = matches[mnum-1].len, start = ip, offset=matches[mnum-1].off; + best_mlen = matches[mnum-1].len, start = ip, best_off=matches[mnum-1].off; } if (best_mlen < MINMATCH) { @@ -485,20 +485,20 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (depth>=1) while (ip= MINMATCH) && (gain2 > gain1)) - best_mlen = mlRep, offset = 0, start = ip; + best_mlen = mlRep, best_off = 0, start = ip; } { size_t mnum = getAllMatches(ctx, ip, iend, maxSearches, mls, matches); if (mnum > 0) { int gain2 = (int)(matches[mnum-1].len*4 - ZSTD_highbit((U32)matches[mnum-1].off+1)); /* raw approx */ - int gain1 = (int)(best_mlen*4 - ZSTD_highbit((U32)offset+1) + 4); + int gain1 = (int)(best_mlen*4 - ZSTD_highbit((U32)best_off+1) + 4); if ((matches[mnum-1].len >= MINMATCH) && (gain2 > gain1)) { - best_mlen = matches[mnum-1].len, offset = matches[mnum-1].off, start = ip; + best_mlen = matches[mnum-1].len, best_off = matches[mnum-1].off, start = ip; continue; /* search a better one */ } } @@ -508,28 +508,72 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } /* catch up */ - if (offset) { - while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) /* only search for offset within prefix */ + if (best_off) { + while ((start>anchor) && (start>base+best_off) && (start[-1] == start[-1-best_off])) /* only search for offset within prefix */ { start--; best_mlen++; } - rep_2 = rep_1; rep_1 = offset; + // rep_2 = rep_1; rep_1 = best_off; } + cur = 0; + last_pos = 1; + /* store sequence */ -_storeSequence: +_storeSequence: // cur, last_pos, best_mlen, best_off have to be set + for (int i = 1; i <= last_pos; i++) + LZ5_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + LZ5_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)((char*)ip-source+cur), cur, last_pos, best_mlen, best_off, opt[cur].rep); + + opt[0].mlen = 1; + + size_t offset; + while (cur >= 0) { - size_t litLength = start - anchor; - ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, best_mlen-MINMATCH); - anchor = ip = start + best_mlen; + mlen = opt[cur].mlen; + offset = opt[cur].off; + opt[cur].mlen = best_mlen; + opt[cur].off = best_off; + best_mlen = mlen; + best_off = offset; + cur -= mlen; } + + for (int i = 0; i <= last_pos;) + { + LZ5_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + i += opt[i].mlen; + } + + cur = 0; + + while (cur < last_pos) + { + LZ5_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); + mlen = opt[cur].mlen; + if (mlen == 1) { ip++; cur++; continue; } + offset = opt[cur].off; + cur += mlen; + + LZ5_LOG_ENCODE("%d: ENCODE literals=%d off=%d mlen=%d ", (int)((char*)ip-source), (int)(ip-anchor), (int)(offset), mlen); + size_t litLength = start - anchor; + ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); + anchor = ip = start + mlen; + + if (offset) + rep_2 = rep_1, rep_1 = offset; + + LZ5_LOG_ENCODE("out=%d\n", (int)((char*)op - dest)); + LZ5_LOG_PARSER("%d: offset=%d rep=%d\n", (int)((char*)ip-source), offset, rep); + } + /* check immediate repcode */ while ( (ip <= ilimit) && (MEM_read32(ip) == MEM_read32(ip - rep_2)) ) { /* store sequence */ best_mlen = ZSTD_count(ip+MINMATCH, ip+MINMATCH-rep_2, iend); - offset = rep_2; + best_off = rep_2; rep_2 = rep_1; - rep_1 = offset; + rep_1 = best_off; ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, best_mlen); ip += best_mlen+MINMATCH; anchor = ip; From d4c3e8c5952d9c4445987c51011d9b57ddaae592 Mon Sep 17 00:00:00 2001 From: inikep Date: Sun, 31 Jan 2016 14:28:26 +0100 Subject: [PATCH 006/113] fixed logs --- lib/zstd_opt.c | 135 +++++++++++++++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 54 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 9ef2aa709..18fe2329c 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -1,3 +1,5 @@ +#include + typedef struct { int off; @@ -16,7 +18,7 @@ typedef struct #define LZ5HC_DEBUG(fmt, args...) ;//printf(fmt, ##args) -#define LZ5_LOG_PARSER(fmt, args...) ;//printf(fmt, ##args) +#define LZ5_LOG_PARSER(fmt, args...) ;// printf(fmt, ##args) #define LZ5_LOG_PRICE(fmt, args...) ;//printf(fmt, ##args) #define LZ5_LOG_ENCODE(fmt, args...) ;//printf(fmt, ##args) @@ -59,7 +61,7 @@ FORCE_INLINE U32 LZ5HC_get_price(U32 litlen, U32 offset, U32 mlen) opt[pos].off = offset; \ opt[pos].litlen = litlen; \ opt[pos].price = price; \ - LZ5_LOG_PARSER("%d: SET price[%d/%d]=%d litlen=%d len=%d off=%d\n", (int)((char*)(char*)inr-source), pos, last_pos, opt[pos].price, opt[pos].litlen, opt[pos].mlen, opt[pos].off); \ + LZ5_LOG_PARSER("%d: SET price[%d/%d]=%d litlen=%d len=%d off=%d\n", (int)(inr-istart), (int)pos, (int)last_pos, opt[pos].price, opt[pos].litlen, opt[pos].mlen, opt[pos].off); \ } @@ -330,6 +332,7 @@ void ZSTD_compressBlock_opt_generic_OLD(ZSTD_CCtx* ctx, continue; } +#if 0 /* let's try to find a better solution */ if (depth>=1) while (ipparams.sufficientLength; - const int faster_get_matches = (ctx->params.strategy == ZSTD_opt); + const int faster_get_matches = 0;//(ctx->params.strategy == ZSTD_opt); /* init */ ZSTD_resetSeqStore(seqStorePtr); @@ -447,15 +451,14 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, /* check repCode */ if (MEM_read32(start) == MEM_read32(start - rep_1)) { /* repcode : we take it */ - best_mlen = ZSTD_count(start+MINMATCH, start+MINMATCH-rep_1, iend) + MINMATCH; + mlen = ZSTD_count(start+MINMATCH, start+MINMATCH-rep_1, iend) + MINMATCH; - LZ5_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)((char*)ip-source), rep, best_mlen); - if (depth==0 || best_mlen > sufficient_len || best_mlen >= LZ5_OPT_NUM) { - best_off = 0; cur = 0; last_pos = 1; + LZ5_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)(ip-istart), (int)rep_1, (int)mlen); + if (depth==0 || mlen > sufficient_len || mlen >= LZ5_OPT_NUM) { + best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; goto _storeSequence; } - mlen = best_mlen; do { litlen = 0; @@ -468,60 +471,70 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } - { + // best_mlen = (last_pos) ? last_pos : MINMATCH; + + if (faster_get_matches && last_pos) + match_num = 0; + else + { /* first search (depth 0) */ - size_t mnum = getAllMatches(ctx, ip, iend, maxSearches, mls, matches); - if (mnum > 0 && matches[mnum-1].len > best_mlen) - best_mlen = matches[mnum-1].len, start = ip, best_off=matches[mnum-1].off; + match_num = getAllMatches(ctx, ip, iend, maxSearches, mls, matches); + } + + LZ5_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-istart), match_num, last_pos); + if (!last_pos && !match_num) { ip++; continue; } + + if (match_num && matches[match_num-1].len > sufficient_len) + { + start = ip; + best_mlen = matches[match_num-1].len; + best_off = matches[match_num-1].off; + cur = 0; + last_pos = 1; + goto _storeSequence; + } + + // set prices using matches at position = 0 + for (int i = 0; i < match_num; i++) + { + mlen = (i>0) ? matches[i-1].len+1 : best_mlen; + best_mlen = (matches[i].len < LZ5_OPT_NUM) ? matches[i].len : LZ5_OPT_NUM; + LZ5_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(ip-istart), matches[i].len, matches[i].off, (int)best_mlen, (int)last_pos); + while (mlen <= best_mlen) + { + litlen = 0; + price = LZ5HC_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - llen; + if (mlen > last_pos || price < opt[mlen].price) + SET_PRICE(mlen, mlen, matches[i].off, litlen, price); + mlen++; + } } - if (best_mlen < MINMATCH) { - // ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */ - ip++; - continue; + if (last_pos < MINMATCH) { + // ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */ + ip++; continue; } - /* let's try to find a better solution */ - if (depth>=1) - while (ip= MINMATCH) && (gain2 > gain1)) - best_mlen = mlRep, best_off = 0, start = ip; - } - { - size_t mnum = getAllMatches(ctx, ip, iend, maxSearches, mls, matches); - if (mnum > 0) { - int gain2 = (int)(matches[mnum-1].len*4 - ZSTD_highbit((U32)matches[mnum-1].off+1)); /* raw approx */ - int gain1 = (int)(best_mlen*4 - ZSTD_highbit((U32)best_off+1) + 4); - if ((matches[mnum-1].len >= MINMATCH) && (gain2 > gain1)) { - best_mlen = matches[mnum-1].len, best_off = matches[mnum-1].off, start = ip; - continue; /* search a better one */ - } - } - } + // printf("%d: last_pos=%d\n", (int)(ip - istart), (int)last_pos); - break; /* nothing found : store previous solution */ - } + opt[0].rep = rep_1; + opt[0].mlen = 1; - /* catch up */ - if (best_off) { - while ((start>anchor) && (start>base+best_off) && (start[-1] == start[-1-best_off])) /* only search for offset within prefix */ - { start--; best_mlen++; } - // rep_2 = rep_1; rep_1 = best_off; - } + best_mlen = opt[last_pos].mlen; + best_off = opt[last_pos].off; + if (best_off) + start = ip; cur = 0; last_pos = 1; +// cur = last_pos - best_mlen; + // printf("%d: start=%d best_mlen=%d best_off=%d cur=%d\n", (int)(ip - istart), (int)(start - ip), (int)best_mlen, (int)best_off, cur); /* store sequence */ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set for (int i = 1; i <= last_pos; i++) - LZ5_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); - LZ5_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)((char*)ip-source+cur), cur, last_pos, best_mlen, best_off, opt[cur].rep); + LZ5_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-istart+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + LZ5_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-istart+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); opt[0].mlen = 1; @@ -539,7 +552,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set for (int i = 0; i <= last_pos;) { - LZ5_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + LZ5_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-istart+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); i += opt[i].mlen; } @@ -547,13 +560,28 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set while (cur < last_pos) { - LZ5_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); + LZ5_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-istart+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); mlen = opt[cur].mlen; if (mlen == 1) { ip++; cur++; continue; } offset = opt[cur].off; cur += mlen; - LZ5_LOG_ENCODE("%d: ENCODE literals=%d off=%d mlen=%d ", (int)((char*)ip-source), (int)(ip-anchor), (int)(offset), mlen); +#if 0 + if (offset) + { + size_t ml2 = ZSTD_count(start, start-offset, iend); + printf("%d: mlen=%d offset=%d\n", (int)(ip - istart), (int)mlen, (int)offset); + if (ml2 < mlen) + { + printf("%d: start=%d iend=%d mlen=%d offset=%d ml2=%d\n", (int)(ip - istart), (int)(start - ip), (int)(iend - ip), (int)mlen, (int)offset, (int)ml2); + exit(0); + } + } + else + printf("%d: mlen=%d offset=%d\n", (int)(ip - istart), (int)mlen, (int)offset); +#endif + + LZ5_LOG_ENCODE("%d: ENCODE literals=%d off=%d mlen=%d ", (int)(ip-istart), (int)(ip-anchor), (int)(offset), (int)mlen); size_t litLength = start - anchor; ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); anchor = ip = start + mlen; @@ -561,8 +589,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set if (offset) rep_2 = rep_1, rep_1 = offset; - LZ5_LOG_ENCODE("out=%d\n", (int)((char*)op - dest)); - LZ5_LOG_PARSER("%d: offset=%d rep=%d\n", (int)((char*)ip-source), offset, rep); + LZ5_LOG_PARSER("%d: offset=%d rep=%d\n", (int)(ip-istart), (int)offset, (int)rep_1); } From 6b0715b8fd4bb0339c091ab85d4d69605aa1cac2 Mon Sep 17 00:00:00 2001 From: inikep Date: Sun, 31 Jan 2016 15:17:50 +0100 Subject: [PATCH 007/113] no "start" --- lib/zstd_opt.c | 256 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 237 insertions(+), 19 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 18fe2329c..e93fcfbcd 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -427,7 +427,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, LZ5HC_optimal_t opt[LZ5_OPT_NUM+4]; LZ5HC_match_t matches[LZ5_OPT_NUM+1]; const uint8_t *inr; - int res, cur, cur2, cur_min, skip_num = 0; + int cur, cur2, cur_min, skip_num = 0; int llen, litlen, price, match_num, last_pos; const int sufficient_len = 128; //ctx->params.sufficientLength; @@ -442,20 +442,19 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, size_t mlen=0; size_t best_mlen=0; size_t best_off=0; - const BYTE* start=ip+1; memset(opt, 0, sizeof(LZ5HC_optimal_t)); last_pos = 0; llen = ip - anchor; inr = ip; /* check repCode */ - if (MEM_read32(start) == MEM_read32(start - rep_1)) { + if (MEM_read32(ip+1) == MEM_read32(ip+1 - rep_1)) { /* repcode : we take it */ - mlen = ZSTD_count(start+MINMATCH, start+MINMATCH-rep_1, iend) + MINMATCH; + mlen = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-rep_1, iend) + MINMATCH; LZ5_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)(ip-istart), (int)rep_1, (int)mlen); if (depth==0 || mlen > sufficient_len || mlen >= LZ5_OPT_NUM) { - best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; + ip++; best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; goto _storeSequence; } @@ -463,14 +462,13 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, { litlen = 0; price = LZ5HC_get_price(llen, 0, mlen - MINMATCH) - llen; - if (mlen > last_pos || price < opt[mlen].price) - SET_PRICE(mlen, mlen, 0, litlen, price); + if (mlen + 1 > last_pos || price < opt[mlen + 1].price) + SET_PRICE(mlen + 1, mlen, 0, litlen, price); mlen--; } while (mlen >= MINMATCH); } - // best_mlen = (last_pos) ? last_pos : MINMATCH; if (faster_get_matches && last_pos) @@ -486,7 +484,6 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (match_num && matches[match_num-1].len > sufficient_len) { - start = ip; best_mlen = matches[match_num-1].len; best_off = matches[match_num-1].off; cur = 0; @@ -517,17 +514,238 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, // printf("%d: last_pos=%d\n", (int)(ip - istart), (int)last_pos); - opt[0].rep = rep_1; - opt[0].mlen = 1; + opt[0].rep = opt[1].rep = rep_1; + opt[0].mlen = opt[1].mlen = 1; +#if 0 + // check further positions + for (skip_num = 0, cur = 1; cur <= last_pos; cur++) + { + inr = ip + cur; + + if (opt[cur-1].mlen == 1) + { + litlen = opt[cur-1].litlen + 1; + + if (cur != litlen) + { + price = opt[cur - litlen].price + LZ5_LIT_ONLY_COST(litlen); + LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)((char*)inr-source), cur - litlen, opt[cur - litlen].price, price, cur, litlen); + } + else + { + price = LZ5_LIT_ONLY_COST(llen + litlen) - llen; + LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)((char*)inr-source), price, cur, litlen, llen); + } + } + else + { + litlen = 1; + price = opt[cur - 1].price + LZ5_LIT_ONLY_COST(litlen); + LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)((char*)inr-source), price, cur, litlen, LZ5_LIT_ONLY_COST(litlen)); + } + + mlen = 1; + best_mlen = 0; + LZ5_LOG_PARSER("%d: TRY price=%d opt[%d].price=%d\n", (int)((char*)inr-source), price, cur, opt[cur].price); + + if (cur > last_pos || price <= opt[cur].price) // || ((price == opt[cur].price) && (opt[cur-1].mlen == 1) && (cur != litlen))) + SET_PRICE(cur, mlen, best_mlen, litlen, price); + + if (cur == last_pos) break; + + if (opt[cur].mlen > 1) + { + mlen = opt[cur].mlen; + if (opt[cur].off < 1) + { + opt[cur].rep = opt[cur-mlen].rep; + LZ5_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d\n", (int)((char*)inr-source), cur, mlen, opt[cur-mlen].rep); + } + else + { + opt[cur].rep = 0; + LZ5_LOG_PARSER("%d: COPYREP2 cur=%d offset=%d rep=%d\n", (int)((char*)inr-source), cur, 0, opt[cur].rep); + } + } + else + { + opt[cur].rep = opt[cur-1].rep; // copy rep + } + + + LZ5_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)inr-source), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); + + // check rep + // best_mlen = 0; + mlen = ZSTD_count(inr, inr - opt[cur].rep, iend); + if (mlen >= MINMATCH && mlen > best_mlen) + { + LZ5_LOG_PARSER("%d: try REP rep=%d mlen=%d\n", (int)((char*)inr-source), opt[cur].rep, mlen); + LZ5_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)((char*)inr-source), mlen, 0, opt[cur].rep, cur, opt[cur].off); + + if (mlen > sufficient_len || cur + mlen >= LZ5_OPT_NUM) + { + best_mlen = mlen; + best_off = 0; + LZ5_LOG_PARSER("%d: REP sufficient_len=%d best_mlen=%d best_off=%d last_pos=%d\n", (int)((char*)inr-source), sufficient_len, best_mlen, best_off, last_pos); + last_pos = cur + 1; + goto encode; + } + + if (opt[cur].mlen == 1) + { + litlen = opt[cur].litlen; + + if (cur != litlen) + { + price = opt[cur - litlen].price + LZ5HC_get_price(litlen, 0, mlen - MINMATCH); + LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)((char*)inr-source), cur - litlen, opt[cur - litlen].price, price, cur, litlen); + } + else + { + price = LZ5HC_get_price(llen + litlen, 0, mlen - MINMATCH) - llen; + LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)((char*)inr-source), price, cur, litlen, llen); + } + } + else + { + litlen = 0; + price = opt[cur].price + LZ5HC_get_price(litlen, 0, mlen - MINMATCH); + LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d getprice=%d\n", (int)((char*)inr-source), price, cur, litlen, LZ5HC_get_price(litlen, 0, mlen - MINMATCH)); + } + + best_mlen = mlen; + if (faster_get_matches) + skip_num = best_mlen; + + LZ5_LOG_PARSER("%d: Found REP mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)((char*)inr-source), mlen, 0, price, litlen, cur - litlen, opt[cur - litlen].price); + + do + { + if (cur + mlen > last_pos || price <= opt[cur + mlen].price) // || ((price == opt[cur + mlen].price) && (opt[cur].mlen == 1) && (cur != litlen))) // at equal price prefer REP instead of MATCH + SET_PRICE(cur + mlen, mlen, 0, litlen, price); + mlen--; + } + while (mlen >= MINMATCH); + } + + if (faster_get_matches && skip_num > 0) + { + skip_num--; + continue; + } + + + best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; + + match_num = getAllMatches(ctx, inr, iend, maxSearches, mls, matches); + // match_num = LZ5HC_GetAllMatches(ctx, inr, ip, matchlimit, best_mlen, matches); + LZ5_LOG_PARSER("%d: LZ5HC_GetAllMatches match_num=%d\n", (int)((char*)inr-source), match_num); + + + if (match_num > 0 && matches[match_num-1].len > sufficient_len) + { + cur -= matches[match_num-1].back; + best_mlen = matches[match_num-1].len; + best_off = matches[match_num-1].off; + last_pos = cur + 1; + goto encode; + } + + cur_min = cur; + + // set prices using matches at position = cur + for (int i = 0; i < match_num; i++) + { + mlen = (i>0) ? matches[i-1].len+1 : best_mlen; + cur2 = cur - matches[i].back; + best_mlen = (cur2 + matches[i].len < LZ5_OPT_NUM) ? matches[i].len : LZ5_OPT_NUM - cur2; + LZ5_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)((char*)inr-source), cur, cur2, matches[i].len, matches[i].off, best_mlen, last_pos); + + while (mlen <= best_mlen) + { + if (opt[cur2].mlen == 1) + { + litlen = opt[cur2].litlen; + + if (cur2 != litlen) + price = opt[cur2 - litlen].price + LZ5HC_get_price(litlen, matches[i].off, mlen - MINMATCH); + else + price = LZ5HC_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - llen; + } + else + { + litlen = 0; + price = opt[cur2].price + LZ5HC_get_price(litlen, matches[i].off, mlen - MINMATCH); + } + + LZ5_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)((char*)inr-source), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); + if (cur2 + mlen > last_pos || price < opt[cur2 + mlen].price) + { + SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); + + opt[cur2 + mlen].rep = matches[i].off; // update reps + if (cur2 < cur_min) cur_min = cur2; + } + + mlen++; + } + } + + if (cur_min < cur) + { + for (int i=cur_min-1; i<=last_pos; i++) + { + LZ5_LOG_PARSER("%d: BEFORE price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + } + + for (int i=cur_min+1; i<=last_pos; i++) + if (opt[i].price < (1<<30) && (opt[i].off) < 1 && i - opt[i].mlen > cur_min) // invalidate reps + { + if (opt[i-1].mlen == 1) + { + litlen = opt[i-1].litlen + 1; + + if (i != litlen) + { + price = opt[i - litlen].price + LZ5_LIT_ONLY_COST(litlen); + // LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), i - litlen, opt[i - litlen].price, price, i, litlen); + } + else + { + price = LZ5_LIT_ONLY_COST(llen + litlen) - llen; + // LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, i, litlen, llen); + } + } + else + { + litlen = 1; + price = opt[i - 1].price + LZ5_LIT_ONLY_COST(litlen); + // LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d\n", (int)(inr-base), price, i, litlen); + } + + mlen = 1; + best_mlen = 0; + SET_PRICE(i, mlen, best_mlen, litlen, price); + + opt[i].rep = opt[i-1].rep; // copy reps + + LZ5_LOG_PARSER("%d: INVALIDATE pred=%d price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)inr-source), cur-cur_min, i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + } + + for (int i=cur_min-1; i<=last_pos; i++) + { + LZ5_LOG_PARSER("%d: AFTER price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + } + + } + } // for (skip_num = 0, cur = 1; cur <= last_pos; cur++) +#endif best_mlen = opt[last_pos].mlen; best_off = opt[last_pos].off; - if (best_off) - start = ip; - cur = 0; - last_pos = 1; -// cur = last_pos - best_mlen; + cur = last_pos - best_mlen; // printf("%d: start=%d best_mlen=%d best_off=%d cur=%d\n", (int)(ip - istart), (int)(start - ip), (int)best_mlen, (int)best_off, cur); /* store sequence */ @@ -537,8 +755,8 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set LZ5_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-istart+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); opt[0].mlen = 1; - size_t offset; + while (cur >= 0) { mlen = opt[cur].mlen; @@ -582,9 +800,9 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set #endif LZ5_LOG_ENCODE("%d: ENCODE literals=%d off=%d mlen=%d ", (int)(ip-istart), (int)(ip-anchor), (int)(offset), (int)mlen); - size_t litLength = start - anchor; + size_t litLength = ip - anchor; ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); - anchor = ip = start + mlen; + anchor = ip = ip + mlen; if (offset) rep_2 = rep_1, rep_1 = offset; From ef2706ed127cc265956a6ecd9943150ffe98ddc2 Mon Sep 17 00:00:00 2001 From: inikep Date: Sun, 31 Jan 2016 15:32:01 +0100 Subject: [PATCH 008/113] in progress --- lib/zstd_opt.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index e93fcfbcd..d6affc62a 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -458,7 +458,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, goto _storeSequence; } - do +/* do { litlen = 0; price = LZ5HC_get_price(llen, 0, mlen - MINMATCH) - llen; @@ -466,7 +466,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, SET_PRICE(mlen + 1, mlen, 0, litlen, price); mlen--; } - while (mlen >= MINMATCH); + while (mlen >= MINMATCH);*/ } // best_mlen = (last_pos) ? last_pos : MINMATCH; @@ -517,7 +517,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, opt[0].rep = opt[1].rep = rep_1; opt[0].mlen = opt[1].mlen = 1; -#if 0 +#if 1 // check further positions for (skip_num = 0, cur = 1; cur <= last_pos; cur++) { @@ -576,6 +576,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, LZ5_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)inr-source), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); +#if 0 // check rep // best_mlen = 0; mlen = ZSTD_count(inr, inr - opt[cur].rep, iend); @@ -590,7 +591,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, best_off = 0; LZ5_LOG_PARSER("%d: REP sufficient_len=%d best_mlen=%d best_off=%d last_pos=%d\n", (int)((char*)inr-source), sufficient_len, best_mlen, best_off, last_pos); last_pos = cur + 1; - goto encode; + goto _storeSequence; } if (opt[cur].mlen == 1) @@ -629,6 +630,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } while (mlen >= MINMATCH); } +#endif if (faster_get_matches && skip_num > 0) { @@ -650,7 +652,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, best_mlen = matches[match_num-1].len; best_off = matches[match_num-1].off; last_pos = cur + 1; - goto encode; + goto _storeSequence; } cur_min = cur; From 59140c5480f1d7bdd55aa8c6f68ce51e8934f7c7 Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 2 Feb 2016 12:36:09 +0100 Subject: [PATCH 009/113] turn off: last match must start at a minimum distance of 8 from oend --- lib/zstd_compress.c | 5 +- lib/zstd_decompress.c | 2 +- lib/zstd_opt.c | 103 +++++++++++++++++++++++++++++++++--------- 3 files changed, 85 insertions(+), 25 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index c0fce45f5..47dd51236 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -2302,8 +2302,8 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 25, 24, 23, 5, 5, ZSTD_btlazy2 }, /* level 18 */ { 0, 25, 26, 23, 5, 5, ZSTD_btlazy2 }, /* level 19 */ { 0, 26, 27, 25, 9, 5, ZSTD_btlazy2 }, /* level 20 */ - { 0, 22, 20, 22, 4, 4, ZSTD_lazy2 }, /* level 11 + L=4 */ // 41902762 - { 0, 23, 21, 22, 5, 4, ZSTD_btlazy2 }, /* level 16 + L=4 */ // 41233150 + { 0, 22, 20, 22, 4, 4, ZSTD_lazy2 }, /* level 11 + L=4 */ // 41902762 42087013 + { 0, 23, 21, 22, 5, 4, ZSTD_btlazy2 }, /* level 16 + L=4 */ // 41233150 41560211 { 0, 23, 21, 22, 5, 4, ZSTD_opt }, /* level 23 */ { 0, 23, 21, 22, 5, 4, ZSTD_opt_bt }, /* level 23 */ }, @@ -2402,6 +2402,7 @@ ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint) int tableID = ((srcSizeHint-1) <= 256 KB) + ((srcSizeHint-1) <= 128 KB) + ((srcSizeHint-1) <= 16 KB); /* intentional underflow for srcSizeHint == 0 */ if (compressionLevel<=0) compressionLevel = 1; if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL; +tableID=0; result = ZSTD_defaultParameters[tableID][compressionLevel]; result.srcSize = srcSizeHint; return result; diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 6061c8741..31fb70069 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -697,7 +697,7 @@ FORCE_INLINE size_t ZSTD_execSequence(BYTE* op, const BYTE* match = oLitEnd - sequence.offset; /* check */ - if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of 8 from oend */ + // if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of 8 from oend */ if (oMatchEnd > oend) return ERROR(dstSize_tooSmall); /* overwrite beyond dst buffer */ if (litEnd > litLimit_8) return ERROR(corruption_detected); /* risk read beyond lit buffer */ diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index d6affc62a..ff4b2f2e4 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -260,12 +260,31 @@ FORCE_INLINE size_t ZSTD_HcGetAllMatches_selectMLS ( } +void print_hex_text(uint8_t* buf, int bufsize, int endline) +{ + int i, j; + for (i=0; i32?buf[i+j]:'.'); + printf("\n"); + } + if (endline) printf("\n"); +} + /* ******************************* * Optimal parser OLD *********************************/ FORCE_INLINE -void ZSTD_compressBlock_opt_generic_OLD(ZSTD_CCtx* ctx, +void ZSTD_compressBlock_opt2_generic(ZSTD_CCtx* ctx, const void* src, size_t srcSize, const U32 searchMethod, const U32 depth) { @@ -301,7 +320,7 @@ void ZSTD_compressBlock_opt_generic_OLD(ZSTD_CCtx* ctx, size_t offset=0; const BYTE* start=ip+1; -#if 1 +#ifdef ZSTD_USE_REP /* check repCode */ if (MEM_read32(start) == MEM_read32(start - offset_1)) { /* repcode : we take it */ @@ -312,16 +331,16 @@ void ZSTD_compressBlock_opt_generic_OLD(ZSTD_CCtx* ctx, { /* first search (depth 0) */ -#if 0 +#if 1 size_t offsetFound = 99999999; size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls); if (ml2 > matchLength) - matchLength = ml2, start = ip, offset=offsetFound; + start=ip, matchLength = ml2, offset=offsetFound; #else size_t mnum = getAllMatches(ctx, ip, iend, maxSearches, mls, matches); if (mnum > 0) { if (matches[mnum-1].len > matchLength) - matchLength = matches[mnum-1].len, start = ip, offset=matches[mnum-1].off; + start=ip, matchLength = matches[mnum-1].len, offset=matches[mnum-1].off; } #endif } @@ -332,11 +351,12 @@ void ZSTD_compressBlock_opt_generic_OLD(ZSTD_CCtx* ctx, continue; } -#if 0 +#if 1 /* let's try to find a better solution */ if (depth>=1) while (ip= MINMATCH) && (gain2 > gain1)) matchLength = mlRep, offset = 0, start = ip; } +#endif { size_t offset2=999999; size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls); @@ -369,11 +390,12 @@ void ZSTD_compressBlock_opt_generic_OLD(ZSTD_CCtx* ctx, _storeSequence: { size_t litLength = start - anchor; + LZ5_LOG_ENCODE("%d/%d: ENCODE literals=%d off=%d mlen=%d\n", (int)(ip-istart), (int)(iend-istart), (int)(litLength), (int)(offset), (int)matchLength); ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH); anchor = ip = start + matchLength; } -#if 1 /* check immediate repcode */ +#ifdef ZSTD_USE_REP /* check immediate repcode */ while ( (ip <= ilimit) && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) { /* store sequence */ @@ -392,6 +414,7 @@ _storeSequence: /* Last Literals */ { size_t lastLLSize = iend - anchor; + LZ5_LOG_ENCODE("%d/%d: ENCODE lastLLSize=%d\n", (int)(ip-istart), (int)(iend-istart), (int)(lastLLSize)); memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } @@ -433,20 +456,25 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, const int sufficient_len = 128; //ctx->params.sufficientLength; const int faster_get_matches = 0;//(ctx->params.strategy == ZSTD_opt); + + // printf("orig_file="); print_hex_text(ip, srcSize, 0); + /* init */ ZSTD_resetSeqStore(seqStorePtr); if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE; + /* Match Loop */ while (ip < ilimit) { - size_t mlen=0; - size_t best_mlen=0; - size_t best_off=0; + int mlen=0; + int best_mlen=0; + int best_off=0; memset(opt, 0, sizeof(LZ5HC_optimal_t)); last_pos = 0; llen = ip - anchor; inr = ip; +#if 0 /* check repCode */ if (MEM_read32(ip+1) == MEM_read32(ip+1 - rep_1)) { /* repcode : we take it */ @@ -468,6 +496,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } while (mlen >= MINMATCH);*/ } +#endif // best_mlen = (last_pos) ? last_pos : MINMATCH; @@ -514,8 +543,10 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, // printf("%d: last_pos=%d\n", (int)(ip - istart), (int)last_pos); - opt[0].rep = opt[1].rep = rep_1; - opt[0].mlen = opt[1].mlen = 1; + // opt[0].rep = opt[1].rep = rep_1; + // opt[0].mlen = opt[1].mlen = 1; + opt[0].rep = rep_1; + opt[0].mlen = 1; #if 1 // check further positions @@ -786,23 +817,46 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set offset = opt[cur].off; cur += mlen; -#if 0 +#if 1 if (offset) { - size_t ml2 = ZSTD_count(start, start-offset, iend); - printf("%d: mlen=%d offset=%d\n", (int)(ip - istart), (int)mlen, (int)offset); - if (ml2 < mlen) + size_t ml2 = ZSTD_count(ip, ip-offset, iend); + // printf("%d: mlen=%d offset=%d\n", (int)(ip - istart), (int)mlen, (int)offset); + if (ml2 < mlen && ml2 < MINMATCH) { - printf("%d: start=%d iend=%d mlen=%d offset=%d ml2=%d\n", (int)(ip - istart), (int)(start - ip), (int)(iend - ip), (int)mlen, (int)offset, (int)ml2); + printf("ERROR %d: iend=%d mlen=%d offset=%d ml2=%d\n", (int)(ip - istart), (int)(iend - ip), (int)mlen, (int)offset, (int)ml2); exit(0); } } else - printf("%d: mlen=%d offset=%d\n", (int)(ip - istart), (int)mlen, (int)offset); + printf("ERROR %d: mlen=%d offset=%d\n", (int)(ip - istart), (int)mlen, (int)offset); + + if (ip < anchor) + { + printf("ERROR %d: ip < anchor iend=%d mlen=%d offset=%d\n", (int)(ip - istart), (int)(iend - ip), (int)mlen, (int)offset); + exit(0); + } + if (ip - offset < base) + { + printf("ERROR %d: ip - offset < istart iend=%d mlen=%d offset=%d\n", (int)(ip - istart), (int)(iend - ip), (int)mlen, (int)offset); + exit(0); + } + if (mlen < MINMATCH) + { + printf("ERROR %d: mlen < MINMATCH iend=%d mlen=%d offset=%d\n", (int)(ip - istart), (int)(iend - ip), (int)mlen, (int)offset); + exit(0); + } + if (ip + mlen > iend) + { + printf("ERROR %d: ip + mlen >= iend iend=%d mlen=%d offset=%d\n", (int)(ip - istart), (int)(iend - ip), (int)mlen, (int)offset); + exit(0); + } #endif - LZ5_LOG_ENCODE("%d: ENCODE literals=%d off=%d mlen=%d ", (int)(ip-istart), (int)(ip-anchor), (int)(offset), (int)mlen); size_t litLength = ip - anchor; + LZ5_LOG_ENCODE("%d/%d: ENCODE literals=%d off=%d mlen=%d\n", (int)(ip-istart), (int)(iend-istart), (int)(litLength), (int)(offset), (int)mlen); + // printf("orig="); print_hex_text(ip, mlen, 0); + // printf("match="); print_hex_text(ip-offset, mlen, 0); ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); anchor = ip = ip + mlen; @@ -813,7 +867,8 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set } - /* check immediate repcode */ +#if 0 + // check immediate repcode while ( (ip <= ilimit) && (MEM_read32(ip) == MEM_read32(ip - rep_2)) ) { /* store sequence */ @@ -824,12 +879,16 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, best_mlen); ip += best_mlen+MINMATCH; anchor = ip; - continue; /* faster when present ... (?) */ - } } + continue; // faster when present ... (?) + } +#endif + + } /* Last Literals */ { size_t lastLLSize = iend - anchor; + LZ5_LOG_ENCODE("%d: lastLLSize literals=%d\n", (int)(ip-istart), (int)(lastLLSize)); memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } From e1b8e53e841fac58c281d3930a4d3086a6d0f68e Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 2 Feb 2016 15:41:16 +0100 Subject: [PATCH 010/113] better logging --- .gitignore | 2 + lib/zstd_compress.c | 4 +- lib/zstd_opt.c | 626 ++++++++------------------------------------ 3 files changed, 112 insertions(+), 520 deletions(-) diff --git a/.gitignore b/.gitignore index 9c7737f4c..8b7aa0c3c 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,5 @@ ipch/ .directory _codelite _zstdbench + +lib/zstd_opt_LZ5.c \ No newline at end of file diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 47dd51236..fe9bde30c 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -2302,8 +2302,8 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 25, 24, 23, 5, 5, ZSTD_btlazy2 }, /* level 18 */ { 0, 25, 26, 23, 5, 5, ZSTD_btlazy2 }, /* level 19 */ { 0, 26, 27, 25, 9, 5, ZSTD_btlazy2 }, /* level 20 */ - { 0, 22, 20, 22, 4, 4, ZSTD_lazy2 }, /* level 11 + L=4 */ // 41902762 42087013 - { 0, 23, 21, 22, 5, 4, ZSTD_btlazy2 }, /* level 16 + L=4 */ // 41233150 41560211 + { 0, 22, 20, 22, 4, 4, ZSTD_lazy2 }, /* level 11 + L=4 */ // 41902762 lazy1=42087013 norep1=42911693 + { 0, 23, 21, 22, 5, 4, ZSTD_btlazy2 }, /* level 16 + L=4 */ // 41233150 btlazy1=41560211 norep1=42322286 { 0, 23, 21, 22, 5, 4, ZSTD_opt }, /* level 23 */ { 0, 23, 21, 22, 5, 4, ZSTD_opt_bt }, /* level 23 */ }, diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index ff4b2f2e4..23b6556bc 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -16,41 +16,49 @@ typedef struct int rep; } LZ5HC_optimal_t; - -#define LZ5HC_DEBUG(fmt, args...) ;//printf(fmt, ##args) -#define LZ5_LOG_PARSER(fmt, args...) ;// printf(fmt, ##args) -#define LZ5_LOG_PRICE(fmt, args...) ;//printf(fmt, ##args) -#define LZ5_LOG_ENCODE(fmt, args...) ;//printf(fmt, ##args) +#if 1 + #define LZ5_LOG_PARSER(fmt, args...) ;// printf(fmt, ##args) + #define LZ5_LOG_PRICE(fmt, args...) ;//printf(fmt, ##args) + #define LZ5_LOG_ENCODE(fmt, args...) ;//printf(fmt, ##args) +#else + #define LZ5_LOG_PARSER(fmt, args...) printf(fmt, ##args) + #define LZ5_LOG_PRICE(fmt, args...) printf(fmt, ##args) + #define LZ5_LOG_ENCODE(fmt, args...) printf(fmt, ##args) +#endif #define LZ5_OPT_NUM (1<<12) -#define LZ5_SHORT_OFFSET_BITS 10 -#define LZ5_SHORT_OFFSET_DISTANCE (1<stateLL), &(seqState->DStream)); +offsetCode = FSE_decodeSymbol(&(seqState->stateOffb), &(seqState->DStream)); +matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); +HUF_decompress(dst, litSize, ip+5, litCSize) -#define LZ5_SHORT_LITERALS ((1<= maxValue then use additional 1 byte (if value < +maxValue+255) or 3 bytes (to encode value up to MaxValue+255+65535). -#define LZ5_SHORT_LITLEN_COST(len) (len LZ5_MID_OFFSET_DISTANCE) || (offset 1 && mlen < MINMATCH) { printf("%d: ERROR SET price[%d/%d]=%d litlen=%d len=%d off=%d\n", (int)(inr-base), (int)pos, (int)last_pos, opt[pos].price, opt[pos].litlen, opt[pos].mlen, opt[pos].off); exit(0); }; \ } @@ -121,13 +130,16 @@ size_t ZSTD_insertBtAndGetAllMatches ( if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) ) bestLength = matchLength, *offsetPtr = current - matchIndex; #else - if (mnum == 0 || (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)matches[mnum-1].off+1)) ) + if (mnum == 0 || (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)matches[mnum-1].off+1)) ) { - bestLength = matchLength; - matches[mnum].off = current - matchIndex; - matches[mnum].len = matchLength; - matches[mnum].back = 0; - mnum++; + if (matchLength >= MINMATCH) + { + bestLength = matchLength; + matches[mnum].off = current - matchIndex; + matches[mnum].len = matchLength; + matches[mnum].back = 0; + mnum++; + } if (matchLength > LZ5_OPT_NUM) break; } #endif @@ -303,13 +315,16 @@ void ZSTD_compressBlock_opt2_generic(ZSTD_CCtx* ctx, typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr, U32 maxNbAttempts, U32 matchLengthSearch); + searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS; + + #if 0 typedef size_t (*getAllMatches_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, U32 maxNbAttempts, U32 matchLengthSearch, LZ5HC_match_t* matches); - searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS; getAllMatches_f getAllMatches = searchMethod ? ZSTD_BtGetAllMatches_selectMLS : ZSTD_HcGetAllMatches_selectMLS; LZ5HC_match_t matches[LZ5_OPT_NUM+1]; - +#endif + /* init */ ZSTD_resetSeqStore(seqStorePtr); if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE; @@ -320,6 +335,7 @@ void ZSTD_compressBlock_opt2_generic(ZSTD_CCtx* ctx, size_t offset=0; const BYTE* start=ip+1; +//#define ZSTD_USE_REP #ifdef ZSTD_USE_REP /* check repCode */ if (MEM_read32(start) == MEM_read32(start - offset_1)) { @@ -390,7 +406,7 @@ void ZSTD_compressBlock_opt2_generic(ZSTD_CCtx* ctx, _storeSequence: { size_t litLength = start - anchor; - LZ5_LOG_ENCODE("%d/%d: ENCODE literals=%d off=%d mlen=%d\n", (int)(ip-istart), (int)(iend-istart), (int)(litLength), (int)(offset), (int)matchLength); + LZ5_LOG_ENCODE("%d/%d: ENCODE literals=%d off=%d mlen=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)(offset), (int)matchLength); ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH); anchor = ip = start + matchLength; } @@ -414,7 +430,7 @@ _storeSequence: /* Last Literals */ { size_t lastLLSize = iend - anchor; - LZ5_LOG_ENCODE("%d/%d: ENCODE lastLLSize=%d\n", (int)(ip-istart), (int)(iend-istart), (int)(lastLLSize)); + LZ5_LOG_ENCODE("%d/%d: ENCODE lastLLSize=%d\n", (int)(ip-base), (int)(iend-base), (int)(lastLLSize)); memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } @@ -454,7 +470,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, int llen, litlen, price, match_num, last_pos; const int sufficient_len = 128; //ctx->params.sufficientLength; - const int faster_get_matches = 0;//(ctx->params.strategy == ZSTD_opt); + const int faster_get_matches = (ctx->params.strategy == ZSTD_opt); // printf("orig_file="); print_hex_text(ip, srcSize, 0); @@ -474,13 +490,13 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, llen = ip - anchor; inr = ip; -#if 0 +#ifdef ZSTD_USE_REP /* check repCode */ if (MEM_read32(ip+1) == MEM_read32(ip+1 - rep_1)) { /* repcode : we take it */ mlen = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-rep_1, iend) + MINMATCH; - LZ5_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)(ip-istart), (int)rep_1, (int)mlen); + LZ5_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)(ip-base), (int)rep_1, (int)mlen); if (depth==0 || mlen > sufficient_len || mlen >= LZ5_OPT_NUM) { ip++; best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; goto _storeSequence; @@ -498,7 +514,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } #endif - // best_mlen = (last_pos) ? last_pos : MINMATCH; + best_mlen = (last_pos) ? last_pos : MINMATCH; if (faster_get_matches && last_pos) match_num = 0; @@ -508,7 +524,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, match_num = getAllMatches(ctx, ip, iend, maxSearches, mls, matches); } - LZ5_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-istart), match_num, last_pos); + LZ5_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); if (!last_pos && !match_num) { ip++; continue; } if (match_num && matches[match_num-1].len > sufficient_len) @@ -525,7 +541,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, { mlen = (i>0) ? matches[i-1].len+1 : best_mlen; best_mlen = (matches[i].len < LZ5_OPT_NUM) ? matches[i].len : LZ5_OPT_NUM; - LZ5_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(ip-istart), matches[i].len, matches[i].off, (int)best_mlen, (int)last_pos); + LZ5_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(ip-base), matches[i].len, matches[i].off, (int)best_mlen, (int)last_pos); while (mlen <= best_mlen) { litlen = 0; @@ -541,14 +557,14 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ip++; continue; } - // printf("%d: last_pos=%d\n", (int)(ip - istart), (int)last_pos); + // printf("%d: last_pos=%d\n", (int)(ip - base), (int)last_pos); // opt[0].rep = opt[1].rep = rep_1; // opt[0].mlen = opt[1].mlen = 1; opt[0].rep = rep_1; opt[0].mlen = 1; -#if 1 + // check further positions for (skip_num = 0, cur = 1; cur <= last_pos; cur++) { @@ -561,24 +577,24 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (cur != litlen) { price = opt[cur - litlen].price + LZ5_LIT_ONLY_COST(litlen); - LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)((char*)inr-source), cur - litlen, opt[cur - litlen].price, price, cur, litlen); + LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); } else { price = LZ5_LIT_ONLY_COST(llen + litlen) - llen; - LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)((char*)inr-source), price, cur, litlen, llen); + LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, cur, litlen, llen); } } else { litlen = 1; price = opt[cur - 1].price + LZ5_LIT_ONLY_COST(litlen); - LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)((char*)inr-source), price, cur, litlen, LZ5_LIT_ONLY_COST(litlen)); + LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)(inr-base), price, cur, litlen, LZ5_LIT_ONLY_COST(litlen)); } mlen = 1; best_mlen = 0; - LZ5_LOG_PARSER("%d: TRY price=%d opt[%d].price=%d\n", (int)((char*)inr-source), price, cur, opt[cur].price); + LZ5_LOG_PRICE("%d: TRY4 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur, opt[cur].price); if (cur > last_pos || price <= opt[cur].price) // || ((price == opt[cur].price) && (opt[cur-1].mlen == 1) && (cur != litlen))) SET_PRICE(cur, mlen, best_mlen, litlen, price); @@ -591,12 +607,12 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (opt[cur].off < 1) { opt[cur].rep = opt[cur-mlen].rep; - LZ5_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d\n", (int)((char*)inr-source), cur, mlen, opt[cur-mlen].rep); + LZ5_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d\n", (int)(inr-base), cur, mlen, opt[cur-mlen].rep); } else { opt[cur].rep = 0; - LZ5_LOG_PARSER("%d: COPYREP2 cur=%d offset=%d rep=%d\n", (int)((char*)inr-source), cur, 0, opt[cur].rep); + LZ5_LOG_PARSER("%d: COPYREP2 cur=%d offset=%d rep=%d\n", (int)(inr-base), cur, 0, opt[cur].rep); } } else @@ -605,22 +621,22 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } - LZ5_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)inr-source), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); + LZ5_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); -#if 0 +#ifdef ZSTD_USE_REP // check rep // best_mlen = 0; mlen = ZSTD_count(inr, inr - opt[cur].rep, iend); if (mlen >= MINMATCH && mlen > best_mlen) { - LZ5_LOG_PARSER("%d: try REP rep=%d mlen=%d\n", (int)((char*)inr-source), opt[cur].rep, mlen); - LZ5_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)((char*)inr-source), mlen, 0, opt[cur].rep, cur, opt[cur].off); + LZ5_LOG_PARSER("%d: try REP rep=%d mlen=%d\n", (int)(inr-base), opt[cur].rep, mlen); + LZ5_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep, cur, opt[cur].off); if (mlen > sufficient_len || cur + mlen >= LZ5_OPT_NUM) { best_mlen = mlen; best_off = 0; - LZ5_LOG_PARSER("%d: REP sufficient_len=%d best_mlen=%d best_off=%d last_pos=%d\n", (int)((char*)inr-source), sufficient_len, best_mlen, best_off, last_pos); + LZ5_LOG_PARSER("%d: REP sufficient_len=%d best_mlen=%d best_off=%d last_pos=%d\n", (int)(inr-base), sufficient_len, best_mlen, best_off, last_pos); last_pos = cur + 1; goto _storeSequence; } @@ -632,26 +648,26 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (cur != litlen) { price = opt[cur - litlen].price + LZ5HC_get_price(litlen, 0, mlen - MINMATCH); - LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)((char*)inr-source), cur - litlen, opt[cur - litlen].price, price, cur, litlen); + LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); } else { price = LZ5HC_get_price(llen + litlen, 0, mlen - MINMATCH) - llen; - LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)((char*)inr-source), price, cur, litlen, llen); + LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, cur, litlen, llen); } } else { litlen = 0; price = opt[cur].price + LZ5HC_get_price(litlen, 0, mlen - MINMATCH); - LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d getprice=%d\n", (int)((char*)inr-source), price, cur, litlen, LZ5HC_get_price(litlen, 0, mlen - MINMATCH)); + LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d getprice=%d\n", (int)(inr-base), price, cur, litlen, LZ5HC_get_price(litlen, 0, mlen - MINMATCH)); } best_mlen = mlen; if (faster_get_matches) skip_num = best_mlen; - LZ5_LOG_PARSER("%d: Found REP mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)((char*)inr-source), mlen, 0, price, litlen, cur - litlen, opt[cur - litlen].price); + LZ5_LOG_PARSER("%d: Found REP mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), mlen, 0, price, litlen, cur - litlen, opt[cur - litlen].price); do { @@ -674,7 +690,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, match_num = getAllMatches(ctx, inr, iend, maxSearches, mls, matches); // match_num = LZ5HC_GetAllMatches(ctx, inr, ip, matchlimit, best_mlen, matches); - LZ5_LOG_PARSER("%d: LZ5HC_GetAllMatches match_num=%d\n", (int)((char*)inr-source), match_num); + LZ5_LOG_PARSER("%d: LZ5HC_GetAllMatches match_num=%d\n", (int)(inr-base), match_num); if (match_num > 0 && matches[match_num-1].len > sufficient_len) @@ -694,7 +710,16 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, mlen = (i>0) ? matches[i-1].len+1 : best_mlen; cur2 = cur - matches[i].back; best_mlen = (cur2 + matches[i].len < LZ5_OPT_NUM) ? matches[i].len : LZ5_OPT_NUM - cur2; - LZ5_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)((char*)inr-source), cur, cur2, matches[i].len, matches[i].off, best_mlen, last_pos); + +#if 0 + if (mlen < MINMATCH) + { + printf("i=%d match_num=%d matches[i-1].len=%d\n", i, match_num, matches[i-1].len); + printf("%d: ERROR mlen=%d Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(inr-base), mlen, cur, cur2, matches[i].len, matches[i].off, best_mlen, last_pos), exit(0); + } +#endif + + LZ5_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(inr-base), cur, cur2, matches[i].len, matches[i].off, best_mlen, last_pos); while (mlen <= best_mlen) { @@ -713,7 +738,8 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, price = opt[cur2].price + LZ5HC_get_price(litlen, matches[i].off, mlen - MINMATCH); } - LZ5_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)((char*)inr-source), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); + LZ5_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); + // LZ5_LOG_PRICE("%d: TRY5 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); if (cur2 + mlen > last_pos || price < opt[cur2 + mlen].price) { SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); @@ -730,7 +756,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, { for (int i=cur_min-1; i<=last_pos; i++) { - LZ5_LOG_PARSER("%d: BEFORE price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + LZ5_LOG_PARSER("%d: BEFORE price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); } for (int i=cur_min+1; i<=last_pos; i++) @@ -760,32 +786,33 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, mlen = 1; best_mlen = 0; + LZ5_LOG_PRICE("%d: TRY6 price=%d opt[%d].price=%d\n", (int)(inr-base), price, i + mlen, opt[i + mlen].price); SET_PRICE(i, mlen, best_mlen, litlen, price); opt[i].rep = opt[i-1].rep; // copy reps - LZ5_LOG_PARSER("%d: INVALIDATE pred=%d price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)inr-source), cur-cur_min, i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + LZ5_LOG_PARSER("%d: INVALIDATE pred=%d price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(inr-base), cur-cur_min, i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); } for (int i=cur_min-1; i<=last_pos; i++) { - LZ5_LOG_PARSER("%d: AFTER price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + LZ5_LOG_PARSER("%d: AFTER price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); } } } // for (skip_num = 0, cur = 1; cur <= last_pos; cur++) -#endif + best_mlen = opt[last_pos].mlen; best_off = opt[last_pos].off; cur = last_pos - best_mlen; - // printf("%d: start=%d best_mlen=%d best_off=%d cur=%d\n", (int)(ip - istart), (int)(start - ip), (int)best_mlen, (int)best_off, cur); + // printf("%d: start=%d best_mlen=%d best_off=%d cur=%d\n", (int)(ip - base), (int)(start - ip), (int)best_mlen, (int)best_off, cur); /* store sequence */ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set for (int i = 1; i <= last_pos; i++) - LZ5_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-istart+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); - LZ5_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-istart+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); + LZ5_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + LZ5_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-base+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); opt[0].mlen = 1; size_t offset; @@ -803,7 +830,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set for (int i = 0; i <= last_pos;) { - LZ5_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-istart+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + LZ5_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); i += opt[i].mlen; } @@ -811,7 +838,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set while (cur < last_pos) { - LZ5_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-istart+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); + LZ5_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-base+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); mlen = opt[cur].mlen; if (mlen == 1) { ip++; cur++; continue; } offset = opt[cur].off; @@ -821,40 +848,39 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set if (offset) { size_t ml2 = ZSTD_count(ip, ip-offset, iend); - // printf("%d: mlen=%d offset=%d\n", (int)(ip - istart), (int)mlen, (int)offset); if (ml2 < mlen && ml2 < MINMATCH) { - printf("ERROR %d: iend=%d mlen=%d offset=%d ml2=%d\n", (int)(ip - istart), (int)(iend - ip), (int)mlen, (int)offset, (int)ml2); + printf("ERROR %d: iend=%d mlen=%d offset=%d ml2=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset, (int)ml2); exit(0); } } else - printf("ERROR %d: mlen=%d offset=%d\n", (int)(ip - istart), (int)mlen, (int)offset); + printf("ERROR %d: mlen=%d offset=%d\n", (int)(ip - base), (int)mlen, (int)offset); if (ip < anchor) { - printf("ERROR %d: ip < anchor iend=%d mlen=%d offset=%d\n", (int)(ip - istart), (int)(iend - ip), (int)mlen, (int)offset); + printf("ERROR %d: ip < anchor iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } if (ip - offset < base) { - printf("ERROR %d: ip - offset < istart iend=%d mlen=%d offset=%d\n", (int)(ip - istart), (int)(iend - ip), (int)mlen, (int)offset); + printf("ERROR %d: ip - offset < base iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } if (mlen < MINMATCH) { - printf("ERROR %d: mlen < MINMATCH iend=%d mlen=%d offset=%d\n", (int)(ip - istart), (int)(iend - ip), (int)mlen, (int)offset); + printf("ERROR %d: mlen < MINMATCH iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } if (ip + mlen > iend) { - printf("ERROR %d: ip + mlen >= iend iend=%d mlen=%d offset=%d\n", (int)(ip - istart), (int)(iend - ip), (int)mlen, (int)offset); + printf("ERROR %d: ip + mlen >= iend iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } #endif size_t litLength = ip - anchor; - LZ5_LOG_ENCODE("%d/%d: ENCODE literals=%d off=%d mlen=%d\n", (int)(ip-istart), (int)(iend-istart), (int)(litLength), (int)(offset), (int)mlen); + LZ5_LOG_ENCODE("%d/%d: ENCODE literals=%d off=%d mlen=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)(offset), (int)mlen); // printf("orig="); print_hex_text(ip, mlen, 0); // printf("match="); print_hex_text(ip-offset, mlen, 0); ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); @@ -863,11 +889,11 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set if (offset) rep_2 = rep_1, rep_1 = offset; - LZ5_LOG_PARSER("%d: offset=%d rep=%d\n", (int)(ip-istart), (int)offset, (int)rep_1); + LZ5_LOG_PARSER("%d: offset=%d rep=%d\n", (int)(ip-base), (int)offset, (int)rep_1); } -#if 0 +#ifdef ZSTD_USE_REP // check immediate repcode while ( (ip <= ilimit) && (MEM_read32(ip) == MEM_read32(ip - rep_2)) ) { @@ -888,7 +914,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set /* Last Literals */ { size_t lastLLSize = iend - anchor; - LZ5_LOG_ENCODE("%d: lastLLSize literals=%d\n", (int)(ip-istart), (int)(lastLLSize)); + LZ5_LOG_ENCODE("%d: lastLLSize literals=%d\n", (int)(ip-base), (int)(lastLLSize)); memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } @@ -896,439 +922,3 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set - -#if 0 -static int LZ5HC_compress_optimal_price ( - LZ5HC_Data_Structure* ctx, - const char* source, - char* dest, - int inputSize, - int maxOutputSize, - limitedOutput_directive limit - ) -{ - ctx->inputBuffer = (const BYTE*) source; - ctx->outputBuffer = (const BYTE*) dest; - const BYTE* ip = (const BYTE*) source; - const BYTE* anchor = ip; - const BYTE* const iend = ip + inputSize; - const BYTE* const mflimit = iend - MFLIMIT; - const BYTE* const matchlimit = (iend - LASTLITERALS); - BYTE* op = (BYTE*) dest; - BYTE* const oend = op + maxOutputSize; - const int sufficient_len = ctx->params.sufficientLength; - const bool faster_get_matches = (ctx->params.fullSearch == 0); - - LZ5HC_optimal_t opt[LZ5_OPT_NUM+4]; - LZ5HC_match_t matches[LZ5_OPT_NUM+1]; - const uint8_t *inr; - int res, cur, cur2, cur_min, skip_num = 0; - int rep, llen, litlen, mlen, best_mlen, price, offset, best_off, match_num, last_pos; - - rep = 1; - - - /* init */ - ctx->end += inputSize; - ip++; - - /* Main Loop */ - while (ip < mflimit) - { - memset(opt, 0, sizeof(LZ5HC_optimal_t)); - last_pos = 0; - llen = ip - anchor; - inr = ip; - - - // check rep - mlen = MEM_count(ip, ip - rep, matchlimit); - if (mlen >= MINMATCH) - { - LZ5_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)((char*)ip-source), rep, mlen); - if (mlen > sufficient_len || mlen >= LZ5_OPT_NUM) - { - best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; - goto encode; - } - - do - { - litlen = 0; - price = LZ5HC_get_price(llen, 0, mlen - MINMATCH) - llen; - if (mlen > last_pos || price < opt[mlen].price) - SET_PRICE(mlen, mlen, 0, litlen, price); - mlen--; - } - while (mlen >= MINMATCH); - } - - - best_mlen = (last_pos) ? last_pos : MINMATCH; - - if (faster_get_matches && last_pos) - match_num = 0; - else - { - if (ctx->params.strategy == LZ5HC_optimal_price) - { - LZ5HC_Insert(ctx, ip); - match_num = LZ5HC_GetAllMatches(ctx, ip, ip, matchlimit, best_mlen, matches); - } - else - { - if (ctx->params.fullSearch < 2) - LZ5HC_BinTree_Insert(ctx, ip); - else - LZ5HC_BinTree_InsertFull(ctx, ip, matchlimit); - match_num = LZ5HC_BinTree_GetAllMatches(ctx, ip, matchlimit, best_mlen, matches); - } - } - - LZ5_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)((char*)ip-source), match_num, last_pos); - if (!last_pos && !match_num) { ip++; continue; } - - if (match_num && matches[match_num-1].len > sufficient_len) - { - best_mlen = matches[match_num-1].len; - best_off = matches[match_num-1].off; - cur = 0; - last_pos = 1; - goto encode; - } - - // set prices using matches at position = 0 - for (int i = 0; i < match_num; i++) - { - mlen = (i>0) ? matches[i-1].len+1 : best_mlen; - best_mlen = (matches[i].len < LZ5_OPT_NUM) ? matches[i].len : LZ5_OPT_NUM; - LZ5_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)((char*)ip-source), matches[i].len, matches[i].off, best_mlen, last_pos); - while (mlen <= best_mlen) - { - litlen = 0; - price = LZ5HC_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - llen; - if (mlen > last_pos || price < opt[mlen].price) - SET_PRICE(mlen, mlen, matches[i].off, litlen, price); - mlen++; - } - } - - if (!last_pos) { ip++; continue; } - - opt[0].rep = rep; - opt[0].mlen = 1; - - // check further positions - for (skip_num = 0, cur = 1; cur <= last_pos; cur++) - { - inr = ip + cur; - - if (opt[cur-1].mlen == 1) - { - litlen = opt[cur-1].litlen + 1; - - if (cur != litlen) - { - price = opt[cur - litlen].price + LZ5_LIT_ONLY_COST(litlen); - LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)((char*)inr-source), cur - litlen, opt[cur - litlen].price, price, cur, litlen); - } - else - { - price = LZ5_LIT_ONLY_COST(llen + litlen) - llen; - LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)((char*)inr-source), price, cur, litlen, llen); - } - } - else - { - litlen = 1; - price = opt[cur - 1].price + LZ5_LIT_ONLY_COST(litlen); - LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)((char*)inr-source), price, cur, litlen, LZ5_LIT_ONLY_COST(litlen)); - } - - mlen = 1; - best_mlen = 0; - LZ5_LOG_PARSER("%d: TRY price=%d opt[%d].price=%d\n", (int)((char*)inr-source), price, cur, opt[cur].price); - - if (cur > last_pos || price <= opt[cur].price) // || ((price == opt[cur].price) && (opt[cur-1].mlen == 1) && (cur != litlen))) - SET_PRICE(cur, mlen, best_mlen, litlen, price); - - if (cur == last_pos) break; - - if (opt[cur].mlen > 1) - { - mlen = opt[cur].mlen; - offset = opt[cur].off; - if (offset < 1) - { - opt[cur].rep = opt[cur-mlen].rep; - LZ5_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d\n", (int)((char*)inr-source), cur, mlen, opt[cur-mlen].rep); - } - else - { - opt[cur].rep = offset; - LZ5_LOG_PARSER("%d: COPYREP2 cur=%d offset=%d rep=%d\n", (int)((char*)inr-source), cur, offset, opt[cur].rep); - } - } - else - { - opt[cur].rep = opt[cur-1].rep; // copy rep - } - - - LZ5_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)inr-source), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); - - // check rep - // best_mlen = 0; - mlen = MEM_count(inr, inr - opt[cur].rep, matchlimit); - if (mlen >= MINMATCH && mlen > best_mlen) - { - LZ5_LOG_PARSER("%d: try REP rep=%d mlen=%d\n", (int)((char*)inr-source), opt[cur].rep, mlen); - LZ5_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)((char*)inr-source), mlen, 0, opt[cur].rep, cur, opt[cur].off); - - if (mlen > sufficient_len || cur + mlen >= LZ5_OPT_NUM) - { - best_mlen = mlen; - best_off = 0; - LZ5_LOG_PARSER("%d: REP sufficient_len=%d best_mlen=%d best_off=%d last_pos=%d\n", (int)((char*)inr-source), sufficient_len, best_mlen, best_off, last_pos); - last_pos = cur + 1; - goto encode; - } - - if (opt[cur].mlen == 1) - { - litlen = opt[cur].litlen; - - if (cur != litlen) - { - price = opt[cur - litlen].price + LZ5HC_get_price(litlen, 0, mlen - MINMATCH); - LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)((char*)inr-source), cur - litlen, opt[cur - litlen].price, price, cur, litlen); - } - else - { - price = LZ5HC_get_price(llen + litlen, 0, mlen - MINMATCH) - llen; - LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)((char*)inr-source), price, cur, litlen, llen); - } - } - else - { - litlen = 0; - price = opt[cur].price + LZ5HC_get_price(litlen, 0, mlen - MINMATCH); - LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d getprice=%d\n", (int)((char*)inr-source), price, cur, litlen, LZ5HC_get_price(litlen, 0, mlen - MINMATCH)); - } - - best_mlen = mlen; - if (faster_get_matches) - skip_num = best_mlen; - - LZ5_LOG_PARSER("%d: Found REP mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)((char*)inr-source), mlen, 0, price, litlen, cur - litlen, opt[cur - litlen].price); - - do - { - if (cur + mlen > last_pos || price <= opt[cur + mlen].price) // || ((price == opt[cur + mlen].price) && (opt[cur].mlen == 1) && (cur != litlen))) // at equal price prefer REP instead of MATCH - SET_PRICE(cur + mlen, mlen, 0, litlen, price); - mlen--; - } - while (mlen >= MINMATCH); - } - - if (faster_get_matches && skip_num > 0) - { - skip_num--; - continue; - } - - - best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; - - if (ctx->params.strategy == LZ5HC_optimal_price) - { - LZ5HC_Insert(ctx, inr); - match_num = LZ5HC_GetAllMatches(ctx, inr, ip, matchlimit, best_mlen, matches); - LZ5_LOG_PARSER("%d: LZ5HC_GetAllMatches match_num=%d\n", (int)((char*)inr-source), match_num); - } - else - { - if (ctx->params.fullSearch < 2) - LZ5HC_BinTree_Insert(ctx, inr); - else - LZ5HC_BinTree_InsertFull(ctx, inr, matchlimit); - match_num = LZ5HC_BinTree_GetAllMatches(ctx, inr, matchlimit, best_mlen, matches); - LZ5_LOG_PARSER("%d: LZ5HC_BinTree_GetAllMatches match_num=%d\n", (int)((char*)inr-source), match_num); - } - - - if (match_num > 0 && matches[match_num-1].len > sufficient_len) - { - cur -= matches[match_num-1].back; - best_mlen = matches[match_num-1].len; - best_off = matches[match_num-1].off; - last_pos = cur + 1; - goto encode; - } - - cur_min = cur; - - // set prices using matches at position = cur - for (int i = 0; i < match_num; i++) - { - mlen = (i>0) ? matches[i-1].len+1 : best_mlen; - cur2 = cur - matches[i].back; - best_mlen = (cur2 + matches[i].len < LZ5_OPT_NUM) ? matches[i].len : LZ5_OPT_NUM - cur2; - LZ5_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)((char*)inr-source), cur, cur2, matches[i].len, matches[i].off, best_mlen, last_pos); - - while (mlen <= best_mlen) - { - if (opt[cur2].mlen == 1) - { - litlen = opt[cur2].litlen; - - if (cur2 != litlen) - price = opt[cur2 - litlen].price + LZ5HC_get_price(litlen, matches[i].off, mlen - MINMATCH); - else - price = LZ5HC_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - llen; - } - else - { - litlen = 0; - price = opt[cur2].price + LZ5HC_get_price(litlen, matches[i].off, mlen - MINMATCH); - } - - LZ5_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)((char*)inr-source), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); - if (cur2 + mlen > last_pos || price < opt[cur2 + mlen].price) - { - SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); - - opt[cur2 + mlen].rep = matches[i].off; // update reps - if (cur2 < cur_min) cur_min = cur2; - } - - mlen++; - } - } - - if (cur_min < cur) - { - for (int i=cur_min-1; i<=last_pos; i++) - { - LZ5_LOG_PARSER("%d: BEFORE price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); - } - - for (int i=cur_min+1; i<=last_pos; i++) - if (opt[i].price < (1<<30) && (opt[i].off) < 1 && i - opt[i].mlen > cur_min) // invalidate reps - { - if (opt[i-1].mlen == 1) - { - litlen = opt[i-1].litlen + 1; - - if (i != litlen) - { - price = opt[i - litlen].price + LZ5_LIT_ONLY_COST(litlen); - // LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), i - litlen, opt[i - litlen].price, price, i, litlen); - } - else - { - price = LZ5_LIT_ONLY_COST(llen + litlen) - llen; - // LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, i, litlen, llen); - } - } - else - { - litlen = 1; - price = opt[i - 1].price + LZ5_LIT_ONLY_COST(litlen); - // LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d\n", (int)(inr-base), price, i, litlen); - } - - mlen = 1; - best_mlen = 0; - SET_PRICE(i, mlen, best_mlen, litlen, price); - - opt[i].rep = opt[i-1].rep; // copy reps - - LZ5_LOG_PARSER("%d: INVALIDATE pred=%d price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)inr-source), cur-cur_min, i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); - } - - for (int i=cur_min-1; i<=last_pos; i++) - { - LZ5_LOG_PARSER("%d: AFTER price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); - } - - } - } // for (skip_num = 0, cur = 1; cur <= last_pos; cur++) - - - best_mlen = opt[last_pos].mlen; - best_off = opt[last_pos].off; - cur = last_pos - best_mlen; - -encode: // cur, last_pos, best_mlen, best_off have to be set - for (int i = 1; i <= last_pos; i++) - { - LZ5_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); - } - - LZ5_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)((char*)ip-source+cur), cur, last_pos, best_mlen, best_off, opt[cur].rep); - - opt[0].mlen = 1; - - while (cur >= 0) - { - mlen = opt[cur].mlen; - offset = opt[cur].off; - opt[cur].mlen = best_mlen; - opt[cur].off = best_off; - best_mlen = mlen; - best_off = offset; - cur -= mlen; - } - - for (int i = 0; i <= last_pos;) - { - LZ5_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); - i += opt[i].mlen; - } - - cur = 0; - - while (cur < last_pos) - { - LZ5_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)((char*)ip-source+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); - mlen = opt[cur].mlen; - if (mlen == 1) { ip++; cur++; continue; } - offset = opt[cur].off; - cur += mlen; - - LZ5_LOG_ENCODE("%d: ENCODE literals=%d off=%d mlen=%d ", (int)((char*)ip-source), (int)(ip-anchor), (int)(offset), mlen); - if (offset == 0) - { - res = LZ5HC_encodeSequence(ctx, &ip, &op, &anchor, mlen, ip - rep, limit, oend); - } - else - { - res = LZ5HC_encodeSequence(ctx, &ip, &op, &anchor, mlen, ip - offset, limit, oend); - rep = offset; - } - LZ5_LOG_ENCODE("out=%d\n", (int)((char*)op - dest)); - - if (res) return 0; - - LZ5_LOG_PARSER("%d: offset=%d rep=%d\n", (int)((char*)ip-source), offset, rep); - } - } - - /* Encode Last Literals */ - { - int lastRun = (int)(iend - anchor); - // if (inputSize > LASTLITERALS && lastRun < LASTLITERALS) { printf("ERROR: lastRun=%d\n", lastRun); } - if ((limit) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0; /* Check output limit */ - if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK< 254 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; } - else *op++ = (BYTE)(lastRun< Date: Tue, 2 Feb 2016 16:43:31 +0100 Subject: [PATCH 011/113] 41403384 --- lib/zstd_opt.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 23b6556bc..53020c62e 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -46,18 +46,18 @@ With the following max values: When value >= maxValue then use additional 1 byte (if value < maxValue+255) or 3 bytes (to encode value up to MaxValue+255+65535). -Am I right? For offsets only the numbers of bits == log2(offset) are +For offsets only the numbers of bits == log2(offset) are entropy encoded and the offset is put into a binary stream. -This is important to make an estimation. */ -#define LZ5_LIT_ONLY_COST(len) (((len)<<3)+8+LLbits) +#define LZ5_LIT_ONLY_COST(len) (((len)<<3)+1+0) + +#define LZ5_LIT_COST(len) (((len)<<3)+0) FORCE_INLINE U32 LZ5HC_get_price(U32 litlen, U32 offset, U32 mlen) { - size_t lit_cost = (litlen<<3)+LLbits; - // size_t match_cost = (mlen<32 ? 0 : (mlen < 255 ? 8 : (mlen-255 < (1<<7) ? 16 : 24))) + ((offset == 0) ? 8 : (offset<(1<<10) ? 16 : (offset<(1<<16) ? 24 : 32))); - size_t match_cost = MLbits + ZSTD_highbit((U32)mlen+1) + Offbits + ZSTD_highbit((U32)offset+1); + size_t lit_cost = (litlen<<3)+0; + size_t match_cost = /*MLbits +*/ ZSTD_highbit((U32)mlen+1) + Offbits + ZSTD_highbit((U32)offset+1); return lit_cost + match_cost; } @@ -490,11 +490,12 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, llen = ip - anchor; inr = ip; -#ifdef ZSTD_USE_REP +#if 1 + cur = 1; /* check repCode */ - if (MEM_read32(ip+1) == MEM_read32(ip+1 - rep_1)) { + if (MEM_read32(ip+cur) == MEM_read32(ip+cur - rep_1)) { /* repcode : we take it */ - mlen = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-rep_1, iend) + MINMATCH; + mlen = ZSTD_count(ip+cur+MINMATCH, ip+cur+MINMATCH-rep_1, iend) + MINMATCH; LZ5_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)(ip-base), (int)rep_1, (int)mlen); if (depth==0 || mlen > sufficient_len || mlen >= LZ5_OPT_NUM) { @@ -502,15 +503,15 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, goto _storeSequence; } -/* do + do { litlen = 0; - price = LZ5HC_get_price(llen, 0, mlen - MINMATCH) - llen; - if (mlen + 1 > last_pos || price < opt[mlen + 1].price) - SET_PRICE(mlen + 1, mlen, 0, litlen, price); + price = LZ5HC_get_price(llen, 0, mlen - MINMATCH) - LZ5_LIT_COST(llen); + if (mlen + cur > last_pos || price < opt[mlen + cur].price) + SET_PRICE(mlen + cur, mlen, 0, litlen, price); mlen--; } - while (mlen >= MINMATCH);*/ + while (mlen >= MINMATCH); } #endif @@ -545,7 +546,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, while (mlen <= best_mlen) { litlen = 0; - price = LZ5HC_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - llen; + price = LZ5HC_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - LZ5_LIT_COST(llen); if (mlen > last_pos || price < opt[mlen].price) SET_PRICE(mlen, mlen, matches[i].off, litlen, price); mlen++; @@ -652,7 +653,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } else { - price = LZ5HC_get_price(llen + litlen, 0, mlen - MINMATCH) - llen; + price = LZ5HC_get_price(llen + litlen, 0, mlen - MINMATCH) - LZ5_LIT_COST(llen); LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, cur, litlen, llen); } } @@ -730,7 +731,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (cur2 != litlen) price = opt[cur2 - litlen].price + LZ5HC_get_price(litlen, matches[i].off, mlen - MINMATCH); else - price = LZ5HC_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - llen; + price = LZ5HC_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - LZ5_LIT_COST(llen); } else { @@ -854,8 +855,8 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set exit(0); } } - else - printf("ERROR %d: mlen=%d offset=%d\n", (int)(ip - base), (int)mlen, (int)offset); +// else +// printf("ERROR %d: mlen=%d offset=%d\n", (int)(ip - base), (int)mlen, (int)offset); if (ip < anchor) { From 5d4131067b5819d2006b7ac8484c96dceeead911 Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 2 Feb 2016 17:41:21 +0100 Subject: [PATCH 012/113] update --- lib/zstd_opt.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 53020c62e..6adc8e48a 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -317,7 +317,7 @@ void ZSTD_compressBlock_opt2_generic(ZSTD_CCtx* ctx, U32 maxNbAttempts, U32 matchLengthSearch); searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS; - #if 0 +#if 0 typedef size_t (*getAllMatches_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, U32 maxNbAttempts, U32 matchLengthSearch, LZ5HC_match_t* matches); getAllMatches_f getAllMatches = searchMethod ? ZSTD_BtGetAllMatches_selectMLS : ZSTD_HcGetAllMatches_selectMLS; @@ -335,7 +335,7 @@ void ZSTD_compressBlock_opt2_generic(ZSTD_CCtx* ctx, size_t offset=0; const BYTE* start=ip+1; -//#define ZSTD_USE_REP +#define ZSTD_USE_REP #ifdef ZSTD_USE_REP /* check repCode */ if (MEM_read32(start) == MEM_read32(start - offset_1)) { @@ -395,6 +395,9 @@ void ZSTD_compressBlock_opt2_generic(ZSTD_CCtx* ctx, } #endif + /* store sequence */ +_storeSequence: + /* catch up */ if (offset) { while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) /* only search for offset within prefix */ @@ -402,8 +405,6 @@ void ZSTD_compressBlock_opt2_generic(ZSTD_CCtx* ctx, offset_2 = offset_1; offset_1 = offset; } - /* store sequence */ -_storeSequence: { size_t litLength = start - anchor; LZ5_LOG_ENCODE("%d/%d: ENCODE literals=%d off=%d mlen=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)(offset), (int)matchLength); @@ -499,14 +500,14 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, LZ5_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)(ip-base), (int)rep_1, (int)mlen); if (depth==0 || mlen > sufficient_len || mlen >= LZ5_OPT_NUM) { - ip++; best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; + ip+=cur; best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; goto _storeSequence; } do { litlen = 0; - price = LZ5HC_get_price(llen, 0, mlen - MINMATCH) - LZ5_LIT_COST(llen); + price = LZ5HC_get_price(llen + cur, 0, mlen - MINMATCH) - LZ5_LIT_COST(llen + cur); if (mlen + cur > last_pos || price < opt[mlen + cur].price) SET_PRICE(mlen + cur, mlen, 0, litlen, price); mlen--; @@ -624,7 +625,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, LZ5_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); -#ifdef ZSTD_USE_REP +#if 0 // check rep // best_mlen = 0; mlen = ZSTD_count(inr, inr - opt[cur].rep, iend); @@ -888,13 +889,21 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set anchor = ip = ip + mlen; if (offset) - rep_2 = rep_1, rep_1 = offset; - + { + rep_2 = rep_1; + rep_1 = offset; + } + else + { +/* best_off = rep_2; + rep_2 = rep_1; + rep_1 = best_off;*/ + } LZ5_LOG_PARSER("%d: offset=%d rep=%d\n", (int)(ip-base), (int)offset, (int)rep_1); } -#ifdef ZSTD_USE_REP +#if 0 // check immediate repcode while ( (ip <= ilimit) && (MEM_read32(ip) == MEM_read32(ip - rep_2)) ) { From 55bc9a868a664e7c8d08cd8e3adce34ef099e8d5 Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 2 Feb 2016 19:47:09 +0100 Subject: [PATCH 013/113] 41374379 --- lib/zstd_opt.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 6adc8e48a..2e4110dc3 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -903,18 +903,19 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set } -#if 0 +#if 1 // check immediate repcode - while ( (ip <= ilimit) - && (MEM_read32(ip) == MEM_read32(ip - rep_2)) ) { + while ( (anchor <= ilimit) + && (MEM_read32(anchor) == MEM_read32(anchor - rep_2)) ) { /* store sequence */ - best_mlen = ZSTD_count(ip+MINMATCH, ip+MINMATCH-rep_2, iend); + best_mlen = ZSTD_count(anchor+MINMATCH, anchor+MINMATCH-rep_2, iend); best_off = rep_2; rep_2 = rep_1; rep_1 = best_off; + LZ5_LOG_ENCODE("%d/%d: ENCODE REP literals=%d off=%d mlen=%d\n", (int)(anchor-base), (int)(iend-base), (int)(0), (int)(rep_1), (int)best_mlen); ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, best_mlen); - ip += best_mlen+MINMATCH; - anchor = ip; + anchor += best_mlen+MINMATCH; + ip = anchor; continue; // faster when present ... (?) } #endif From 5391a718a485d87b519bcbb3f0e3ce97ea7b30a6 Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 3 Feb 2016 00:04:14 +0100 Subject: [PATCH 014/113] fixed --- lib/zstd_opt.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 2e4110dc3..26dd66528 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -561,8 +561,8 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, // printf("%d: last_pos=%d\n", (int)(ip - base), (int)last_pos); - // opt[0].rep = opt[1].rep = rep_1; - // opt[0].mlen = opt[1].mlen = 1; + // opt[0].rep = opt[1].rep = rep_1; + // opt[0].mlen = opt[1].mlen = 1; opt[0].rep = rep_1; opt[0].mlen = 1; @@ -606,26 +606,31 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (opt[cur].mlen > 1) { mlen = opt[cur].mlen; - if (opt[cur].off < 1) + best_off = opt[cur].off; + if (best_off < 1) { opt[cur].rep = opt[cur-mlen].rep; LZ5_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d\n", (int)(inr-base), cur, mlen, opt[cur-mlen].rep); } else { - opt[cur].rep = 0; +// if (opt[cur].litlen>0) + opt[cur].rep = best_off; + // else + // opt[cur].rep = opt[cur-mlen].rep; LZ5_LOG_PARSER("%d: COPYREP2 cur=%d offset=%d rep=%d\n", (int)(inr-base), cur, 0, opt[cur].rep); } } else { opt[cur].rep = opt[cur-1].rep; // copy rep + LZ5_LOG_PARSER("%d: COPYREP3 cur=%d rep=%d\n", (int)(inr-base), cur, opt[cur].rep); } LZ5_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); -#if 0 +#if 1 // check rep // best_mlen = 0; mlen = ZSTD_count(inr, inr - opt[cur].rep, iend); @@ -741,12 +746,15 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } LZ5_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); - // LZ5_LOG_PRICE("%d: TRY5 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); - if (cur2 + mlen > last_pos || price < opt[cur2 + mlen].price) + LZ5_LOG_PRICE("%d: TRY5 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); + if (cur2 + mlen > last_pos || ((matches[i].off != opt[cur2 + mlen].off) && (price < opt[cur2 + mlen].price))) { SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); - opt[cur2 + mlen].rep = matches[i].off; // update reps + // if (opt[cur2].litlen>0) + opt[cur2 + mlen].rep = matches[i].off; // update reps + // else + // opt[cur2 + mlen].rep = opt[cur2].rep; if (cur2 < cur_min) cur_min = cur2; } @@ -847,17 +855,16 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set cur += mlen; #if 1 + size_t ml2; if (offset) + ml2 = ZSTD_count(ip, ip-offset, iend); + else + ml2 = ZSTD_count(ip, ip-rep_1, iend); + if (ml2 < mlen && ml2 < MINMATCH) { - size_t ml2 = ZSTD_count(ip, ip-offset, iend); - if (ml2 < mlen && ml2 < MINMATCH) - { - printf("ERROR %d: iend=%d mlen=%d offset=%d ml2=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset, (int)ml2); - exit(0); - } + printf("ERROR %d: iend=%d mlen=%d offset=%d rep=%d ml2=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset, (int)rep_1, (int)ml2); + exit(0); } -// else -// printf("ERROR %d: mlen=%d offset=%d\n", (int)(ip - base), (int)mlen, (int)offset); if (ip < anchor) { @@ -882,13 +889,13 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set #endif size_t litLength = ip - anchor; - LZ5_LOG_ENCODE("%d/%d: ENCODE literals=%d off=%d mlen=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)(offset), (int)mlen); + LZ5_LOG_ENCODE("%d/%d: ENCODE literals=%d mlen=%d off=%d rep=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1); // printf("orig="); print_hex_text(ip, mlen, 0); // printf("match="); print_hex_text(ip-offset, mlen, 0); ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); anchor = ip = ip + mlen; - if (offset) + if (offset && litLength>0) { rep_2 = rep_1; rep_1 = offset; From e9f30eae4bb7048a455dd31cc8857aa5cbd97331 Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 3 Feb 2016 12:53:07 +0100 Subject: [PATCH 015/113] 40970636 --- lib/zstd_decompress.c | 7 ++ lib/zstd_opt.c | 196 ++++++++++++++++++++++++------------------ 2 files changed, 121 insertions(+), 82 deletions(-) diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 31fb70069..a26d95fc1 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -610,6 +610,8 @@ typedef struct { const BYTE* dumpsEnd; } seqState_t; + + static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) { size_t litLength; @@ -632,6 +634,11 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) if (dumps >= de) dumps = de-1; /* late correction, to avoid read overflow (data is now corrupted anyway) */ } +// litLength==0 offsetCode==0 offset = seqState->prevOffset seqState->prevOffset = seq->offset +// litLength==0 offsetCode>0 seqState->prevOffset = seq->offset; +// litLength>0 offsetCode==0 +// litLength>0 offsetCode>0 seqState->prevOffset = seq->offset; + /* Offset */ { static const U32 offsetPrefix[MaxOff+1] = { diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 26dd66528..66d0dcdbf 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -14,6 +14,7 @@ typedef struct int mlen; int litlen; int rep; + int rep2; } LZ5HC_optimal_t; #if 1 @@ -26,6 +27,8 @@ typedef struct #define LZ5_LOG_ENCODE(fmt, args...) printf(fmt, ##args) #endif +#define LZ5_LOG_TRY_PRICE(fmt, args...) ;//printf(fmt, ##args) + #define LZ5_OPT_NUM (1<<12) @@ -407,7 +410,7 @@ _storeSequence: { size_t litLength = start - anchor; - LZ5_LOG_ENCODE("%d/%d: ENCODE literals=%d off=%d mlen=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)(offset), (int)matchLength); + LZ5_LOG_ENCODE("%d/%d: ENCODE literals=%d off=%d mlen=%d offset_1=%d offset_2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)(offset), (int)matchLength, (int)offset_1, (int)offset_2); ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH); anchor = ip = start + matchLength; } @@ -501,6 +504,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, LZ5_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)(ip-base), (int)rep_1, (int)mlen); if (depth==0 || mlen > sufficient_len || mlen >= LZ5_OPT_NUM) { ip+=cur; best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; + opt[0].rep = rep_1; goto _storeSequence; } @@ -529,6 +533,11 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, LZ5_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); if (!last_pos && !match_num) { ip++; continue; } + // opt[0].rep = opt[1].rep = rep_1; + // opt[0].mlen = opt[1].mlen = 1; + opt[0].rep = opt[0].rep2 = rep_1; + opt[0].mlen = 1; + if (match_num && matches[match_num-1].len > sufficient_len) { best_mlen = matches[match_num-1].len; @@ -561,10 +570,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, // printf("%d: last_pos=%d\n", (int)(ip - base), (int)last_pos); - // opt[0].rep = opt[1].rep = rep_1; - // opt[0].mlen = opt[1].mlen = 1; - opt[0].rep = rep_1; - opt[0].mlen = 1; + // check further positions @@ -579,65 +585,72 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (cur != litlen) { price = opt[cur - litlen].price + LZ5_LIT_ONLY_COST(litlen); - LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); + LZ5_LOG_TRY_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); } else { price = LZ5_LIT_ONLY_COST(llen + litlen) - llen; - LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, cur, litlen, llen); + LZ5_LOG_TRY_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, cur, litlen, llen); } } else { litlen = 1; price = opt[cur - 1].price + LZ5_LIT_ONLY_COST(litlen); - LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)(inr-base), price, cur, litlen, LZ5_LIT_ONLY_COST(litlen)); + LZ5_LOG_TRY_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)(inr-base), price, cur, litlen, LZ5_LIT_ONLY_COST(litlen)); } mlen = 1; best_mlen = 0; - LZ5_LOG_PRICE("%d: TRY4 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur, opt[cur].price); + LZ5_LOG_TRY_PRICE("%d: TRY4 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur, opt[cur].price); if (cur > last_pos || price <= opt[cur].price) // || ((price == opt[cur].price) && (opt[cur-1].mlen == 1) && (cur != litlen))) SET_PRICE(cur, mlen, best_mlen, litlen, price); - if (cur == last_pos) break; - if (opt[cur].mlen > 1) { mlen = opt[cur].mlen; best_off = opt[cur].off; if (best_off < 1) { - opt[cur].rep = opt[cur-mlen].rep; - LZ5_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d\n", (int)(inr-base), cur, mlen, opt[cur-mlen].rep); + if (opt[cur].off == 0 && opt[cur].litlen==0) + { + opt[cur].rep = opt[cur-mlen].rep2; + opt[cur].rep2 = opt[cur-mlen].rep; + } + else + { + opt[cur].rep = opt[cur-mlen].rep; + opt[cur].rep2 = opt[cur-mlen].rep2; + } + LZ5_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); } else { -// if (opt[cur].litlen>0) - opt[cur].rep = best_off; - // else - // opt[cur].rep = opt[cur-mlen].rep; - LZ5_LOG_PARSER("%d: COPYREP2 cur=%d offset=%d rep=%d\n", (int)(inr-base), cur, 0, opt[cur].rep); + opt[cur].rep = best_off; + opt[cur].rep2 = opt[cur-mlen].rep; + LZ5_LOG_PARSER("%d: COPYREP2 cur=%d offset=%d rep=%d rep2=%d litlen=%d\n", (int)(inr-base), cur, 0, opt[cur].rep, opt[cur].rep2, litlen); } } else { opt[cur].rep = opt[cur-1].rep; // copy rep - LZ5_LOG_PARSER("%d: COPYREP3 cur=%d rep=%d\n", (int)(inr-base), cur, opt[cur].rep); + opt[cur].rep2 = opt[cur-1].rep; // copy rep + LZ5_LOG_PARSER("%d: COPYREP3 cur=%d rep=%d rep2=%d\n", (int)(inr-base), cur, opt[cur].rep, opt[cur].rep2); } + if (cur == last_pos) break; - LZ5_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); + LZ5_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); #if 1 // check rep // best_mlen = 0; - mlen = ZSTD_count(inr, inr - opt[cur].rep, iend); + mlen = ZSTD_count(inr, inr - opt[cur].rep2, iend); if (mlen >= MINMATCH && mlen > best_mlen) { - LZ5_LOG_PARSER("%d: try REP rep=%d mlen=%d\n", (int)(inr-base), opt[cur].rep, mlen); - LZ5_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep, cur, opt[cur].off); + LZ5_LOG_PARSER("%d: try REP rep=%d mlen=%d\n", (int)(inr-base), opt[cur].rep2, mlen); + LZ5_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep2, cur, opt[cur].off); if (mlen > sufficient_len || cur + mlen >= LZ5_OPT_NUM) { @@ -655,19 +668,19 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (cur != litlen) { price = opt[cur - litlen].price + LZ5HC_get_price(litlen, 0, mlen - MINMATCH); - LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); + LZ5_LOG_TRY_PRICE("%d: TRY5 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); } else { price = LZ5HC_get_price(llen + litlen, 0, mlen - MINMATCH) - LZ5_LIT_COST(llen); - LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, cur, litlen, llen); + LZ5_LOG_TRY_PRICE("%d: TRY6 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, cur, litlen, llen); } } else { litlen = 0; price = opt[cur].price + LZ5HC_get_price(litlen, 0, mlen - MINMATCH); - LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d getprice=%d\n", (int)(inr-base), price, cur, litlen, LZ5HC_get_price(litlen, 0, mlen - MINMATCH)); + LZ5_LOG_TRY_PRICE("%d: TRY7 price=%d cur=%d litlen=%d getprice=%d\n", (int)(inr-base), price, cur, litlen, LZ5HC_get_price(litlen, 0, mlen - MINMATCH)); } best_mlen = mlen; @@ -746,16 +759,16 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } LZ5_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); - LZ5_LOG_PRICE("%d: TRY5 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); + LZ5_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); if (cur2 + mlen > last_pos || ((matches[i].off != opt[cur2 + mlen].off) && (price < opt[cur2 + mlen].price))) { SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); - // if (opt[cur2].litlen>0) + // if (opt[cur2].litlen>0) opt[cur2 + mlen].rep = matches[i].off; // update reps - // else - // opt[cur2 + mlen].rep = opt[cur2].rep; - if (cur2 < cur_min) cur_min = cur2; + // else + // opt[cur2 + mlen].rep = opt[cur2].off; + // if (cur2 < cur_min) cur_min = cur2; } mlen++; @@ -779,24 +792,24 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (i != litlen) { price = opt[i - litlen].price + LZ5_LIT_ONLY_COST(litlen); - // LZ5_LOG_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), i - litlen, opt[i - litlen].price, price, i, litlen); + LZ5_LOG_TRY_PRICE("%d: TRY9 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), i - litlen, opt[i - litlen].price, price, i, litlen); } else { price = LZ5_LIT_ONLY_COST(llen + litlen) - llen; - // LZ5_LOG_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, i, litlen, llen); + LZ5_LOG_TRY_PRICE("%d: TRY10 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, i, litlen, llen); } } else { litlen = 1; price = opt[i - 1].price + LZ5_LIT_ONLY_COST(litlen); - // LZ5_LOG_PRICE("%d: TRY3 price=%d cur=%d litlen=%d\n", (int)(inr-base), price, i, litlen); + LZ5_LOG_TRY_PRICE("%d: TRY11 price=%d cur=%d litlen=%d\n", (int)(inr-base), price, i, litlen); } mlen = 1; best_mlen = 0; - LZ5_LOG_PRICE("%d: TRY6 price=%d opt[%d].price=%d\n", (int)(inr-base), price, i + mlen, opt[i + mlen].price); + LZ5_LOG_TRY_PRICE("%d: TRY12 price=%d opt[%d].price=%d\n", (int)(inr-base), price, i + mlen, opt[i + mlen].price); SET_PRICE(i, mlen, best_mlen, litlen, price); opt[i].rep = opt[i-1].rep; // copy reps @@ -821,7 +834,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, /* store sequence */ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set for (int i = 1; i <= last_pos; i++) - LZ5_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + LZ5_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); LZ5_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-base+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); opt[0].mlen = 1; @@ -840,7 +853,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set for (int i = 0; i <= last_pos;) { - LZ5_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + LZ5_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); i += opt[i].mlen; } @@ -848,65 +861,84 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set while (cur < last_pos) { - LZ5_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-base+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep); + LZ5_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); mlen = opt[cur].mlen; if (mlen == 1) { ip++; cur++; continue; } offset = opt[cur].off; + int cur_rep = opt[cur].rep; cur += mlen; -#if 1 - size_t ml2; - if (offset) - ml2 = ZSTD_count(ip, ip-offset, iend); - else - ml2 = ZSTD_count(ip, ip-rep_1, iend); - if (ml2 < mlen && ml2 < MINMATCH) - { - printf("ERROR %d: iend=%d mlen=%d offset=%d rep=%d ml2=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset, (int)rep_1, (int)ml2); - exit(0); - } - - if (ip < anchor) - { - printf("ERROR %d: ip < anchor iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); - exit(0); - } - if (ip - offset < base) - { - printf("ERROR %d: ip - offset < base iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); - exit(0); - } - if (mlen < MINMATCH) - { - printf("ERROR %d: mlen < MINMATCH iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); - exit(0); - } - if (ip + mlen > iend) - { - printf("ERROR %d: ip + mlen >= iend iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); - exit(0); - } -#endif size_t litLength = ip - anchor; - LZ5_LOG_ENCODE("%d/%d: ENCODE literals=%d mlen=%d off=%d rep=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1); - // printf("orig="); print_hex_text(ip, mlen, 0); - // printf("match="); print_hex_text(ip-offset, mlen, 0); - ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); - anchor = ip = ip + mlen; - if (offset && litLength>0) + LZ5_LOG_ENCODE("%d/%d: BEFORE_ENCODE literals=%d mlen=%d off=%d rep1=%d rep2=%d cur_rep=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2, cur_rep); + + if (rep_1 != cur_rep) + { + printf("%d: ERROR rep_1=%d rep_2=%d cur_rep=%d\n", (int)(ip - base), (int)rep_1, (int)rep_2, cur_rep); + exit(0); + } + + + if (offset) { rep_2 = rep_1; rep_1 = offset; } else { -/* best_off = rep_2; - rep_2 = rep_1; - rep_1 = best_off;*/ + if (litLength == 0) + { + best_off = rep_2; + rep_2 = rep_1; + rep_1 = best_off; + } } - LZ5_LOG_PARSER("%d: offset=%d rep=%d\n", (int)(ip-base), (int)offset, (int)rep_1); + + LZ5_LOG_ENCODE("%d/%d: ENCODE literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); + // printf("orig="); print_hex_text(ip, mlen, 0); + // printf("match="); print_hex_text(ip-offset, mlen, 0); + +#if 1 +/* size_t ml2; + if (offset) + ml2 = ZSTD_count(ip, ip-offset, iend); + else +// if (litLength>0) + ml2 = ZSTD_count(ip, ip-rep_1, iend); + // else + // ml2 = ZSTD_count(ip, ip-rep_2, iend); + if (ml2 < mlen && ml2 < MINMATCH) + { + printf("%d: ERROR iend=%d mlen=%d offset=%d rep=%d ml2=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset, (int)rep_1, (int)ml2); + exit(0); + } +*/ + + if (ip < anchor) + { + printf("%d: ERROR ip < anchor iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); + exit(0); + } + if (ip - offset < base) + { + printf("%d: ERROR ip - offset < base iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); + exit(0); + } + if (mlen < MINMATCH) + { + printf("%d: ERROR mlen < MINMATCH iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); + exit(0); + } + if (ip + mlen > iend) + { + printf("%d: ERROR ip + mlen >= iend iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); + exit(0); + } +#endif + + ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); + anchor = ip = ip + mlen; } @@ -919,7 +951,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set best_off = rep_2; rep_2 = rep_1; rep_1 = best_off; - LZ5_LOG_ENCODE("%d/%d: ENCODE REP literals=%d off=%d mlen=%d\n", (int)(anchor-base), (int)(iend-base), (int)(0), (int)(rep_1), (int)best_mlen); + LZ5_LOG_ENCODE("%d/%d: ENCODE REP literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(anchor-base), (int)(iend-base), (int)(0), (int)best_mlen, (int)(0), (int)rep_1, (int)rep_2); ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, best_mlen); anchor += best_mlen+MINMATCH; ip = anchor; From 1b8b1f9d539efa301227a6616f28db24f7951097 Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 3 Feb 2016 13:17:28 +0100 Subject: [PATCH 016/113] auto check of matches --- lib/zstd_opt.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 66d0dcdbf..4eb516578 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -764,11 +764,8 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, { SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); - // if (opt[cur2].litlen>0) - opt[cur2 + mlen].rep = matches[i].off; // update reps - // else - // opt[cur2 + mlen].rep = opt[cur2].off; - // if (cur2 < cur_min) cur_min = cur2; + opt[cur2 + mlen].rep = matches[i].off; // update reps + opt[cur2 + mlen].rep2 = opt[cur2].rep; } mlen++; @@ -878,8 +875,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set printf("%d: ERROR rep_1=%d rep_2=%d cur_rep=%d\n", (int)(ip - base), (int)rep_1, (int)rep_2, cur_rep); exit(0); } - - + if (offset) { rep_2 = rep_1; @@ -900,20 +896,17 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set // printf("match="); print_hex_text(ip-offset, mlen, 0); #if 1 -/* size_t ml2; + size_t ml2; if (offset) ml2 = ZSTD_count(ip, ip-offset, iend); else -// if (litLength>0) ml2 = ZSTD_count(ip, ip-rep_1, iend); - // else - // ml2 = ZSTD_count(ip, ip-rep_2, iend); + if (ml2 < mlen && ml2 < MINMATCH) { - printf("%d: ERROR iend=%d mlen=%d offset=%d rep=%d ml2=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset, (int)rep_1, (int)ml2); + printf("%d: ERROR iend=%d mlen=%d offset=%d cur_rep=%d ml2=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset, (int)cur_rep, (int)ml2); exit(0); } -*/ if (ip < anchor) { From 4cb2009821cfcd0161460fddcbc08ee5acc522e9 Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 3 Feb 2016 13:25:34 +0100 Subject: [PATCH 017/113] 40901629 --- lib/zstd_opt.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 4eb516578..6963a80ff 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -130,10 +130,8 @@ size_t ZSTD_insertBtAndGetAllMatches ( if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; #if 0 - if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) ) - bestLength = matchLength, *offsetPtr = current - matchIndex; -#else if (mnum == 0 || (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)matches[mnum-1].off+1)) ) +#endif { if (matchLength >= MINMATCH) { @@ -145,7 +143,6 @@ size_t ZSTD_insertBtAndGetAllMatches ( } if (matchLength > LZ5_OPT_NUM) break; } -#endif if (ip+matchLength == iend) /* equal : no way to know if inf or sup */ break; /* drop, to guarantee consistency (miss a little bit of compression) */ } From 7f6680e6584b2ff05ea8273190bc3eaba3451bb2 Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 3 Feb 2016 13:30:34 +0100 Subject: [PATCH 018/113] clean some code --- lib/zstd_opt.c | 40 +++++++++++----------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 6963a80ff..fe6bea0bb 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -73,7 +73,6 @@ FORCE_INLINE U32 LZ5HC_get_price(U32 litlen, U32 offset, U32 mlen) opt[pos].litlen = litlen; \ opt[pos].price = price; \ LZ5_LOG_PARSER("%d: SET price[%d/%d]=%d litlen=%d len=%d off=%d\n", (int)(inr-base), (int)pos, (int)last_pos, opt[pos].price, opt[pos].litlen, opt[pos].mlen, opt[pos].off); \ - if (mlen > 1 && mlen < MINMATCH) { printf("%d: ERROR SET price[%d/%d]=%d litlen=%d len=%d off=%d\n", (int)(inr-base), (int)pos, (int)last_pos, opt[pos].price, opt[pos].litlen, opt[pos].mlen, opt[pos].off); exit(0); }; \ } @@ -123,7 +122,7 @@ size_t ZSTD_insertBtAndGetAllMatches ( match = dictBase + matchIndex; matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart); if (matchIndex+matchLength >= dictLimit) - match = base + matchIndex; /* to prepare for next usage of match[matchLength] */ + match = base + matchIndex; /* to prepare for next usage of match[matchLength] */ } if (matchLength > bestLength) { @@ -491,16 +490,15 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, llen = ip - anchor; inr = ip; -#if 1 - cur = 1; + /* check repCode */ - if (MEM_read32(ip+cur) == MEM_read32(ip+cur - rep_1)) { + if (MEM_read32(ip+1) == MEM_read32(ip+1 - rep_1)) { /* repcode : we take it */ - mlen = ZSTD_count(ip+cur+MINMATCH, ip+cur+MINMATCH-rep_1, iend) + MINMATCH; + mlen = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-rep_1, iend) + MINMATCH; LZ5_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)(ip-base), (int)rep_1, (int)mlen); if (depth==0 || mlen > sufficient_len || mlen >= LZ5_OPT_NUM) { - ip+=cur; best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; + ip+=1; best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; opt[0].rep = rep_1; goto _storeSequence; } @@ -508,14 +506,14 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, do { litlen = 0; - price = LZ5HC_get_price(llen + cur, 0, mlen - MINMATCH) - LZ5_LIT_COST(llen + cur); - if (mlen + cur > last_pos || price < opt[mlen + cur].price) - SET_PRICE(mlen + cur, mlen, 0, litlen, price); + price = LZ5HC_get_price(llen + 1, 0, mlen - MINMATCH) - LZ5_LIT_COST(llen + 1); + if (mlen + 1 > last_pos || price < opt[mlen + 1].price) + SET_PRICE(mlen + 1, mlen, 0, litlen, price); mlen--; } while (mlen >= MINMATCH); } -#endif + best_mlen = (last_pos) ? last_pos : MINMATCH; @@ -565,10 +563,6 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ip++; continue; } - // printf("%d: last_pos=%d\n", (int)(ip - base), (int)last_pos); - - - // check further positions for (skip_num = 0, cur = 1; cur <= last_pos; cur++) @@ -640,7 +634,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, LZ5_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); -#if 1 + // check rep // best_mlen = 0; mlen = ZSTD_count(inr, inr - opt[cur].rep2, iend); @@ -694,7 +688,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } while (mlen >= MINMATCH); } -#endif + if (faster_get_matches && skip_num > 0) { @@ -706,7 +700,6 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; match_num = getAllMatches(ctx, inr, iend, maxSearches, mls, matches); - // match_num = LZ5HC_GetAllMatches(ctx, inr, ip, matchlimit, best_mlen, matches); LZ5_LOG_PARSER("%d: LZ5HC_GetAllMatches match_num=%d\n", (int)(inr-base), match_num); @@ -728,14 +721,6 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, cur2 = cur - matches[i].back; best_mlen = (cur2 + matches[i].len < LZ5_OPT_NUM) ? matches[i].len : LZ5_OPT_NUM - cur2; -#if 0 - if (mlen < MINMATCH) - { - printf("i=%d match_num=%d matches[i-1].len=%d\n", i, match_num, matches[i-1].len); - printf("%d: ERROR mlen=%d Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(inr-base), mlen, cur, cur2, matches[i].len, matches[i].off, best_mlen, last_pos), exit(0); - } -#endif - LZ5_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(inr-base), cur, cur2, matches[i].len, matches[i].off, best_mlen, last_pos); while (mlen <= best_mlen) @@ -932,7 +917,6 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set } -#if 1 // check immediate repcode while ( (anchor <= ilimit) && (MEM_read32(anchor) == MEM_read32(anchor - rep_2)) ) { @@ -947,8 +931,6 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set ip = anchor; continue; // faster when present ... (?) } -#endif - } /* Last Literals */ From 85cc6b509bd7da187f9ada154ffa5f6690f7a08a Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 3 Feb 2016 15:58:08 +0100 Subject: [PATCH 019/113] minml --- lib/zstd_opt.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index fe6bea0bb..ecad1d708 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -82,7 +82,7 @@ size_t ZSTD_insertBtAndGetAllMatches ( ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, U32 nbCompares, const U32 mls, - U32 extDict, LZ5HC_match_t* matches) + U32 extDict, LZ5HC_match_t* matches, size_t bestLength) { U32* const hashTable = zc->hashTable; const U32 hashLog = zc->params.hashLog; @@ -102,11 +102,11 @@ size_t ZSTD_insertBtAndGetAllMatches ( const U32 windowLow = zc->lowLimit; U32* smallerPtr = bt + 2*(current&btMask); U32* largerPtr = bt + 2*(current&btMask) + 1; - size_t bestLength = 0; U32 matchEndIdx = current+8; U32 dummy32; /* to be nullified at the end */ size_t mnum = 0; + bestLength = 0; hashTable[h] = current; /* Update Hash Table */ while (nbCompares-- && (matchIndex > windowLow)) { @@ -175,25 +175,25 @@ FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulati size_t ZSTD_BtGetAllMatches ( ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iLimit, - const U32 maxNbAttempts, const U32 mls, LZ5HC_match_t* matches) + const U32 maxNbAttempts, const U32 mls, LZ5HC_match_t* matches, size_t minml) { if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */ ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls); - return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 0, matches); + return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 0, matches, minml); } FORCE_INLINE size_t ZSTD_BtGetAllMatches_selectMLS ( ZSTD_CCtx* zc, /* Index table will be updated */ const BYTE* ip, const BYTE* const iLimit, - const U32 maxNbAttempts, const U32 matchLengthSearch, LZ5HC_match_t* matches) + const U32 maxNbAttempts, const U32 matchLengthSearch, LZ5HC_match_t* matches, size_t minml) { switch(matchLengthSearch) { default : - case 4 : return ZSTD_BtGetAllMatches(zc, ip, iLimit, maxNbAttempts, 4, matches); - case 5 : return ZSTD_BtGetAllMatches(zc, ip, iLimit, maxNbAttempts, 5, matches); - case 6 : return ZSTD_BtGetAllMatches(zc, ip, iLimit, maxNbAttempts, 6, matches); + case 4 : return ZSTD_BtGetAllMatches(zc, ip, iLimit, maxNbAttempts, 4, matches, minml); + case 5 : return ZSTD_BtGetAllMatches(zc, ip, iLimit, maxNbAttempts, 5, matches, minml); + case 6 : return ZSTD_BtGetAllMatches(zc, ip, iLimit, maxNbAttempts, 6, matches, minml); } } @@ -202,7 +202,7 @@ FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulati size_t ZSTD_HcGetAllMatches_generic ( ZSTD_CCtx* zc, /* Index table will be updated */ const BYTE* const ip, const BYTE* const iLimit, - const U32 maxNbAttempts, const U32 mls, const U32 extDict, LZ5HC_match_t* matches) + const U32 maxNbAttempts, const U32 mls, const U32 extDict, LZ5HC_match_t* matches, size_t minml) { U32* const chainTable = zc->contentTable; const U32 chainSize = (1 << zc->params.contentLog); @@ -218,8 +218,8 @@ size_t ZSTD_HcGetAllMatches_generic ( U32 matchIndex; const BYTE* match; int nbAttempts=maxNbAttempts; - size_t ml=MINMATCH-1; size_t mnum = 0; + minml=MINMATCH-1; /* HC4 match finder */ matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls); @@ -229,7 +229,7 @@ size_t ZSTD_HcGetAllMatches_generic ( nbAttempts--; if ((!extDict) || matchIndex >= dictLimit) { match = base + matchIndex; - if (match[ml] == ip[ml]) /* potentially better */ + if (match[minml] == ip[minml]) /* potentially better */ currentMl = ZSTD_count(ip, match, iLimit); } else { match = dictBase + matchIndex; @@ -238,8 +238,8 @@ size_t ZSTD_HcGetAllMatches_generic ( } /* save best solution */ - if (currentMl > ml) { - ml = currentMl; + if (currentMl > minml) { + minml = currentMl; matches[mnum].off = current - matchIndex; matches[mnum].len = currentMl; matches[mnum].back = 0; @@ -259,14 +259,14 @@ size_t ZSTD_HcGetAllMatches_generic ( FORCE_INLINE size_t ZSTD_HcGetAllMatches_selectMLS ( ZSTD_CCtx* zc, const BYTE* ip, const BYTE* const iLimit, - const U32 maxNbAttempts, const U32 matchLengthSearch, LZ5HC_match_t* matches) + const U32 maxNbAttempts, const U32 matchLengthSearch, LZ5HC_match_t* matches, size_t minml) { switch(matchLengthSearch) { default : - case 4 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLimit, maxNbAttempts, 4, 0, matches); - case 5 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLimit, maxNbAttempts, 5, 0, matches); - case 6 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLimit, maxNbAttempts, 6, 0, matches); + case 4 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLimit, maxNbAttempts, 4, 0, matches, minml); + case 5 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLimit, maxNbAttempts, 5, 0, matches, minml); + case 6 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLimit, maxNbAttempts, 6, 0, matches, minml); } } @@ -460,7 +460,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, const U32 mls = ctx->params.searchLength; typedef size_t (*getAllMatches_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, - U32 maxNbAttempts, U32 matchLengthSearch, LZ5HC_match_t* matches); + U32 maxNbAttempts, U32 matchLengthSearch, LZ5HC_match_t* matches, size_t minml); getAllMatches_f getAllMatches = searchMethod ? ZSTD_BtGetAllMatches_selectMLS : ZSTD_HcGetAllMatches_selectMLS; LZ5HC_optimal_t opt[LZ5_OPT_NUM+4]; @@ -522,7 +522,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, else { /* first search (depth 0) */ - match_num = getAllMatches(ctx, ip, iend, maxSearches, mls, matches); + match_num = getAllMatches(ctx, ip, iend, maxSearches, mls, matches, best_mlen); } LZ5_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); @@ -699,7 +699,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; - match_num = getAllMatches(ctx, inr, iend, maxSearches, mls, matches); + match_num = getAllMatches(ctx, inr, iend, maxSearches, mls, matches, best_mlen); LZ5_LOG_PARSER("%d: LZ5HC_GetAllMatches match_num=%d\n", (int)(inr-base), match_num); @@ -743,6 +743,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, LZ5_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); LZ5_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); if (cur2 + mlen > last_pos || ((matches[i].off != opt[cur2 + mlen].off) && (price < opt[cur2 + mlen].price))) + // if (cur2 + mlen > last_pos || (price < opt[cur2 + mlen].price)) { SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); @@ -852,11 +853,13 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set LZ5_LOG_ENCODE("%d/%d: BEFORE_ENCODE literals=%d mlen=%d off=%d rep1=%d rep2=%d cur_rep=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2, cur_rep); +#if 1 if (rep_1 != cur_rep) { printf("%d: ERROR rep_1=%d rep_2=%d cur_rep=%d\n", (int)(ip - base), (int)rep_1, (int)rep_2, cur_rep); exit(0); } +#endif if (offset) { From d02506c18699a5afa881bdba584369e91b04d216 Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 3 Feb 2016 16:54:23 +0100 Subject: [PATCH 020/113] 40699855 --- lib/zstd_opt.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index ecad1d708..e6f0f402f 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -106,7 +106,11 @@ size_t ZSTD_insertBtAndGetAllMatches ( U32 dummy32; /* to be nullified at the end */ size_t mnum = 0; +#if 1 bestLength = 0; +#else + bestLength--; +#endif hashTable[h] = current; /* Update Hash Table */ while (nbCompares-- && (matchIndex > windowLow)) { @@ -125,15 +129,12 @@ size_t ZSTD_insertBtAndGetAllMatches ( match = base + matchIndex; /* to prepare for next usage of match[matchLength] */ } +#if 1 if (matchLength > bestLength) { if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; -#if 0 - if (mnum == 0 || (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)matches[mnum-1].off+1)) ) -#endif { - if (matchLength >= MINMATCH) - { + if (matchLength >= MINMATCH) { bestLength = matchLength; matches[mnum].off = current - matchIndex; matches[mnum].len = matchLength; @@ -145,6 +146,24 @@ size_t ZSTD_insertBtAndGetAllMatches ( if (ip+matchLength == iend) /* equal : no way to know if inf or sup */ break; /* drop, to guarantee consistency (miss a little bit of compression) */ } +#else + if (matchLength > matchEndIdx - matchIndex) + matchEndIdx = matchIndex + (U32)matchLength; + + if (matchLength > bestLength) { + bestLength = matchLength; + matches[mnum].off = current - matchIndex; + matches[mnum].len = matchLength; + matches[mnum].back = 0; + mnum++; + + if (matchLength > LZ5_OPT_NUM) break; + } + + if (ip+matchLength == iend) /* equal : no way to know if inf or sup */ + break; /* drop, to guarantee consistency (miss a little bit of compression) */ +#endif + if (match[matchLength] < ip[matchLength]) { /* match is smaller than current */ @@ -742,8 +761,8 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, LZ5_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); LZ5_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); - if (cur2 + mlen > last_pos || ((matches[i].off != opt[cur2 + mlen].off) && (price < opt[cur2 + mlen].price))) - // if (cur2 + mlen > last_pos || (price < opt[cur2 + mlen].price)) + + if (cur2 + mlen > last_pos || (price < opt[cur2 + mlen].price)) { SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); From 78e5ea3a32c39c9334ae623e60dd5e498d5d7cf4 Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 3 Feb 2016 17:25:42 +0100 Subject: [PATCH 021/113] ZSTD_getPrice --- lib/zstd_compress.c | 2 +- lib/zstd_opt.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index fe9bde30c..71ff02e7b 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -2305,7 +2305,7 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 22, 20, 22, 4, 4, ZSTD_lazy2 }, /* level 11 + L=4 */ // 41902762 lazy1=42087013 norep1=42911693 { 0, 23, 21, 22, 5, 4, ZSTD_btlazy2 }, /* level 16 + L=4 */ // 41233150 btlazy1=41560211 norep1=42322286 { 0, 23, 21, 22, 5, 4, ZSTD_opt }, /* level 23 */ - { 0, 23, 21, 22, 5, 4, ZSTD_opt_bt }, /* level 23 */ + { 0, 23, 21, 22, 5, 4, ZSTD_opt_bt }, /* level 24 */ }, { /* for srcSize <= 256 KB */ /* W, C, H, S, L, strat */ diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index e6f0f402f..ebd33835a 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -64,6 +64,41 @@ FORCE_INLINE U32 LZ5HC_get_price(U32 litlen, U32 offset, U32 mlen) return lit_cost + match_cost; } +MEM_STATIC size_t ZSTD_getPrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offsetCode, size_t matchCode) +{ +#if 0 + static const BYTE* g_start = NULL; + if (g_start==NULL) g_start = literals; + //if (literals - g_start == 8695) + printf("pos %6u : %3u literals & match %3u bytes at distance %6u \n", + (U32)(literals - g_start), (U32)litLength, (U32)matchCode+4, (U32)offsetCode); +#endif + size_t price = 0; + + /* literals */ + seqStorePtr->lit += litLength; + + /* literal Length */ + if (litLength >= MaxLL) { + *(seqStorePtr->litLength++) = MaxLL; + if (litLength<255 + MaxLL) price += 8; else price += 32; + } + else *(seqStorePtr->litLength++) = (BYTE)litLength; + + /* match offset */ + *(seqStorePtr->offset++) = (U32)offsetCode; + + /* match Length */ + if (matchCode >= MaxML) { + *(seqStorePtr->matchLength++) = MaxML; + if (matchCode < 255+MaxML) price += 8; else price += 32; + } + else *(seqStorePtr->matchLength++) = (BYTE)matchCode; + + return price; +} + + #define SET_PRICE(pos, mlen, offset, litlen, price) \ { \ From 3bfcfc7bb09510f90f1351e58524af11ea292f93 Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 3 Feb 2016 18:47:30 +0100 Subject: [PATCH 022/113] ZSTD_updatePrice --- lib/zstd_compress.c | 26 +++++++++++++++++++++++++- lib/zstd_internal.h | 1 + lib/zstd_opt.c | 10 ++++++---- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index d88bac8ca..4b345c4aa 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -88,6 +88,14 @@ typedef struct { BYTE* matchLength; BYTE* dumpsStart; BYTE* dumps; + BYTE* matchLengthFreq; + BYTE* litLengthFreq; + BYTE* litFreq; + BYTE* offCodeFreq; + U32 matchLengthSum; + U32 litLengthSum; + U32 litSum; + U32 offCodeSum; } seqStore_t; static void ZSTD_resetSeqStore(seqStore_t* ssPtr) @@ -97,6 +105,16 @@ static void ZSTD_resetSeqStore(seqStore_t* ssPtr) ssPtr->litLength = ssPtr->litLengthStart; ssPtr->matchLength = ssPtr->matchLengthStart; ssPtr->dumps = ssPtr->dumpsStart; + + ssPtr->matchLengthSum = (1<litLengthSum = (1<litSum = (1<offCodeSum = (1<litFreq, 1, (1<litLengthFreq, 1, (1<matchLengthFreq, 1, (1<offCodeFreq, 1, (1<workSpaceSize < neededSpace) { free(zc->workSpace); zc->workSpace = malloc(neededSpace); @@ -213,6 +231,12 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, zc->seqStore.litLengthStart = zc->seqStore.litStart + blockSize; zc->seqStore.matchLengthStart = zc->seqStore.litLengthStart + (blockSize>>2); zc->seqStore.dumpsStart = zc->seqStore.matchLengthStart + (blockSize>>2); + zc->seqStore.litFreq = zc->seqStore.dumpsStart + (blockSize>>2); + zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (1<seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (1<seqStore.XXX = zc->seqStore.offCodeFreq + (1<hbSize = 0; zc->stage = 0; zc->loadedDictEnd = 0; diff --git a/lib/zstd_internal.h b/lib/zstd_internal.h index d3f989cd2..f2af062f7 100644 --- a/lib/zstd_internal.h +++ b/lib/zstd_internal.h @@ -83,6 +83,7 @@ static const size_t ZSTD_frameHeaderSize_min = 5; #define MINMATCH 4 #define REPCODE_STARTVALUE 1 +#define Litbits 8 #define MLbits 7 #define LLbits 6 #define Offbits 5 diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index ebd33835a..454be470d 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -64,7 +64,7 @@ FORCE_INLINE U32 LZ5HC_get_price(U32 litlen, U32 offset, U32 mlen) return lit_cost + match_cost; } -MEM_STATIC size_t ZSTD_getPrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offsetCode, size_t matchCode) +MEM_STATIC size_t ZSTD_updatePrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offsetCode, size_t matchCode) { #if 0 static const BYTE* g_start = NULL; @@ -76,13 +76,14 @@ MEM_STATIC size_t ZSTD_getPrice(seqStore_t* seqStorePtr, size_t litLength, const size_t price = 0; /* literals */ - seqStorePtr->lit += litLength; - + // seqStorePtr->lit += litLength; + printf("litSum=%d litLengthSum=%d matchLengthSum=%d offCodeSum=%d\n", seqStorePtr->litSum, seqStorePtr->litLengthSum, seqStorePtr->matchLengthSum, seqStorePtr->offCodeSum); + /* literal Length */ if (litLength >= MaxLL) { *(seqStorePtr->litLength++) = MaxLL; if (litLength<255 + MaxLL) price += 8; else price += 32; - } + } else *(seqStorePtr->litLength++) = (BYTE)litLength; /* match offset */ @@ -969,6 +970,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set } #endif + ZSTD_updatePrice(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); anchor = ip = ip + mlen; } From 749460d9ab9772f808ab1d6b04a307e4f8956c77 Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 3 Feb 2016 19:08:48 +0100 Subject: [PATCH 023/113] ZSTD_updatePrice --- lib/zstd_opt.c | 216 ++++++++++++++++++++++++++----------------------- 1 file changed, 116 insertions(+), 100 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 454be470d..1d1a44a5c 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -5,7 +5,7 @@ typedef struct int off; int len; int back; -} LZ5HC_match_t; +} ZSTD_match_t; typedef struct { @@ -15,21 +15,21 @@ typedef struct int litlen; int rep; int rep2; -} LZ5HC_optimal_t; +} ZSTD_optimal_t; #if 1 - #define LZ5_LOG_PARSER(fmt, args...) ;// printf(fmt, ##args) - #define LZ5_LOG_PRICE(fmt, args...) ;//printf(fmt, ##args) - #define LZ5_LOG_ENCODE(fmt, args...) ;//printf(fmt, ##args) + #define ZSTD_LOG_PARSER(fmt, args...) ;// printf(fmt, ##args) + #define ZSTD_LOG_PRICE(fmt, args...) ;//printf(fmt, ##args) + #define ZSTD_LOG_ENCODE(fmt, args...) ;//printf(fmt, ##args) #else - #define LZ5_LOG_PARSER(fmt, args...) printf(fmt, ##args) - #define LZ5_LOG_PRICE(fmt, args...) printf(fmt, ##args) - #define LZ5_LOG_ENCODE(fmt, args...) printf(fmt, ##args) + #define ZSTD_LOG_PARSER(fmt, args...) printf(fmt, ##args) + #define ZSTD_LOG_PRICE(fmt, args...) printf(fmt, ##args) + #define ZSTD_LOG_ENCODE(fmt, args...) printf(fmt, ##args) #endif -#define LZ5_LOG_TRY_PRICE(fmt, args...) ;//printf(fmt, ##args) +#define ZSTD_LOG_TRY_PRICE(fmt, args...) ;//printf(fmt, ##args) -#define LZ5_OPT_NUM (1<<12) +#define ZSTD_OPT_NUM (1<<12) /* @@ -53,54 +53,69 @@ For offsets only the numbers of bits == log2(offset) are entropy encoded and the offset is put into a binary stream. */ -#define LZ5_LIT_ONLY_COST(len) (((len)<<3)+1+0) +#define ZSTD_LIT_ONLY_COST(len) (((len)<<3)+1+0) -#define LZ5_LIT_COST(len) (((len)<<3)+0) +#define ZSTD_LIT_COST(len) (((len)<<3)+0) -FORCE_INLINE U32 LZ5HC_get_price(U32 litlen, U32 offset, U32 mlen) +FORCE_INLINE U32 ZSTD_get_price(U32 litlen, U32 offset, U32 mlen) { size_t lit_cost = (litlen<<3)+0; size_t match_cost = /*MLbits +*/ ZSTD_highbit((U32)mlen+1) + Offbits + ZSTD_highbit((U32)offset+1); return lit_cost + match_cost; } -MEM_STATIC size_t ZSTD_updatePrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offsetCode, size_t matchCode) +MEM_STATIC size_t ZSTD_updatePrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offset, size_t matchCode) { #if 0 static const BYTE* g_start = NULL; if (g_start==NULL) g_start = literals; //if (literals - g_start == 8695) printf("pos %6u : %3u literals & match %3u bytes at distance %6u \n", - (U32)(literals - g_start), (U32)litLength, (U32)matchCode+4, (U32)offsetCode); + (U32)(literals - g_start), (U32)litLength, (U32)matchCode+4, (U32)offset); #endif size_t price = 0; - /* literals */ - // seqStorePtr->lit += litLength; printf("litSum=%d litLengthSum=%d matchLengthSum=%d offCodeSum=%d\n", seqStorePtr->litSum, seqStorePtr->litLengthSum, seqStorePtr->matchLengthSum, seqStorePtr->offCodeSum); + + /* literals */ + seqStorePtr->litSum += litLength; + for (int i=litLength-1; i>=0; i--) + seqStorePtr->litFreq[literals[i]]++; /* literal Length */ + seqStorePtr->litLengthSum++; if (litLength >= MaxLL) { - *(seqStorePtr->litLength++) = MaxLL; - if (litLength<255 + MaxLL) price += 8; else price += 32; - } - else *(seqStorePtr->litLength++) = (BYTE)litLength; + seqStorePtr->litLengthFreq[MaxLL]++; + if (litLength<255 + MaxLL) { + price += 8; + } else { + price += 8; + if (litLength < (1<<15)) price += 16; else price += 24; + } } + else seqStorePtr->litLengthFreq[litLength]++; /* match offset */ - *(seqStorePtr->offset++) = (U32)offsetCode; + seqStorePtr->offCodeSum++; + BYTE offCode = (BYTE)ZSTD_highbit(offset) + 1; + if (offset==0) offCode=0; + seqStorePtr->offCodeFreq[offCode]++; /* match Length */ + seqStorePtr->matchLengthSum++; if (matchCode >= MaxML) { - *(seqStorePtr->matchLength++) = MaxML; - if (matchCode < 255+MaxML) price += 8; else price += 32; - } - else *(seqStorePtr->matchLength++) = (BYTE)matchCode; - + seqStorePtr->matchLengthFreq[MaxML]++; + if (matchCode < 255+MaxML) { + price += 8; + } else { + price += 8; + if (matchCode < (1<<15)) price += 16; else price += 24; + } } + else seqStorePtr->matchLengthFreq[matchCode]++; + return price; } - #define SET_PRICE(pos, mlen, offset, litlen, price) \ { \ while (last_pos < pos) { opt[last_pos+1].price = 1<<30; last_pos++; } \ @@ -108,7 +123,7 @@ MEM_STATIC size_t ZSTD_updatePrice(seqStore_t* seqStorePtr, size_t litLength, co opt[pos].off = offset; \ opt[pos].litlen = litlen; \ opt[pos].price = price; \ - LZ5_LOG_PARSER("%d: SET price[%d/%d]=%d litlen=%d len=%d off=%d\n", (int)(inr-base), (int)pos, (int)last_pos, opt[pos].price, opt[pos].litlen, opt[pos].mlen, opt[pos].off); \ + ZSTD_LOG_PARSER("%d: SET price[%d/%d]=%d litlen=%d len=%d off=%d\n", (int)(inr-base), (int)pos, (int)last_pos, opt[pos].price, opt[pos].litlen, opt[pos].mlen, opt[pos].off); \ } @@ -118,7 +133,7 @@ size_t ZSTD_insertBtAndGetAllMatches ( ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, U32 nbCompares, const U32 mls, - U32 extDict, LZ5HC_match_t* matches, size_t bestLength) + U32 extDict, ZSTD_match_t* matches, size_t bestLength) { U32* const hashTable = zc->hashTable; const U32 hashLog = zc->params.hashLog; @@ -177,7 +192,7 @@ size_t ZSTD_insertBtAndGetAllMatches ( matches[mnum].back = 0; mnum++; } - if (matchLength > LZ5_OPT_NUM) break; + if (matchLength > ZSTD_OPT_NUM) break; } if (ip+matchLength == iend) /* equal : no way to know if inf or sup */ break; /* drop, to guarantee consistency (miss a little bit of compression) */ @@ -193,7 +208,7 @@ size_t ZSTD_insertBtAndGetAllMatches ( matches[mnum].back = 0; mnum++; - if (matchLength > LZ5_OPT_NUM) break; + if (matchLength > ZSTD_OPT_NUM) break; } if (ip+matchLength == iend) /* equal : no way to know if inf or sup */ @@ -230,7 +245,7 @@ FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulati size_t ZSTD_BtGetAllMatches ( ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iLimit, - const U32 maxNbAttempts, const U32 mls, LZ5HC_match_t* matches, size_t minml) + const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, size_t minml) { if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */ ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls); @@ -241,7 +256,7 @@ size_t ZSTD_BtGetAllMatches ( FORCE_INLINE size_t ZSTD_BtGetAllMatches_selectMLS ( ZSTD_CCtx* zc, /* Index table will be updated */ const BYTE* ip, const BYTE* const iLimit, - const U32 maxNbAttempts, const U32 matchLengthSearch, LZ5HC_match_t* matches, size_t minml) + const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, size_t minml) { switch(matchLengthSearch) { @@ -257,7 +272,7 @@ FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulati size_t ZSTD_HcGetAllMatches_generic ( ZSTD_CCtx* zc, /* Index table will be updated */ const BYTE* const ip, const BYTE* const iLimit, - const U32 maxNbAttempts, const U32 mls, const U32 extDict, LZ5HC_match_t* matches, size_t minml) + const U32 maxNbAttempts, const U32 mls, const U32 extDict, ZSTD_match_t* matches, size_t minml) { U32* const chainTable = zc->contentTable; const U32 chainSize = (1 << zc->params.contentLog); @@ -299,7 +314,7 @@ size_t ZSTD_HcGetAllMatches_generic ( matches[mnum].len = currentMl; matches[mnum].back = 0; mnum++; - if (currentMl > LZ5_OPT_NUM) break; + if (currentMl > ZSTD_OPT_NUM) break; if (ip+currentMl == iLimit) break; /* best possible, and avoid read overflow*/ } @@ -314,7 +329,7 @@ size_t ZSTD_HcGetAllMatches_generic ( FORCE_INLINE size_t ZSTD_HcGetAllMatches_selectMLS ( ZSTD_CCtx* zc, const BYTE* ip, const BYTE* const iLimit, - const U32 maxNbAttempts, const U32 matchLengthSearch, LZ5HC_match_t* matches, size_t minml) + const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, size_t minml) { switch(matchLengthSearch) { @@ -373,10 +388,10 @@ void ZSTD_compressBlock_opt2_generic(ZSTD_CCtx* ctx, #if 0 typedef size_t (*getAllMatches_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, - U32 maxNbAttempts, U32 matchLengthSearch, LZ5HC_match_t* matches); + U32 maxNbAttempts, U32 matchLengthSearch, ZSTD_match_t* matches); getAllMatches_f getAllMatches = searchMethod ? ZSTD_BtGetAllMatches_selectMLS : ZSTD_HcGetAllMatches_selectMLS; - LZ5HC_match_t matches[LZ5_OPT_NUM+1]; + ZSTD_match_t matches[ZSTD_OPT_NUM+1]; #endif /* init */ @@ -461,7 +476,7 @@ _storeSequence: { size_t litLength = start - anchor; - LZ5_LOG_ENCODE("%d/%d: ENCODE literals=%d off=%d mlen=%d offset_1=%d offset_2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)(offset), (int)matchLength, (int)offset_1, (int)offset_2); + ZSTD_LOG_ENCODE("%d/%d: ENCODE literals=%d off=%d mlen=%d offset_1=%d offset_2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)(offset), (int)matchLength, (int)offset_1, (int)offset_2); ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH); anchor = ip = start + matchLength; } @@ -485,7 +500,7 @@ _storeSequence: /* Last Literals */ { size_t lastLLSize = iend - anchor; - LZ5_LOG_ENCODE("%d/%d: ENCODE lastLLSize=%d\n", (int)(ip-base), (int)(iend-base), (int)(lastLLSize)); + ZSTD_LOG_ENCODE("%d/%d: ENCODE lastLLSize=%d\n", (int)(ip-base), (int)(iend-base), (int)(lastLLSize)); memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } @@ -515,11 +530,11 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, const U32 mls = ctx->params.searchLength; typedef size_t (*getAllMatches_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, - U32 maxNbAttempts, U32 matchLengthSearch, LZ5HC_match_t* matches, size_t minml); + U32 maxNbAttempts, U32 matchLengthSearch, ZSTD_match_t* matches, size_t minml); getAllMatches_f getAllMatches = searchMethod ? ZSTD_BtGetAllMatches_selectMLS : ZSTD_HcGetAllMatches_selectMLS; - LZ5HC_optimal_t opt[LZ5_OPT_NUM+4]; - LZ5HC_match_t matches[LZ5_OPT_NUM+1]; + ZSTD_optimal_t opt[ZSTD_OPT_NUM+4]; + ZSTD_match_t matches[ZSTD_OPT_NUM+1]; const uint8_t *inr; int cur, cur2, cur_min, skip_num = 0; int llen, litlen, price, match_num, last_pos; @@ -540,7 +555,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, int mlen=0; int best_mlen=0; int best_off=0; - memset(opt, 0, sizeof(LZ5HC_optimal_t)); + memset(opt, 0, sizeof(ZSTD_optimal_t)); last_pos = 0; llen = ip - anchor; inr = ip; @@ -551,8 +566,8 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, /* repcode : we take it */ mlen = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-rep_1, iend) + MINMATCH; - LZ5_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)(ip-base), (int)rep_1, (int)mlen); - if (depth==0 || mlen > sufficient_len || mlen >= LZ5_OPT_NUM) { + ZSTD_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)(ip-base), (int)rep_1, (int)mlen); + if (depth==0 || mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) { ip+=1; best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; opt[0].rep = rep_1; goto _storeSequence; @@ -561,7 +576,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, do { litlen = 0; - price = LZ5HC_get_price(llen + 1, 0, mlen - MINMATCH) - LZ5_LIT_COST(llen + 1); + price = ZSTD_get_price(llen + 1, 0, mlen - MINMATCH) - ZSTD_LIT_COST(llen + 1); if (mlen + 1 > last_pos || price < opt[mlen + 1].price) SET_PRICE(mlen + 1, mlen, 0, litlen, price); mlen--; @@ -580,7 +595,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, match_num = getAllMatches(ctx, ip, iend, maxSearches, mls, matches, best_mlen); } - LZ5_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); + ZSTD_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); if (!last_pos && !match_num) { ip++; continue; } // opt[0].rep = opt[1].rep = rep_1; @@ -601,12 +616,12 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, for (int i = 0; i < match_num; i++) { mlen = (i>0) ? matches[i-1].len+1 : best_mlen; - best_mlen = (matches[i].len < LZ5_OPT_NUM) ? matches[i].len : LZ5_OPT_NUM; - LZ5_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(ip-base), matches[i].len, matches[i].off, (int)best_mlen, (int)last_pos); + best_mlen = (matches[i].len < ZSTD_OPT_NUM) ? matches[i].len : ZSTD_OPT_NUM; + ZSTD_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(ip-base), matches[i].len, matches[i].off, (int)best_mlen, (int)last_pos); while (mlen <= best_mlen) { litlen = 0; - price = LZ5HC_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - LZ5_LIT_COST(llen); + price = ZSTD_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - ZSTD_LIT_COST(llen); if (mlen > last_pos || price < opt[mlen].price) SET_PRICE(mlen, mlen, matches[i].off, litlen, price); mlen++; @@ -630,25 +645,25 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (cur != litlen) { - price = opt[cur - litlen].price + LZ5_LIT_ONLY_COST(litlen); - LZ5_LOG_TRY_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); + price = opt[cur - litlen].price + ZSTD_LIT_ONLY_COST(litlen); + ZSTD_LOG_TRY_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); } else { - price = LZ5_LIT_ONLY_COST(llen + litlen) - llen; - LZ5_LOG_TRY_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, cur, litlen, llen); + price = ZSTD_LIT_ONLY_COST(llen + litlen) - llen; + ZSTD_LOG_TRY_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, cur, litlen, llen); } } else { litlen = 1; - price = opt[cur - 1].price + LZ5_LIT_ONLY_COST(litlen); - LZ5_LOG_TRY_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)(inr-base), price, cur, litlen, LZ5_LIT_ONLY_COST(litlen)); + price = opt[cur - 1].price + ZSTD_LIT_ONLY_COST(litlen); + ZSTD_LOG_TRY_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)(inr-base), price, cur, litlen, ZSTD_LIT_ONLY_COST(litlen)); } mlen = 1; best_mlen = 0; - LZ5_LOG_TRY_PRICE("%d: TRY4 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur, opt[cur].price); + ZSTD_LOG_TRY_PRICE("%d: TRY4 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur, opt[cur].price); if (cur > last_pos || price <= opt[cur].price) // || ((price == opt[cur].price) && (opt[cur-1].mlen == 1) && (cur != litlen))) SET_PRICE(cur, mlen, best_mlen, litlen, price); @@ -669,25 +684,25 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, opt[cur].rep = opt[cur-mlen].rep; opt[cur].rep2 = opt[cur-mlen].rep2; } - LZ5_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); + ZSTD_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); } else { opt[cur].rep = best_off; opt[cur].rep2 = opt[cur-mlen].rep; - LZ5_LOG_PARSER("%d: COPYREP2 cur=%d offset=%d rep=%d rep2=%d litlen=%d\n", (int)(inr-base), cur, 0, opt[cur].rep, opt[cur].rep2, litlen); + ZSTD_LOG_PARSER("%d: COPYREP2 cur=%d offset=%d rep=%d rep2=%d litlen=%d\n", (int)(inr-base), cur, 0, opt[cur].rep, opt[cur].rep2, litlen); } } else { opt[cur].rep = opt[cur-1].rep; // copy rep opt[cur].rep2 = opt[cur-1].rep; // copy rep - LZ5_LOG_PARSER("%d: COPYREP3 cur=%d rep=%d rep2=%d\n", (int)(inr-base), cur, opt[cur].rep, opt[cur].rep2); + ZSTD_LOG_PARSER("%d: COPYREP3 cur=%d rep=%d rep2=%d\n", (int)(inr-base), cur, opt[cur].rep, opt[cur].rep2); } if (cur == last_pos) break; - LZ5_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); + ZSTD_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); // check rep @@ -695,14 +710,14 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, mlen = ZSTD_count(inr, inr - opt[cur].rep2, iend); if (mlen >= MINMATCH && mlen > best_mlen) { - LZ5_LOG_PARSER("%d: try REP rep=%d mlen=%d\n", (int)(inr-base), opt[cur].rep2, mlen); - LZ5_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep2, cur, opt[cur].off); + ZSTD_LOG_PARSER("%d: try REP rep=%d mlen=%d\n", (int)(inr-base), opt[cur].rep2, mlen); + ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep2, cur, opt[cur].off); - if (mlen > sufficient_len || cur + mlen >= LZ5_OPT_NUM) + if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) { best_mlen = mlen; best_off = 0; - LZ5_LOG_PARSER("%d: REP sufficient_len=%d best_mlen=%d best_off=%d last_pos=%d\n", (int)(inr-base), sufficient_len, best_mlen, best_off, last_pos); + ZSTD_LOG_PARSER("%d: REP sufficient_len=%d best_mlen=%d best_off=%d last_pos=%d\n", (int)(inr-base), sufficient_len, best_mlen, best_off, last_pos); last_pos = cur + 1; goto _storeSequence; } @@ -713,27 +728,27 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (cur != litlen) { - price = opt[cur - litlen].price + LZ5HC_get_price(litlen, 0, mlen - MINMATCH); - LZ5_LOG_TRY_PRICE("%d: TRY5 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); + price = opt[cur - litlen].price + ZSTD_get_price(litlen, 0, mlen - MINMATCH); + ZSTD_LOG_TRY_PRICE("%d: TRY5 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); } else { - price = LZ5HC_get_price(llen + litlen, 0, mlen - MINMATCH) - LZ5_LIT_COST(llen); - LZ5_LOG_TRY_PRICE("%d: TRY6 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, cur, litlen, llen); + price = ZSTD_get_price(llen + litlen, 0, mlen - MINMATCH) - ZSTD_LIT_COST(llen); + ZSTD_LOG_TRY_PRICE("%d: TRY6 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, cur, litlen, llen); } } else { litlen = 0; - price = opt[cur].price + LZ5HC_get_price(litlen, 0, mlen - MINMATCH); - LZ5_LOG_TRY_PRICE("%d: TRY7 price=%d cur=%d litlen=%d getprice=%d\n", (int)(inr-base), price, cur, litlen, LZ5HC_get_price(litlen, 0, mlen - MINMATCH)); + price = opt[cur].price + ZSTD_get_price(litlen, 0, mlen - MINMATCH); + ZSTD_LOG_TRY_PRICE("%d: TRY7 price=%d cur=%d litlen=%d getprice=%d\n", (int)(inr-base), price, cur, litlen, ZSTD_get_price(litlen, 0, mlen - MINMATCH)); } best_mlen = mlen; if (faster_get_matches) skip_num = best_mlen; - LZ5_LOG_PARSER("%d: Found REP mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), mlen, 0, price, litlen, cur - litlen, opt[cur - litlen].price); + ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), mlen, 0, price, litlen, cur - litlen, opt[cur - litlen].price); do { @@ -755,7 +770,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; match_num = getAllMatches(ctx, inr, iend, maxSearches, mls, matches, best_mlen); - LZ5_LOG_PARSER("%d: LZ5HC_GetAllMatches match_num=%d\n", (int)(inr-base), match_num); + ZSTD_LOG_PARSER("%d: ZSTD_GetAllMatches match_num=%d\n", (int)(inr-base), match_num); if (match_num > 0 && matches[match_num-1].len > sufficient_len) @@ -774,9 +789,9 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, { mlen = (i>0) ? matches[i-1].len+1 : best_mlen; cur2 = cur - matches[i].back; - best_mlen = (cur2 + matches[i].len < LZ5_OPT_NUM) ? matches[i].len : LZ5_OPT_NUM - cur2; + best_mlen = (cur2 + matches[i].len < ZSTD_OPT_NUM) ? matches[i].len : ZSTD_OPT_NUM - cur2; - LZ5_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(inr-base), cur, cur2, matches[i].len, matches[i].off, best_mlen, last_pos); + ZSTD_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(inr-base), cur, cur2, matches[i].len, matches[i].off, best_mlen, last_pos); while (mlen <= best_mlen) { @@ -785,18 +800,18 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, litlen = opt[cur2].litlen; if (cur2 != litlen) - price = opt[cur2 - litlen].price + LZ5HC_get_price(litlen, matches[i].off, mlen - MINMATCH); + price = opt[cur2 - litlen].price + ZSTD_get_price(litlen, matches[i].off, mlen - MINMATCH); else - price = LZ5HC_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - LZ5_LIT_COST(llen); + price = ZSTD_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - ZSTD_LIT_COST(llen); } else { litlen = 0; - price = opt[cur2].price + LZ5HC_get_price(litlen, matches[i].off, mlen - MINMATCH); + price = opt[cur2].price + ZSTD_get_price(litlen, matches[i].off, mlen - MINMATCH); } - LZ5_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); - LZ5_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); + ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); + ZSTD_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); if (cur2 + mlen > last_pos || (price < opt[cur2 + mlen].price)) { @@ -814,7 +829,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, { for (int i=cur_min-1; i<=last_pos; i++) { - LZ5_LOG_PARSER("%d: BEFORE price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + ZSTD_LOG_PARSER("%d: BEFORE price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); } for (int i=cur_min+1; i<=last_pos; i++) @@ -826,35 +841,35 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (i != litlen) { - price = opt[i - litlen].price + LZ5_LIT_ONLY_COST(litlen); - LZ5_LOG_TRY_PRICE("%d: TRY9 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), i - litlen, opt[i - litlen].price, price, i, litlen); + price = opt[i - litlen].price + ZSTD_LIT_ONLY_COST(litlen); + ZSTD_LOG_TRY_PRICE("%d: TRY9 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), i - litlen, opt[i - litlen].price, price, i, litlen); } else { - price = LZ5_LIT_ONLY_COST(llen + litlen) - llen; - LZ5_LOG_TRY_PRICE("%d: TRY10 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, i, litlen, llen); + price = ZSTD_LIT_ONLY_COST(llen + litlen) - llen; + ZSTD_LOG_TRY_PRICE("%d: TRY10 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, i, litlen, llen); } } else { litlen = 1; - price = opt[i - 1].price + LZ5_LIT_ONLY_COST(litlen); - LZ5_LOG_TRY_PRICE("%d: TRY11 price=%d cur=%d litlen=%d\n", (int)(inr-base), price, i, litlen); + price = opt[i - 1].price + ZSTD_LIT_ONLY_COST(litlen); + ZSTD_LOG_TRY_PRICE("%d: TRY11 price=%d cur=%d litlen=%d\n", (int)(inr-base), price, i, litlen); } mlen = 1; best_mlen = 0; - LZ5_LOG_TRY_PRICE("%d: TRY12 price=%d opt[%d].price=%d\n", (int)(inr-base), price, i + mlen, opt[i + mlen].price); + ZSTD_LOG_TRY_PRICE("%d: TRY12 price=%d opt[%d].price=%d\n", (int)(inr-base), price, i + mlen, opt[i + mlen].price); SET_PRICE(i, mlen, best_mlen, litlen, price); opt[i].rep = opt[i-1].rep; // copy reps - LZ5_LOG_PARSER("%d: INVALIDATE pred=%d price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(inr-base), cur-cur_min, i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + ZSTD_LOG_PARSER("%d: INVALIDATE pred=%d price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(inr-base), cur-cur_min, i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); } for (int i=cur_min-1; i<=last_pos; i++) { - LZ5_LOG_PARSER("%d: AFTER price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); + ZSTD_LOG_PARSER("%d: AFTER price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); } } @@ -869,8 +884,8 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, /* store sequence */ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set for (int i = 1; i <= last_pos; i++) - LZ5_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); - LZ5_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-base+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); + ZSTD_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); + ZSTD_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-base+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); opt[0].mlen = 1; size_t offset; @@ -888,7 +903,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set for (int i = 0; i <= last_pos;) { - LZ5_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); + ZSTD_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); i += opt[i].mlen; } @@ -896,7 +911,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set while (cur < last_pos) { - LZ5_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); + ZSTD_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); mlen = opt[cur].mlen; if (mlen == 1) { ip++; cur++; continue; } offset = opt[cur].off; @@ -906,7 +921,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set size_t litLength = ip - anchor; - LZ5_LOG_ENCODE("%d/%d: BEFORE_ENCODE literals=%d mlen=%d off=%d rep1=%d rep2=%d cur_rep=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2, cur_rep); + ZSTD_LOG_ENCODE("%d/%d: BEFORE_ENCODE literals=%d mlen=%d off=%d rep1=%d rep2=%d cur_rep=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2, cur_rep); #if 1 if (rep_1 != cur_rep) @@ -931,7 +946,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set } } - LZ5_LOG_ENCODE("%d/%d: ENCODE literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); + ZSTD_LOG_ENCODE("%d/%d: ENCODE literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); // printf("orig="); print_hex_text(ip, mlen, 0); // printf("match="); print_hex_text(ip-offset, mlen, 0); @@ -984,7 +999,8 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set best_off = rep_2; rep_2 = rep_1; rep_1 = best_off; - LZ5_LOG_ENCODE("%d/%d: ENCODE REP literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(anchor-base), (int)(iend-base), (int)(0), (int)best_mlen, (int)(0), (int)rep_1, (int)rep_2); + ZSTD_LOG_ENCODE("%d/%d: ENCODE REP literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(anchor-base), (int)(iend-base), (int)(0), (int)best_mlen, (int)(0), (int)rep_1, (int)rep_2); + ZSTD_updatePrice(seqStorePtr, 0, anchor, 0, best_mlen); ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, best_mlen); anchor += best_mlen+MINMATCH; ip = anchor; @@ -995,7 +1011,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set /* Last Literals */ { size_t lastLLSize = iend - anchor; - LZ5_LOG_ENCODE("%d: lastLLSize literals=%d\n", (int)(ip-base), (int)(lastLLSize)); + ZSTD_LOG_ENCODE("%d: lastLLSize literals=%d\n", (int)(ip-base), (int)(lastLLSize)); memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } From 1292509987d73a1371caa99230736f0f3cd475a0 Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 3 Feb 2016 19:13:28 +0100 Subject: [PATCH 024/113] ZSTD_get_price --- lib/zstd_opt.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 1d1a44a5c..54fecce8c 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -57,25 +57,25 @@ entropy encoded and the offset is put into a binary stream. #define ZSTD_LIT_COST(len) (((len)<<3)+0) -FORCE_INLINE U32 ZSTD_get_price(U32 litlen, U32 offset, U32 mlen) +FORCE_INLINE size_t ZSTD_get_price(seqStore_t* seqStorePtr, size_t litlen, size_t offset, size_t mlen) { size_t lit_cost = (litlen<<3)+0; size_t match_cost = /*MLbits +*/ ZSTD_highbit((U32)mlen+1) + Offbits + ZSTD_highbit((U32)offset+1); return lit_cost + match_cost; } -MEM_STATIC size_t ZSTD_updatePrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offset, size_t matchCode) +MEM_STATIC size_t ZSTD_updatePrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offset, size_t matchLength) { #if 0 static const BYTE* g_start = NULL; if (g_start==NULL) g_start = literals; //if (literals - g_start == 8695) printf("pos %6u : %3u literals & match %3u bytes at distance %6u \n", - (U32)(literals - g_start), (U32)litLength, (U32)matchCode+4, (U32)offset); + (U32)(literals - g_start), (U32)litLength, (U32)matchLength+4, (U32)offset); #endif size_t price = 0; - printf("litSum=%d litLengthSum=%d matchLengthSum=%d offCodeSum=%d\n", seqStorePtr->litSum, seqStorePtr->litLengthSum, seqStorePtr->matchLengthSum, seqStorePtr->offCodeSum); + // printf("litSum=%d litLengthSum=%d matchLengthSum=%d offCodeSum=%d\n", seqStorePtr->litSum, seqStorePtr->litLengthSum, seqStorePtr->matchLengthSum, seqStorePtr->offCodeSum); /* literals */ seqStorePtr->litSum += litLength; @@ -102,15 +102,15 @@ MEM_STATIC size_t ZSTD_updatePrice(seqStore_t* seqStorePtr, size_t litLength, co /* match Length */ seqStorePtr->matchLengthSum++; - if (matchCode >= MaxML) { + if (matchLength >= MaxML) { seqStorePtr->matchLengthFreq[MaxML]++; - if (matchCode < 255+MaxML) { + if (matchLength < 255+MaxML) { price += 8; } else { price += 8; - if (matchCode < (1<<15)) price += 16; else price += 24; + if (matchLength < (1<<15)) price += 16; else price += 24; } } - else seqStorePtr->matchLengthFreq[matchCode]++; + else seqStorePtr->matchLengthFreq[matchLength]++; return price; } @@ -576,7 +576,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, do { litlen = 0; - price = ZSTD_get_price(llen + 1, 0, mlen - MINMATCH) - ZSTD_LIT_COST(llen + 1); + price = ZSTD_get_price(seqStorePtr, llen + 1, 0, mlen - MINMATCH) - ZSTD_LIT_COST(llen + 1); if (mlen + 1 > last_pos || price < opt[mlen + 1].price) SET_PRICE(mlen + 1, mlen, 0, litlen, price); mlen--; @@ -621,7 +621,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, while (mlen <= best_mlen) { litlen = 0; - price = ZSTD_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - ZSTD_LIT_COST(llen); + price = ZSTD_get_price(seqStorePtr, llen + litlen, matches[i].off, mlen - MINMATCH) - ZSTD_LIT_COST(llen); if (mlen > last_pos || price < opt[mlen].price) SET_PRICE(mlen, mlen, matches[i].off, litlen, price); mlen++; @@ -728,20 +728,20 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (cur != litlen) { - price = opt[cur - litlen].price + ZSTD_get_price(litlen, 0, mlen - MINMATCH); + price = opt[cur - litlen].price + ZSTD_get_price(seqStorePtr, litlen, 0, mlen - MINMATCH); ZSTD_LOG_TRY_PRICE("%d: TRY5 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); } else { - price = ZSTD_get_price(llen + litlen, 0, mlen - MINMATCH) - ZSTD_LIT_COST(llen); + price = ZSTD_get_price(seqStorePtr, llen + litlen, 0, mlen - MINMATCH) - ZSTD_LIT_COST(llen); ZSTD_LOG_TRY_PRICE("%d: TRY6 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, cur, litlen, llen); } } else { litlen = 0; - price = opt[cur].price + ZSTD_get_price(litlen, 0, mlen - MINMATCH); - ZSTD_LOG_TRY_PRICE("%d: TRY7 price=%d cur=%d litlen=%d getprice=%d\n", (int)(inr-base), price, cur, litlen, ZSTD_get_price(litlen, 0, mlen - MINMATCH)); + price = opt[cur].price + ZSTD_get_price(seqStorePtr, litlen, 0, mlen - MINMATCH); + ZSTD_LOG_TRY_PRICE("%d: TRY7 price=%d cur=%d litlen=%d getprice=%d\n", (int)(inr-base), price, cur, litlen, ZSTD_get_price(seqStorePtr, litlen, 0, mlen - MINMATCH)); } best_mlen = mlen; @@ -800,14 +800,14 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, litlen = opt[cur2].litlen; if (cur2 != litlen) - price = opt[cur2 - litlen].price + ZSTD_get_price(litlen, matches[i].off, mlen - MINMATCH); + price = opt[cur2 - litlen].price + ZSTD_get_price(seqStorePtr, litlen, matches[i].off, mlen - MINMATCH); else - price = ZSTD_get_price(llen + litlen, matches[i].off, mlen - MINMATCH) - ZSTD_LIT_COST(llen); + price = ZSTD_get_price(seqStorePtr, llen + litlen, matches[i].off, mlen - MINMATCH) - ZSTD_LIT_COST(llen); } else { litlen = 0; - price = opt[cur2].price + ZSTD_get_price(litlen, matches[i].off, mlen - MINMATCH); + price = opt[cur2].price + ZSTD_get_price(seqStorePtr, litlen, matches[i].off, mlen - MINMATCH); } ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); From 892776efd6423f82f772f9e181f88d2a1976a53c Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 3 Feb 2016 19:27:44 +0100 Subject: [PATCH 025/113] ZSTD_get_price2 --- lib/zstd_opt.c | 41 ++++++++++------------------------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 54fecce8c..2f89a647e 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -32,32 +32,11 @@ typedef struct #define ZSTD_OPT_NUM (1<<12) -/* -I assume that you are using 4 entropy-coder tables: -litLength = FSE_decodeSymbol(&(seqState->stateLL), &(seqState->DStream)); -offsetCode = FSE_decodeSymbol(&(seqState->stateOffb), &(seqState->DStream)); -matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); -HUF_decompress(dst, litSize, ip+5, litCSize) - -With the following max values: -#define MLbits 7 -#define LLbits 6 -#define Offbits 5 -#define MaxML ((1<= maxValue then use additional 1 byte (if value < -maxValue+255) or 3 bytes (to encode value up to MaxValue+255+65535). - -For offsets only the numbers of bits == log2(offset) are -entropy encoded and the offset is put into a binary stream. -*/ - #define ZSTD_LIT_ONLY_COST(len) (((len)<<3)+1+0) #define ZSTD_LIT_COST(len) (((len)<<3)+0) -FORCE_INLINE size_t ZSTD_get_price(seqStore_t* seqStorePtr, size_t litlen, size_t offset, size_t mlen) +FORCE_INLINE size_t ZSTD_get_price(seqStore_t* seqStorePtr, size_t litlen, const BYTE* literals, size_t offset, size_t mlen) { size_t lit_cost = (litlen<<3)+0; size_t match_cost = /*MLbits +*/ ZSTD_highbit((U32)mlen+1) + Offbits + ZSTD_highbit((U32)offset+1); @@ -576,7 +555,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, do { litlen = 0; - price = ZSTD_get_price(seqStorePtr, llen + 1, 0, mlen - MINMATCH) - ZSTD_LIT_COST(llen + 1); + price = ZSTD_get_price(seqStorePtr, llen + 1, anchor, 0, mlen - MINMATCH) - ZSTD_LIT_COST(llen + 1); if (mlen + 1 > last_pos || price < opt[mlen + 1].price) SET_PRICE(mlen + 1, mlen, 0, litlen, price); mlen--; @@ -621,7 +600,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, while (mlen <= best_mlen) { litlen = 0; - price = ZSTD_get_price(seqStorePtr, llen + litlen, matches[i].off, mlen - MINMATCH) - ZSTD_LIT_COST(llen); + price = ZSTD_get_price(seqStorePtr, llen + litlen, anchor, matches[i].off, mlen - MINMATCH) - ZSTD_LIT_COST(llen); if (mlen > last_pos || price < opt[mlen].price) SET_PRICE(mlen, mlen, matches[i].off, litlen, price); mlen++; @@ -728,20 +707,20 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (cur != litlen) { - price = opt[cur - litlen].price + ZSTD_get_price(seqStorePtr, litlen, 0, mlen - MINMATCH); + price = opt[cur - litlen].price + ZSTD_get_price(seqStorePtr, litlen, inr-litlen, 0, mlen - MINMATCH); ZSTD_LOG_TRY_PRICE("%d: TRY5 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); } else { - price = ZSTD_get_price(seqStorePtr, llen + litlen, 0, mlen - MINMATCH) - ZSTD_LIT_COST(llen); + price = ZSTD_get_price(seqStorePtr, llen + litlen, anchor, 0, mlen - MINMATCH) - ZSTD_LIT_COST(llen); ZSTD_LOG_TRY_PRICE("%d: TRY6 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, cur, litlen, llen); } } else { litlen = 0; - price = opt[cur].price + ZSTD_get_price(seqStorePtr, litlen, 0, mlen - MINMATCH); - ZSTD_LOG_TRY_PRICE("%d: TRY7 price=%d cur=%d litlen=%d getprice=%d\n", (int)(inr-base), price, cur, litlen, ZSTD_get_price(seqStorePtr, litlen, 0, mlen - MINMATCH)); + price = opt[cur].price + ZSTD_get_price(seqStorePtr, 0, NULL, 0, mlen - MINMATCH); + ZSTD_LOG_TRY_PRICE("%d: TRY7 price=%d cur=%d litlen=0 getprice=%d\n", (int)(inr-base), price, cur, ZSTD_get_price(seqStorePtr, 0, NULL, 0, mlen - MINMATCH)); } best_mlen = mlen; @@ -800,14 +779,14 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, litlen = opt[cur2].litlen; if (cur2 != litlen) - price = opt[cur2 - litlen].price + ZSTD_get_price(seqStorePtr, litlen, matches[i].off, mlen - MINMATCH); + price = opt[cur2 - litlen].price + ZSTD_get_price(seqStorePtr, litlen, ip+cur2-litlen, matches[i].off, mlen - MINMATCH); else - price = ZSTD_get_price(seqStorePtr, llen + litlen, matches[i].off, mlen - MINMATCH) - ZSTD_LIT_COST(llen); + price = ZSTD_get_price(seqStorePtr, llen + litlen, anchor, matches[i].off, mlen - MINMATCH) - ZSTD_LIT_COST(llen); } else { litlen = 0; - price = opt[cur2].price + ZSTD_get_price(seqStorePtr, litlen, matches[i].off, mlen - MINMATCH); + price = opt[cur2].price + ZSTD_get_price(seqStorePtr, 0, NULL, matches[i].off, mlen - MINMATCH); } ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); From dbbedfbd95be66fc1e55b4bf65ec8c342765ce99 Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 3 Feb 2016 19:53:29 +0100 Subject: [PATCH 026/113] ZSTD_getLiteralPrice --- lib/zstd_opt.c | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 2f89a647e..8ba922028 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -32,13 +32,19 @@ typedef struct #define ZSTD_OPT_NUM (1<<12) -#define ZSTD_LIT_ONLY_COST(len) (((len)<<3)+1+0) +#define ZSTD_LIT_COST(len) 0 //(((len)<<3)+0) -#define ZSTD_LIT_COST(len) (((len)<<3)+0) -FORCE_INLINE size_t ZSTD_get_price(seqStore_t* seqStorePtr, size_t litlen, const BYTE* literals, size_t offset, size_t mlen) +FORCE_INLINE size_t ZSTD_getLiteralPrice(seqStore_t* seqStorePtr, size_t litlen, const BYTE* literals) { - size_t lit_cost = (litlen<<3)+0; + size_t lit_cost = (litlen<<3)+1+0; + return lit_cost; +} + + +FORCE_INLINE size_t ZSTD_getPrice(seqStore_t* seqStorePtr, size_t litlen, const BYTE* literals, size_t offset, size_t mlen) +{ + size_t lit_cost = (litlen<<3)+0; size_t match_cost = /*MLbits +*/ ZSTD_highbit((U32)mlen+1) + Offbits + ZSTD_highbit((U32)offset+1); return lit_cost + match_cost; } @@ -555,7 +561,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, do { litlen = 0; - price = ZSTD_get_price(seqStorePtr, llen + 1, anchor, 0, mlen - MINMATCH) - ZSTD_LIT_COST(llen + 1); + price = ZSTD_getPrice(seqStorePtr, llen + 1, anchor, 0, mlen - MINMATCH) - ZSTD_LIT_COST(llen + 1); if (mlen + 1 > last_pos || price < opt[mlen + 1].price) SET_PRICE(mlen + 1, mlen, 0, litlen, price); mlen--; @@ -581,7 +587,8 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, // opt[0].mlen = opt[1].mlen = 1; opt[0].rep = opt[0].rep2 = rep_1; opt[0].mlen = 1; - + // opt[0].price = ZSTD_getLiteralPrice(seqStorePtr, 1, ip); + if (match_num && matches[match_num-1].len > sufficient_len) { best_mlen = matches[match_num-1].len; @@ -600,7 +607,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, while (mlen <= best_mlen) { litlen = 0; - price = ZSTD_get_price(seqStorePtr, llen + litlen, anchor, matches[i].off, mlen - MINMATCH) - ZSTD_LIT_COST(llen); + price = ZSTD_getPrice(seqStorePtr, llen + litlen, anchor, matches[i].off, mlen - MINMATCH) - ZSTD_LIT_COST(llen); if (mlen > last_pos || price < opt[mlen].price) SET_PRICE(mlen, mlen, matches[i].off, litlen, price); mlen++; @@ -624,20 +631,20 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (cur != litlen) { - price = opt[cur - litlen].price + ZSTD_LIT_ONLY_COST(litlen); + price = opt[cur - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-litlen); ZSTD_LOG_TRY_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); } else { - price = ZSTD_LIT_ONLY_COST(llen + litlen) - llen; + price = ZSTD_getLiteralPrice(seqStorePtr, llen + litlen, inr-(llen+litlen)) - ZSTD_LIT_COST(llen); ZSTD_LOG_TRY_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, cur, litlen, llen); } } else { litlen = 1; - price = opt[cur - 1].price + ZSTD_LIT_ONLY_COST(litlen); - ZSTD_LOG_TRY_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)(inr-base), price, cur, litlen, ZSTD_LIT_ONLY_COST(litlen)); + price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1); + ZSTD_LOG_TRY_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)(inr-base), price, cur, litlen, ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1)); } mlen = 1; @@ -707,20 +714,20 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (cur != litlen) { - price = opt[cur - litlen].price + ZSTD_get_price(seqStorePtr, litlen, inr-litlen, 0, mlen - MINMATCH); + price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, inr-litlen, 0, mlen - MINMATCH); ZSTD_LOG_TRY_PRICE("%d: TRY5 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); } else { - price = ZSTD_get_price(seqStorePtr, llen + litlen, anchor, 0, mlen - MINMATCH) - ZSTD_LIT_COST(llen); + price = ZSTD_getPrice(seqStorePtr, llen + litlen, anchor, 0, mlen - MINMATCH) - ZSTD_LIT_COST(llen); ZSTD_LOG_TRY_PRICE("%d: TRY6 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, cur, litlen, llen); } } else { litlen = 0; - price = opt[cur].price + ZSTD_get_price(seqStorePtr, 0, NULL, 0, mlen - MINMATCH); - ZSTD_LOG_TRY_PRICE("%d: TRY7 price=%d cur=%d litlen=0 getprice=%d\n", (int)(inr-base), price, cur, ZSTD_get_price(seqStorePtr, 0, NULL, 0, mlen - MINMATCH)); + price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, 0, mlen - MINMATCH); + ZSTD_LOG_TRY_PRICE("%d: TRY7 price=%d cur=%d litlen=0 getprice=%d\n", (int)(inr-base), price, cur, ZSTD_getPrice(seqStorePtr, 0, NULL, 0, mlen - MINMATCH)); } best_mlen = mlen; @@ -779,14 +786,14 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, litlen = opt[cur2].litlen; if (cur2 != litlen) - price = opt[cur2 - litlen].price + ZSTD_get_price(seqStorePtr, litlen, ip+cur2-litlen, matches[i].off, mlen - MINMATCH); + price = opt[cur2 - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, ip+cur2-litlen, matches[i].off, mlen - MINMATCH); else - price = ZSTD_get_price(seqStorePtr, llen + litlen, anchor, matches[i].off, mlen - MINMATCH) - ZSTD_LIT_COST(llen); + price = ZSTD_getPrice(seqStorePtr, llen + litlen, anchor, matches[i].off, mlen - MINMATCH) - ZSTD_LIT_COST(llen); } else { litlen = 0; - price = opt[cur2].price + ZSTD_get_price(seqStorePtr, 0, NULL, matches[i].off, mlen - MINMATCH); + price = opt[cur2].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[i].off, mlen - MINMATCH); } ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); @@ -820,19 +827,19 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (i != litlen) { - price = opt[i - litlen].price + ZSTD_LIT_ONLY_COST(litlen); + price = opt[i - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, ip+i-litlen); ZSTD_LOG_TRY_PRICE("%d: TRY9 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), i - litlen, opt[i - litlen].price, price, i, litlen); } else { - price = ZSTD_LIT_ONLY_COST(llen + litlen) - llen; + price = ZSTD_getLiteralPrice(seqStorePtr, llen + litlen, ip+i-(llen + litlen)) - ZSTD_LIT_COST(llen); ZSTD_LOG_TRY_PRICE("%d: TRY10 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, i, litlen, llen); } } else { litlen = 1; - price = opt[i - 1].price + ZSTD_LIT_ONLY_COST(litlen); + price = opt[i - 1].price + ZSTD_getLiteralPrice(seqStorePtr, 1, ip+i-1); ZSTD_LOG_TRY_PRICE("%d: TRY11 price=%d cur=%d litlen=%d\n", (int)(inr-base), price, i, litlen); } From a98149df595c27570deda9a6b54602ece8fa30d4 Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 3 Feb 2016 21:26:18 +0100 Subject: [PATCH 027/113] ZSTD_getLiteralPrice 2 --- lib/zstd_opt.c | 133 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 103 insertions(+), 30 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 8ba922028..090afc4d1 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -1,4 +1,5 @@ #include +#include // log typedef struct { @@ -17,7 +18,7 @@ typedef struct int rep2; } ZSTD_optimal_t; -#if 1 +#if 0 #define ZSTD_LOG_PARSER(fmt, args...) ;// printf(fmt, ##args) #define ZSTD_LOG_PRICE(fmt, args...) ;//printf(fmt, ##args) #define ZSTD_LOG_ENCODE(fmt, args...) ;//printf(fmt, ##args) @@ -35,21 +36,108 @@ typedef struct #define ZSTD_LIT_COST(len) 0 //(((len)<<3)+0) +#if 0 FORCE_INLINE size_t ZSTD_getLiteralPrice(seqStore_t* seqStorePtr, size_t litlen, const BYTE* literals) { size_t lit_cost = (litlen<<3)+1+0; return lit_cost; } - -FORCE_INLINE size_t ZSTD_getPrice(seqStore_t* seqStorePtr, size_t litlen, const BYTE* literals, size_t offset, size_t mlen) +#else +FORCE_INLINE size_t ZSTD_getLiteralPrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals) { - size_t lit_cost = (litlen<<3)+0; - size_t match_cost = /*MLbits +*/ ZSTD_highbit((U32)mlen+1) + Offbits + ZSTD_highbit((U32)offset+1); + size_t freq; + size_t price = 0; + double litBits, litLenBits; + // printf("litSum=%d litLengthSum=%d matchLengthSum=%d offCodeSum=%d\n", seqStorePtr->litSum, seqStorePtr->litLengthSum, seqStorePtr->matchLengthSum, seqStorePtr->offCodeSum); + + /* literals */ + litBits = 0.0f; + if (litLength > 0) { + for (int i=litLength-1; i>=0; i--) + litBits += -log2((double)seqStorePtr->litFreq[literals[i]]/(double)seqStorePtr->litSum); + + /* literal Length */ + if (litLength >= MaxLL) { + freq = seqStorePtr->litLengthFreq[MaxLL]; + if (litLength<255 + MaxLL) { + price += 8; + } else { + price += 8; + if (litLength < (1<<15)) price += 16; else price += 24; + } } + else freq = seqStorePtr->litLengthFreq[litLength]; + litLenBits = -log2((double)freq/(double)seqStorePtr->litLengthSum); + } + else litLenBits = 0.0f; + + freq = round(litBits + litLenBits + price); + // printf("litLength=%d litBits=%.02f litLenBits=%.02f dumpsPrice=%d sum=%d\n", (int)litLength, litBits, litLenBits, (int)price, (int)freq); + return freq; +} +#endif + + +FORCE_INLINE size_t ZSTD_getPrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offset, size_t matchLength) +{ +#if 1 + size_t freq; + size_t price = 0; + double litBits, litLenBits, offCodeBits, matchBits; + // printf("litSum=%d litLengthSum=%d matchLengthSum=%d offCodeSum=%d\n", seqStorePtr->litSum, seqStorePtr->litLengthSum, seqStorePtr->matchLengthSum, seqStorePtr->offCodeSum); + + /* literals */ + litBits = 0.0f; + if (litLength > 0) { + for (int i=litLength-1; i>=0; i--) + litBits += -log2((double)seqStorePtr->litFreq[literals[i]]/(double)seqStorePtr->litSum); + + /* literal Length */ + if (litLength >= MaxLL) { + freq = seqStorePtr->litLengthFreq[MaxLL]; + if (litLength<255 + MaxLL) { + price += 8; + } else { + price += 8; + if (litLength < (1<<15)) price += 16; else price += 24; + } } + else freq = seqStorePtr->litLengthFreq[litLength]; + litLenBits = -log2((double)freq/(double)seqStorePtr->litLengthSum); + } + else litLenBits = 0.0f; + + /* match offset */ + BYTE offCode = (BYTE)ZSTD_highbit(offset) + 1; + if (offset==0) + offCodeBits = 0.0f; + else + offCodeBits = -log2((double)seqStorePtr->offCodeFreq[offCode]/(double)seqStorePtr->offCodeSum); + + /* match Length */ + if (matchLength >= MaxML) { + freq = seqStorePtr->matchLengthFreq[MaxML]; + if (matchLength < 255+MaxML) { + price += 8; + } else { + price += 8; + if (matchLength < (1<<15)) price += 16; else price += 24; + } } + else freq = seqStorePtr->matchLengthFreq[matchLength]; + matchBits = -log2((double)freq/(double)seqStorePtr->matchLengthSum); + + freq = round(litBits + litLenBits + offCodeBits + matchBits + price); + // printf("litLength=%d litBits=%.02f litLenBits=%.02f offCodeBits=%.02f matchBits=%.02f dumpsPrice=%d sum=%d\n", (int)litLength, litBits, litLenBits, offCodeBits, matchBits, (int)price, (int)freq); + return freq; +#else + size_t lit_cost = (litLength<<3)+0; + size_t match_cost = /*MLbits +*/ ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); return lit_cost + match_cost; +#endif } -MEM_STATIC size_t ZSTD_updatePrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offset, size_t matchLength) + + +MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offset, size_t matchLength) { #if 0 static const BYTE* g_start = NULL; @@ -58,10 +146,6 @@ MEM_STATIC size_t ZSTD_updatePrice(seqStore_t* seqStorePtr, size_t litLength, co printf("pos %6u : %3u literals & match %3u bytes at distance %6u \n", (U32)(literals - g_start), (U32)litLength, (U32)matchLength+4, (U32)offset); #endif - size_t price = 0; - - // printf("litSum=%d litLengthSum=%d matchLengthSum=%d offCodeSum=%d\n", seqStorePtr->litSum, seqStorePtr->litLengthSum, seqStorePtr->matchLengthSum, seqStorePtr->offCodeSum); - /* literals */ seqStorePtr->litSum += litLength; for (int i=litLength-1; i>=0; i--) @@ -69,15 +153,10 @@ MEM_STATIC size_t ZSTD_updatePrice(seqStore_t* seqStorePtr, size_t litLength, co /* literal Length */ seqStorePtr->litLengthSum++; - if (litLength >= MaxLL) { + if (litLength >= MaxLL) seqStorePtr->litLengthFreq[MaxLL]++; - if (litLength<255 + MaxLL) { - price += 8; - } else { - price += 8; - if (litLength < (1<<15)) price += 16; else price += 24; - } } - else seqStorePtr->litLengthFreq[litLength]++; + else + seqStorePtr->litLengthFreq[litLength]++; /* match offset */ seqStorePtr->offCodeSum++; @@ -87,17 +166,10 @@ MEM_STATIC size_t ZSTD_updatePrice(seqStore_t* seqStorePtr, size_t litLength, co /* match Length */ seqStorePtr->matchLengthSum++; - if (matchLength >= MaxML) { + if (matchLength >= MaxML) seqStorePtr->matchLengthFreq[MaxML]++; - if (matchLength < 255+MaxML) { - price += 8; - } else { - price += 8; - if (matchLength < (1<<15)) price += 16; else price += 24; - } } - else seqStorePtr->matchLengthFreq[matchLength]++; - - return price; + else + seqStorePtr->matchLengthFreq[matchLength]++; } @@ -585,7 +657,8 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, // opt[0].rep = opt[1].rep = rep_1; // opt[0].mlen = opt[1].mlen = 1; - opt[0].rep = opt[0].rep2 = rep_1; + opt[0].rep = rep_1; + opt[0].rep2 = rep_1; opt[0].mlen = 1; // opt[0].price = ZSTD_getLiteralPrice(seqStorePtr, 1, ip); @@ -936,7 +1009,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set // printf("orig="); print_hex_text(ip, mlen, 0); // printf("match="); print_hex_text(ip-offset, mlen, 0); -#if 1 +#if 0 size_t ml2; if (offset) ml2 = ZSTD_count(ip, ip-offset, iend); From 70b054559b883db78558cdd3928565a4b778b03d Mon Sep 17 00:00:00 2001 From: inikep Date: Wed, 3 Feb 2016 22:56:55 +0100 Subject: [PATCH 028/113] MaxLit --- lib/zstd_compress.c | 26 +++++++++++++++----------- lib/zstd_internal.h | 1 + 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 4b345c4aa..601df8159 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -88,10 +88,10 @@ typedef struct { BYTE* matchLength; BYTE* dumpsStart; BYTE* dumps; - BYTE* matchLengthFreq; - BYTE* litLengthFreq; - BYTE* litFreq; - BYTE* offCodeFreq; + U32* matchLengthFreq; + U32* litLengthFreq; + U32* litFreq; + U32* offCodeFreq; U32 matchLengthSum; U32 litLengthSum; U32 litSum; @@ -111,10 +111,14 @@ static void ZSTD_resetSeqStore(seqStore_t* ssPtr) ssPtr->litSum = (1<offCodeSum = (1<litFreq, 1, (1<litLengthFreq, 1, (1<matchLengthFreq, 1, (1<offCodeFreq, 1, (1<litFreq[i] = 1; + for (int i=0; i<=MaxLL; i++) + ssPtr->litLengthFreq[i] = 1; + for (int i=0; i<=MaxML; i++) + ssPtr->matchLengthFreq[i] = 1; + for (int i=0; i<=MaxOff; i++) + ssPtr->offCodeFreq[i] = 1; } @@ -202,7 +206,7 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, /* reserve table memory */ const U32 contentLog = (params.strategy == ZSTD_fast) ? 1 : params.contentLog; const size_t tableSpace = ((1 << contentLog) + (1 << params.hashLog)) * sizeof(U32); - const size_t neededSpace = tableSpace + (256*sizeof(U32)) + (3*blockSize) + (1<workSpaceSize < neededSpace) { free(zc->workSpace); zc->workSpace = malloc(neededSpace); @@ -231,11 +235,11 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, zc->seqStore.litLengthStart = zc->seqStore.litStart + blockSize; zc->seqStore.matchLengthStart = zc->seqStore.litLengthStart + (blockSize>>2); zc->seqStore.dumpsStart = zc->seqStore.matchLengthStart + (blockSize>>2); - zc->seqStore.litFreq = zc->seqStore.dumpsStart + (blockSize>>2); + zc->seqStore.litFreq = (U32*) (zc->seqStore.dumpsStart + (blockSize>>2)); zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (1<seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (1<seqStore.XXX = zc->seqStore.offCodeFreq + (1<seqStore.XXX = zc->seqStore.offCodeFreq + (1<hbSize = 0; zc->stage = 0; diff --git a/lib/zstd_internal.h b/lib/zstd_internal.h index f2af062f7..eebcc0d77 100644 --- a/lib/zstd_internal.h +++ b/lib/zstd_internal.h @@ -87,6 +87,7 @@ static const size_t ZSTD_frameHeaderSize_min = 5; #define MLbits 7 #define LLbits 6 #define Offbits 5 +#define MaxLit ((1< Date: Thu, 4 Feb 2016 10:04:33 +0100 Subject: [PATCH 029/113] 40370570 ZSTD_getPriceReal --- lib/zstd_opt.c | 71 ++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 090afc4d1..72263b37d 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -18,7 +18,7 @@ typedef struct int rep2; } ZSTD_optimal_t; -#if 0 +#if 1 #define ZSTD_LOG_PARSER(fmt, args...) ;// printf(fmt, ##args) #define ZSTD_LOG_PRICE(fmt, args...) ;//printf(fmt, ##args) #define ZSTD_LOG_ENCODE(fmt, args...) ;//printf(fmt, ##args) @@ -36,15 +36,7 @@ typedef struct #define ZSTD_LIT_COST(len) 0 //(((len)<<3)+0) -#if 0 -FORCE_INLINE size_t ZSTD_getLiteralPrice(seqStore_t* seqStorePtr, size_t litlen, const BYTE* literals) -{ - size_t lit_cost = (litlen<<3)+1+0; - return lit_cost; -} - -#else -FORCE_INLINE size_t ZSTD_getLiteralPrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals) +FORCE_INLINE size_t ZSTD_getLiteralPriceReal(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals) { size_t freq; size_t price = 0; @@ -56,6 +48,7 @@ FORCE_INLINE size_t ZSTD_getLiteralPrice(seqStore_t* seqStorePtr, size_t litLeng if (litLength > 0) { for (int i=litLength-1; i>=0; i--) litBits += -log2((double)seqStorePtr->litFreq[literals[i]]/(double)seqStorePtr->litSum); +// litBits += ceil(-log2((double)seqStorePtr->litFreq[literals[i]]/(double)seqStorePtr->litSum)); /* literal Length */ if (litLength >= MaxLL) { @@ -71,41 +64,35 @@ FORCE_INLINE size_t ZSTD_getLiteralPrice(seqStore_t* seqStorePtr, size_t litLeng } else litLenBits = 0.0f; - freq = round(litBits + litLenBits + price); - // printf("litLength=%d litBits=%.02f litLenBits=%.02f dumpsPrice=%d sum=%d\n", (int)litLength, litBits, litLenBits, (int)price, (int)freq); + freq = round(1.0f*(litBits + litLenBits + price)); +// printf("litLength=%d litBits=%.02f litLenBits=%.02f dumpsPrice=%d sum=%d\n", (int)litLength, litBits, litLenBits, (int)price, (int)freq); + + // printf("old=%d new=%d\n", (int)((litLength<<3)+1), (int)freq/8); + if (freq <= 0) freq = 1; return freq; } -#endif -FORCE_INLINE size_t ZSTD_getPrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offset, size_t matchLength) + +FORCE_INLINE size_t ZSTD_getLiteralPrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals) { #if 1 + return ZSTD_getLiteralPriceReal(seqStorePtr, litLength, literals); +#else + size_t lit_cost = 1 + (litLength<<3)+0; + return lit_cost; +#endif +} + + + +FORCE_INLINE size_t ZSTD_getPriceReal(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offset, size_t matchLength) +{ size_t freq; size_t price = 0; - double litBits, litLenBits, offCodeBits, matchBits; + double offCodeBits, matchBits; // printf("litSum=%d litLengthSum=%d matchLengthSum=%d offCodeSum=%d\n", seqStorePtr->litSum, seqStorePtr->litLengthSum, seqStorePtr->matchLengthSum, seqStorePtr->offCodeSum); - /* literals */ - litBits = 0.0f; - if (litLength > 0) { - for (int i=litLength-1; i>=0; i--) - litBits += -log2((double)seqStorePtr->litFreq[literals[i]]/(double)seqStorePtr->litSum); - - /* literal Length */ - if (litLength >= MaxLL) { - freq = seqStorePtr->litLengthFreq[MaxLL]; - if (litLength<255 + MaxLL) { - price += 8; - } else { - price += 8; - if (litLength < (1<<15)) price += 16; else price += 24; - } } - else freq = seqStorePtr->litLengthFreq[litLength]; - litLenBits = -log2((double)freq/(double)seqStorePtr->litLengthSum); - } - else litLenBits = 0.0f; - /* match offset */ BYTE offCode = (BYTE)ZSTD_highbit(offset) + 1; if (offset==0) @@ -125,9 +112,19 @@ FORCE_INLINE size_t ZSTD_getPrice(seqStore_t* seqStorePtr, size_t litLength, con else freq = seqStorePtr->matchLengthFreq[matchLength]; matchBits = -log2((double)freq/(double)seqStorePtr->matchLengthSum); - freq = round(litBits + litLenBits + offCodeBits + matchBits + price); - // printf("litLength=%d litBits=%.02f litLenBits=%.02f offCodeBits=%.02f matchBits=%.02f dumpsPrice=%d sum=%d\n", (int)litLength, litBits, litLenBits, offCodeBits, matchBits, (int)price, (int)freq); + freq = round(1.0f*(offCodeBits + matchBits + price)); +// printf("litLength=%d litBits=%.02f litLenBits=%.02f offCodeBits=%.02f matchBits=%.02f dumpsPrice=%d sum=%d\n", (int)litLength, litBits, litLenBits, offCodeBits, matchBits, (int)price, (int)freq); + if (freq <= 0) return 1; + return freq; +} + +FORCE_INLINE size_t ZSTD_getPrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offset, size_t matchLength) +{ +#if 1 + size_t lit_cost = ZSTD_getLiteralPriceReal(seqStorePtr, litLength, literals); + size_t match_cost = /*MLbits +*/ ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); + return lit_cost + match_cost; #else size_t lit_cost = (litLength<<3)+0; size_t match_cost = /*MLbits +*/ ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); From 27e1c6a51f42d45d719aa0d56134cce0e40a2225 Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 4 Feb 2016 11:11:08 +0100 Subject: [PATCH 030/113] ZSTD_resetFreqs --- lib/zstd_compress.c | 21 ++++++++++++------ lib/zstd_opt.c | 53 +++++++++++++++++++++++++++++++++------------ 2 files changed, 53 insertions(+), 21 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 601df8159..0b299349c 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -98,14 +98,9 @@ typedef struct { U32 offCodeSum; } seqStore_t; -static void ZSTD_resetSeqStore(seqStore_t* ssPtr) +static void ZSTD_resetFreqs(seqStore_t* ssPtr) { - ssPtr->offset = ssPtr->offsetStart; - ssPtr->lit = ssPtr->litStart; - ssPtr->litLength = ssPtr->litLengthStart; - ssPtr->matchLength = ssPtr->matchLengthStart; - ssPtr->dumps = ssPtr->dumpsStart; - + printf("litSum=%d litLengthSum=%d matchLengthSum=%d offCodeSum=%d\n", ssPtr->litSum, ssPtr->litLengthSum, ssPtr->matchLengthSum, ssPtr->offCodeSum); ssPtr->matchLengthSum = (1<litLengthSum = (1<litSum = (1<offCodeFreq[i] = 1; } +static void ZSTD_resetSeqStore(seqStore_t* ssPtr) +{ + ssPtr->offset = ssPtr->offsetStart; + ssPtr->lit = ssPtr->litStart; + ssPtr->litLength = ssPtr->litLengthStart; + ssPtr->matchLength = ssPtr->matchLengthStart; + ssPtr->dumps = ssPtr->dumpsStart; + + ZSTD_resetFreqs(ssPtr); +} + /* ************************************* * Context memory management @@ -240,6 +246,7 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (1<seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (1<seqStore.XXX = zc->seqStore.offCodeFreq + (1<seqStore); zc->hbSize = 0; zc->stage = 0; diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 72263b37d..ef40648b4 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -33,7 +33,23 @@ typedef struct #define ZSTD_OPT_NUM (1<<12) -#define ZSTD_LIT_COST(len) 0 //(((len)<<3)+0) +#define ZSTD_LIT_COST(len) 0 //(((len)<<3)) + +const int tab32[32] = { + 0, 9, 1, 10, 13, 21, 2, 29, + 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, + 19, 27, 23, 6, 26, 5, 4, 31}; + +int log2_32 (uint32_t value) +{ + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; + return tab32[(uint32_t)(value*0x07C4ACDD) >> 27]; +} FORCE_INLINE size_t ZSTD_getLiteralPriceReal(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals) @@ -79,14 +95,14 @@ FORCE_INLINE size_t ZSTD_getLiteralPrice(seqStore_t* seqStorePtr, size_t litLeng #if 1 return ZSTD_getLiteralPriceReal(seqStorePtr, litLength, literals); #else - size_t lit_cost = 1 + (litLength<<3)+0; + size_t lit_cost = 1 + (litLength<<3); return lit_cost; #endif } -FORCE_INLINE size_t ZSTD_getPriceReal(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offset, size_t matchLength) +FORCE_INLINE size_t ZSTD_getMatchPriceReal(seqStore_t* seqStorePtr, size_t offset, size_t matchLength) { size_t freq; size_t price = 0; @@ -96,9 +112,12 @@ FORCE_INLINE size_t ZSTD_getPriceReal(seqStore_t* seqStorePtr, size_t litLength, /* match offset */ BYTE offCode = (BYTE)ZSTD_highbit(offset) + 1; if (offset==0) - offCodeBits = 0.0f; - else - offCodeBits = -log2((double)seqStorePtr->offCodeFreq[offCode]/(double)seqStorePtr->offCodeSum); + offCode = 0; + // offCodeBits = -log2((double)seqStorePtr->offCodeFreq[offCode]/(double)seqStorePtr->offCodeSum); + offCodeBits = log2_32(seqStorePtr->offCodeSum) - log2_32(seqStorePtr->offCodeFreq[offCode]); + // printf("offCodeBits=%.02f matchBits=%.02f dumpsPrice=%d sum=%d\n", offCodeBits, matchBits, (int)price, (int)freq); + + offCodeBits += offCode; /* match Length */ if (matchLength >= MaxML) { @@ -110,24 +129,30 @@ FORCE_INLINE size_t ZSTD_getPriceReal(seqStore_t* seqStorePtr, size_t litLength, if (matchLength < (1<<15)) price += 16; else price += 24; } } else freq = seqStorePtr->matchLengthFreq[matchLength]; - matchBits = -log2((double)freq/(double)seqStorePtr->matchLengthSum); +// matchBits = -log2((double)freq/(double)seqStorePtr->matchLengthSum); + matchBits = log2_32(seqStorePtr->matchLengthSum) - log2_32(freq); freq = round(1.0f*(offCodeBits + matchBits + price)); -// printf("litLength=%d litBits=%.02f litLenBits=%.02f offCodeBits=%.02f matchBits=%.02f dumpsPrice=%d sum=%d\n", (int)litLength, litBits, litLenBits, offCodeBits, matchBits, (int)price, (int)freq); - if (freq <= 0) return 1; - +// printf("offCodeBits=%.02f matchBits=%.02f dumpsPrice=%d sum=%d\n", offCodeBits, matchBits, (int)price, (int)freq); return freq; } +// zstd v0.5 beta level 23 1.94 MB/s 403 MB/s 40845550 38.95 +// zstd v0.5 beta level 24 1.80 MB/s 458 MB/s 40370570 38.50 +// zstd v0.5 beta level 23 1.10 MB/s ERROR 40584556 38.70 +// zstd v0.5 beta level 24 0.87 MB/s ERROR 40103205 38.25 + FORCE_INLINE size_t ZSTD_getPrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offset, size_t matchLength) { #if 1 size_t lit_cost = ZSTD_getLiteralPriceReal(seqStorePtr, litLength, literals); - size_t match_cost = /*MLbits +*/ ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); + size_t match_cost2 = ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); + size_t match_cost = ZSTD_getMatchPriceReal(seqStorePtr, offset, matchLength); + // printf("old=%d new=%d\n", (int)match_cost2, (int)match_cost); return lit_cost + match_cost; #else - size_t lit_cost = (litLength<<3)+0; - size_t match_cost = /*MLbits +*/ ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); + size_t lit_cost = (litLength<<3); + size_t match_cost = ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); return lit_cost + match_cost; #endif } @@ -979,7 +1004,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set ZSTD_LOG_ENCODE("%d/%d: BEFORE_ENCODE literals=%d mlen=%d off=%d rep1=%d rep2=%d cur_rep=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2, cur_rep); -#if 1 +#if 0 if (rep_1 != cur_rep) { printf("%d: ERROR rep_1=%d rep_2=%d cur_rep=%d\n", (int)(ip - base), (int)rep_1, (int)rep_2, cur_rep); From cb5cd16d6b4fd6cf3f2dfb2e8a82c1760e91e58b Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 4 Feb 2016 11:19:06 +0100 Subject: [PATCH 031/113] 40392170 integer --- lib/zstd_compress.c | 2 +- lib/zstd_opt.c | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 0b299349c..59d9d6064 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -100,7 +100,7 @@ typedef struct { static void ZSTD_resetFreqs(seqStore_t* ssPtr) { - printf("litSum=%d litLengthSum=%d matchLengthSum=%d offCodeSum=%d\n", ssPtr->litSum, ssPtr->litLengthSum, ssPtr->matchLengthSum, ssPtr->offCodeSum); + // printf("litSum=%d litLengthSum=%d matchLengthSum=%d offCodeSum=%d\n", ssPtr->litSum, ssPtr->litLengthSum, ssPtr->matchLengthSum, ssPtr->offCodeSum); ssPtr->matchLengthSum = (1<litLengthSum = (1<litSum = (1<litSum, seqStorePtr->litLengthSum, seqStorePtr->matchLengthSum, seqStorePtr->offCodeSum); /* literals */ litBits = 0.0f; if (litLength > 0) { for (int i=litLength-1; i>=0; i--) - litBits += -log2((double)seqStorePtr->litFreq[literals[i]]/(double)seqStorePtr->litSum); -// litBits += ceil(-log2((double)seqStorePtr->litFreq[literals[i]]/(double)seqStorePtr->litSum)); - +// litBits += -log2((double)seqStorePtr->litFreq[literals[i]]/(double)seqStorePtr->litSum); + litBits += log2_32(seqStorePtr->litSum) - log2_32(seqStorePtr->litFreq[literals[i]]); + /* literal Length */ if (litLength >= MaxLL) { freq = seqStorePtr->litLengthFreq[MaxLL]; @@ -76,11 +76,13 @@ FORCE_INLINE size_t ZSTD_getLiteralPriceReal(seqStore_t* seqStorePtr, size_t lit if (litLength < (1<<15)) price += 16; else price += 24; } } else freq = seqStorePtr->litLengthFreq[litLength]; - litLenBits = -log2((double)freq/(double)seqStorePtr->litLengthSum); +// litLenBits = -log2((double)freq/(double)seqStorePtr->litLengthSum); + litLenBits = log2_32(seqStorePtr->litLengthSum) - log2_32(freq); } else litLenBits = 0.0f; - freq = round(1.0f*(litBits + litLenBits + price)); +// freq = round(1.0f*(litBits + litLenBits + price)); + freq = litBits + litLenBits + price; // printf("litLength=%d litBits=%.02f litLenBits=%.02f dumpsPrice=%d sum=%d\n", (int)litLength, litBits, litLenBits, (int)price, (int)freq); // printf("old=%d new=%d\n", (int)((litLength<<3)+1), (int)freq/8); @@ -106,7 +108,7 @@ FORCE_INLINE size_t ZSTD_getMatchPriceReal(seqStore_t* seqStorePtr, size_t offse { size_t freq; size_t price = 0; - double offCodeBits, matchBits; + size_t offCodeBits, matchBits; // printf("litSum=%d litLengthSum=%d matchLengthSum=%d offCodeSum=%d\n", seqStorePtr->litSum, seqStorePtr->litLengthSum, seqStorePtr->matchLengthSum, seqStorePtr->offCodeSum); /* match offset */ @@ -132,13 +134,14 @@ FORCE_INLINE size_t ZSTD_getMatchPriceReal(seqStore_t* seqStorePtr, size_t offse // matchBits = -log2((double)freq/(double)seqStorePtr->matchLengthSum); matchBits = log2_32(seqStorePtr->matchLengthSum) - log2_32(freq); - freq = round(1.0f*(offCodeBits + matchBits + price)); +// freq = round(1.0f*(offCodeBits + matchBits + price)); + freq = offCodeBits + matchBits + price; // printf("offCodeBits=%.02f matchBits=%.02f dumpsPrice=%d sum=%d\n", offCodeBits, matchBits, (int)price, (int)freq); return freq; } -// zstd v0.5 beta level 23 1.94 MB/s 403 MB/s 40845550 38.95 -// zstd v0.5 beta level 24 1.80 MB/s 458 MB/s 40370570 38.50 +// zstd v0.5 beta level 23 3.05 MB/s 448 MB/s 40868360 38.98 +// zstd v0.5 beta level 24 2.90 MB/s 472 MB/s 40392170 38.52 // zstd v0.5 beta level 23 1.10 MB/s ERROR 40584556 38.70 // zstd v0.5 beta level 24 0.87 MB/s ERROR 40103205 38.25 @@ -149,7 +152,7 @@ FORCE_INLINE size_t ZSTD_getPrice(seqStore_t* seqStorePtr, size_t litLength, con size_t match_cost2 = ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); size_t match_cost = ZSTD_getMatchPriceReal(seqStorePtr, offset, matchLength); // printf("old=%d new=%d\n", (int)match_cost2, (int)match_cost); - return lit_cost + match_cost; + return lit_cost + match_cost2; #else size_t lit_cost = (litLength<<3); size_t match_cost = ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); From 75be1a412c239f4cee7f8d8aa74abcab6f7586f9 Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 4 Feb 2016 11:48:06 +0100 Subject: [PATCH 032/113] fixes --- lib/zstd_opt.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index fbf4c7da6..ff4a59e66 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -60,7 +60,7 @@ FORCE_INLINE size_t ZSTD_getLiteralPriceReal(seqStore_t* seqStorePtr, size_t lit // printf("litSum=%d litLengthSum=%d matchLengthSum=%d offCodeSum=%d\n", seqStorePtr->litSum, seqStorePtr->litLengthSum, seqStorePtr->matchLengthSum, seqStorePtr->offCodeSum); /* literals */ - litBits = 0.0f; + litBits = 0; if (litLength > 0) { for (int i=litLength-1; i>=0; i--) // litBits += -log2((double)seqStorePtr->litFreq[literals[i]]/(double)seqStorePtr->litSum); @@ -79,7 +79,7 @@ FORCE_INLINE size_t ZSTD_getLiteralPriceReal(seqStore_t* seqStorePtr, size_t lit // litLenBits = -log2((double)freq/(double)seqStorePtr->litLengthSum); litLenBits = log2_32(seqStorePtr->litLengthSum) - log2_32(freq); } - else litLenBits = 0.0f; + else litLenBits = 0; // freq = round(1.0f*(litBits + litLenBits + price)); freq = litBits + litLenBits + price; @@ -149,10 +149,10 @@ FORCE_INLINE size_t ZSTD_getPrice(seqStore_t* seqStorePtr, size_t litLength, con { #if 1 size_t lit_cost = ZSTD_getLiteralPriceReal(seqStorePtr, litLength, literals); - size_t match_cost2 = ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); + size_t match_cost_old = ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); size_t match_cost = ZSTD_getMatchPriceReal(seqStorePtr, offset, matchLength); // printf("old=%d new=%d\n", (int)match_cost2, (int)match_cost); - return lit_cost + match_cost2; + return lit_cost + match_cost_old; #else size_t lit_cost = (litLength<<3); size_t match_cost = ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); @@ -657,7 +657,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, do { - litlen = 0; + litlen = 1; price = ZSTD_getPrice(seqStorePtr, llen + 1, anchor, 0, mlen - MINMATCH) - ZSTD_LIT_COST(llen + 1); if (mlen + 1 > last_pos || price < opt[mlen + 1].price) SET_PRICE(mlen + 1, mlen, 0, litlen, price); @@ -1007,7 +1007,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set ZSTD_LOG_ENCODE("%d/%d: BEFORE_ENCODE literals=%d mlen=%d off=%d rep1=%d rep2=%d cur_rep=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2, cur_rep); -#if 0 +#if 1 if (rep_1 != cur_rep) { printf("%d: ERROR rep_1=%d rep_2=%d cur_rep=%d\n", (int)(ip - base), (int)rep_1, (int)rep_2, cur_rep); @@ -1034,7 +1034,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set // printf("orig="); print_hex_text(ip, mlen, 0); // printf("match="); print_hex_text(ip-offset, mlen, 0); -#if 0 +#if 1 size_t ml2; if (offset) ml2 = ZSTD_count(ip, ip-offset, iend); From 997fb064a64f76a1cfb1d1d5f8383c79a6c7b911 Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 4 Feb 2016 13:01:56 +0100 Subject: [PATCH 033/113] anchor --- lib/zstd_opt.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index ff4a59e66..4623b6598 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -198,13 +198,13 @@ MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, size_t litLength, cons } -#define SET_PRICE(pos, mlen, offset, litlen, price) \ +#define SET_PRICE(pos, mlen_, offset_, litlen_, price_) \ { \ while (last_pos < pos) { opt[last_pos+1].price = 1<<30; last_pos++; } \ - opt[pos].mlen = mlen; \ - opt[pos].off = offset; \ - opt[pos].litlen = litlen; \ - opt[pos].price = price; \ + opt[pos].mlen = mlen_; \ + opt[pos].off = offset_; \ + opt[pos].litlen = litlen_; \ + opt[pos].price = price_; \ ZSTD_LOG_PARSER("%d: SET price[%d/%d]=%d litlen=%d len=%d off=%d\n", (int)(inr-base), (int)pos, (int)last_pos, opt[pos].price, opt[pos].litlen, opt[pos].mlen, opt[pos].off); \ } @@ -734,7 +734,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } else { - price = ZSTD_getLiteralPrice(seqStorePtr, llen + litlen, inr-(llen+litlen)) - ZSTD_LIT_COST(llen); + price = ZSTD_getLiteralPrice(seqStorePtr, llen + litlen, anchor) - ZSTD_LIT_COST(llen); ZSTD_LOG_TRY_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, cur, litlen, llen); } } @@ -930,7 +930,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } else { - price = ZSTD_getLiteralPrice(seqStorePtr, llen + litlen, ip+i-(llen + litlen)) - ZSTD_LIT_COST(llen); + price = ZSTD_getLiteralPrice(seqStorePtr, llen + litlen, anchor) - ZSTD_LIT_COST(llen); ZSTD_LOG_TRY_PRICE("%d: TRY10 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, i, litlen, llen); } } From eb72f5992a25c4509e9f9c0554b6299e6420939a Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 4 Feb 2016 14:55:23 +0100 Subject: [PATCH 034/113] i != litlen --- lib/zstd_opt.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 4623b6598..11dd3a364 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -657,10 +657,9 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, do { - litlen = 1; price = ZSTD_getPrice(seqStorePtr, llen + 1, anchor, 0, mlen - MINMATCH) - ZSTD_LIT_COST(llen + 1); if (mlen + 1 > last_pos || price < opt[mlen + 1].price) - SET_PRICE(mlen + 1, mlen, 0, litlen, price); + SET_PRICE(mlen + 1, mlen, 0, 1, price); mlen--; } while (mlen >= MINMATCH); @@ -680,10 +679,9 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); if (!last_pos && !match_num) { ip++; continue; } - // opt[0].rep = opt[1].rep = rep_1; - // opt[0].mlen = opt[1].mlen = 1; + opt[0].rep = rep_1; - opt[0].rep2 = rep_1; + opt[0].rep2 = rep_2; opt[0].mlen = 1; // opt[0].price = ZSTD_getLiteralPrice(seqStorePtr, 1, ip); @@ -727,7 +725,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, { litlen = opt[cur-1].litlen + 1; - if (cur != litlen) + if (cur > litlen) { price = opt[cur - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-litlen); ZSTD_LOG_TRY_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); @@ -742,7 +740,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, { litlen = 1; price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1); - ZSTD_LOG_TRY_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)(inr-base), price, cur, litlen, ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1)); + ZSTD_LOG_TRY_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)(inr-base), price, cur, litlen, (int)ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1)); } mlen = 1; @@ -752,6 +750,8 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (cur > last_pos || price <= opt[cur].price) // || ((price == opt[cur].price) && (opt[cur-1].mlen == 1) && (cur != litlen))) SET_PRICE(cur, mlen, best_mlen, litlen, price); + if (cur == last_pos) break; + if (opt[cur].mlen > 1) { mlen = opt[cur].mlen; @@ -784,7 +784,6 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_LOG_PARSER("%d: COPYREP3 cur=%d rep=%d rep2=%d\n", (int)(inr-base), cur, opt[cur].rep, opt[cur].rep2); } - if (cur == last_pos) break; ZSTD_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); @@ -810,7 +809,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, { litlen = opt[cur].litlen; - if (cur != litlen) + if (cur > litlen) { price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, inr-litlen, 0, mlen - MINMATCH); ZSTD_LOG_TRY_PRICE("%d: TRY5 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); @@ -883,7 +882,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, { litlen = opt[cur2].litlen; - if (cur2 != litlen) + if (cur2 > litlen) price = opt[cur2 - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, ip+cur2-litlen, matches[i].off, mlen - MINMATCH); else price = ZSTD_getPrice(seqStorePtr, llen + litlen, anchor, matches[i].off, mlen - MINMATCH) - ZSTD_LIT_COST(llen); @@ -901,8 +900,8 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, { SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); - opt[cur2 + mlen].rep = matches[i].off; // update reps - opt[cur2 + mlen].rep2 = opt[cur2].rep; +// opt[cur2 + mlen].rep = matches[i].off; // update reps +// opt[cur2 + mlen].rep2 = opt[cur2].rep; } mlen++; @@ -923,7 +922,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, { litlen = opt[i-1].litlen + 1; - if (i != litlen) + if (i > litlen) { price = opt[i - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, ip+i-litlen); ZSTD_LOG_TRY_PRICE("%d: TRY9 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), i - litlen, opt[i - litlen].price, price, i, litlen); @@ -946,7 +945,8 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_LOG_TRY_PRICE("%d: TRY12 price=%d opt[%d].price=%d\n", (int)(inr-base), price, i + mlen, opt[i + mlen].price); SET_PRICE(i, mlen, best_mlen, litlen, price); - opt[i].rep = opt[i-1].rep; // copy reps + // opt[i].rep = opt[i-1].rep; // copy reps + // opt[i].rep2 = opt[i-1].rep2; // copy reps ZSTD_LOG_PARSER("%d: INVALIDATE pred=%d price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(inr-base), cur-cur_min, i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); } From d1ff7bf89a4dc961a7f99cb803fa462b8bf33f3d Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 4 Feb 2016 14:57:11 +0100 Subject: [PATCH 035/113] cur_rep --- lib/zstd_opt.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 11dd3a364..5f03a5d66 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -999,21 +999,13 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set mlen = opt[cur].mlen; if (mlen == 1) { ip++; cur++; continue; } offset = opt[cur].off; - int cur_rep = opt[cur].rep; cur += mlen; size_t litLength = ip - anchor; - ZSTD_LOG_ENCODE("%d/%d: BEFORE_ENCODE literals=%d mlen=%d off=%d rep1=%d rep2=%d cur_rep=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2, cur_rep); + ZSTD_LOG_ENCODE("%d/%d: BEFORE_ENCODE literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); -#if 1 - if (rep_1 != cur_rep) - { - printf("%d: ERROR rep_1=%d rep_2=%d cur_rep=%d\n", (int)(ip - base), (int)rep_1, (int)rep_2, cur_rep); - exit(0); - } -#endif if (offset) { @@ -1043,7 +1035,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set if (ml2 < mlen && ml2 < MINMATCH) { - printf("%d: ERROR iend=%d mlen=%d offset=%d cur_rep=%d ml2=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset, (int)cur_rep, (int)ml2); + printf("%d: ERROR iend=%d mlen=%d offset=%d ml2=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset, (int)ml2); exit(0); } From 158677c16a072e58e403f697823f35b1e47a4cfa Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 4 Feb 2016 15:25:37 +0100 Subject: [PATCH 036/113] new copy rep --- lib/zstd_opt.c | 57 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 5f03a5d66..bc2b80ab1 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -679,12 +679,10 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); if (!last_pos && !match_num) { ip++; continue; } - - opt[0].rep = rep_1; - opt[0].rep2 = rep_2; + opt[0].rep = rep_2; + opt[0].rep2 = rep_1; opt[0].mlen = 1; - // opt[0].price = ZSTD_getLiteralPrice(seqStorePtr, 1, ip); - + if (match_num && matches[match_num-1].len > sufficient_len) { best_mlen = matches[match_num-1].len; @@ -742,7 +740,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1); ZSTD_LOG_TRY_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)(inr-base), price, cur, litlen, (int)ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1)); } - + mlen = 1; best_mlen = 0; ZSTD_LOG_TRY_PRICE("%d: TRY4 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur, opt[cur].price); @@ -752,6 +750,31 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (cur == last_pos) break; + +#if 1 + mlen = opt[cur].mlen; + + if (opt[cur-mlen].off) + { + opt[cur].rep2 = opt[cur-mlen].rep; + opt[cur].rep = opt[cur-mlen].off; + } + else + { + if (opt[cur-mlen].litlen == 0) + { + opt[cur].rep2 = opt[cur-mlen].rep; + opt[cur].rep = opt[cur-mlen].rep2; + } + else + { + opt[cur].rep2 = opt[cur-mlen].rep2; + opt[cur].rep = opt[cur-mlen].rep; + } + } + +#else + if (opt[cur].mlen > 1) { mlen = opt[cur].mlen; @@ -783,18 +806,18 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, opt[cur].rep2 = opt[cur-1].rep; // copy rep ZSTD_LOG_PARSER("%d: COPYREP3 cur=%d rep=%d rep2=%d\n", (int)(inr-base), cur, opt[cur].rep, opt[cur].rep2); } - +#endif ZSTD_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); // check rep // best_mlen = 0; - mlen = ZSTD_count(inr, inr - opt[cur].rep2, iend); + mlen = ZSTD_count(inr, inr - opt[cur].rep, iend); if (mlen >= MINMATCH && mlen > best_mlen) { - ZSTD_LOG_PARSER("%d: try REP rep=%d mlen=%d\n", (int)(inr-base), opt[cur].rep2, mlen); - ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep2, cur, opt[cur].off); + ZSTD_LOG_PARSER("%d: try REP rep=%d mlen=%d\n", (int)(inr-base), opt[cur].rep, mlen); + ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep, cur, opt[cur].off); if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) { @@ -824,7 +847,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, { litlen = 0; price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, 0, mlen - MINMATCH); - ZSTD_LOG_TRY_PRICE("%d: TRY7 price=%d cur=%d litlen=0 getprice=%d\n", (int)(inr-base), price, cur, ZSTD_getPrice(seqStorePtr, 0, NULL, 0, mlen - MINMATCH)); + ZSTD_LOG_TRY_PRICE("%d: TRY7 price=%d cur=%d litlen=0 getprice=%d\n", (int)(inr-base), price, cur, (int)ZSTD_getPrice(seqStorePtr, 0, NULL, 0, mlen - MINMATCH)); } best_mlen = mlen; @@ -893,15 +916,15 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, price = opt[cur2].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[i].off, mlen - MINMATCH); } - ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); - ZSTD_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); + // ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); + // ZSTD_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); if (cur2 + mlen > last_pos || (price < opt[cur2 + mlen].price)) { SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); -// opt[cur2 + mlen].rep = matches[i].off; // update reps -// opt[cur2 + mlen].rep2 = opt[cur2].rep; + // opt[cur2 + mlen].rep = matches[i].off; // update reps + // opt[cur2 + mlen].rep2 = opt[cur2].rep; } mlen++; @@ -947,7 +970,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, // opt[i].rep = opt[i-1].rep; // copy reps // opt[i].rep2 = opt[i-1].rep2; // copy reps - + ZSTD_LOG_PARSER("%d: INVALIDATE pred=%d price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(inr-base), cur-cur_min, i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); } @@ -1003,10 +1026,8 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set size_t litLength = ip - anchor; - ZSTD_LOG_ENCODE("%d/%d: BEFORE_ENCODE literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); - if (offset) { rep_2 = rep_1; From c9483f09827dd74dff3eed7a8b3684634c91f243 Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 4 Feb 2016 15:28:55 +0100 Subject: [PATCH 037/113] clean code --- lib/zstd_opt.c | 42 ++++-------------------------------------- 1 file changed, 4 insertions(+), 38 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index bc2b80ab1..d99cdda8f 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -751,13 +751,14 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (cur == last_pos) break; -#if 1 + mlen = opt[cur].mlen; if (opt[cur-mlen].off) { opt[cur].rep2 = opt[cur-mlen].rep; opt[cur].rep = opt[cur-mlen].off; + ZSTD_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); } else { @@ -773,47 +774,12 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } } -#else - - if (opt[cur].mlen > 1) - { - mlen = opt[cur].mlen; - best_off = opt[cur].off; - if (best_off < 1) - { - if (opt[cur].off == 0 && opt[cur].litlen==0) - { - opt[cur].rep = opt[cur-mlen].rep2; - opt[cur].rep2 = opt[cur-mlen].rep; - } - else - { - opt[cur].rep = opt[cur-mlen].rep; - opt[cur].rep2 = opt[cur-mlen].rep2; - } - ZSTD_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); - } - else - { - opt[cur].rep = best_off; - opt[cur].rep2 = opt[cur-mlen].rep; - ZSTD_LOG_PARSER("%d: COPYREP2 cur=%d offset=%d rep=%d rep2=%d litlen=%d\n", (int)(inr-base), cur, 0, opt[cur].rep, opt[cur].rep2, litlen); - } - } - else - { - opt[cur].rep = opt[cur-1].rep; // copy rep - opt[cur].rep2 = opt[cur-1].rep; // copy rep - ZSTD_LOG_PARSER("%d: COPYREP3 cur=%d rep=%d rep2=%d\n", (int)(inr-base), cur, opt[cur].rep, opt[cur].rep2); - } -#endif - ZSTD_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); - // check rep + // best_mlen = 0; - mlen = ZSTD_count(inr, inr - opt[cur].rep, iend); + mlen = ZSTD_count(inr, inr - opt[cur].rep, iend); // check rep if (mlen >= MINMATCH && mlen > best_mlen) { ZSTD_LOG_PARSER("%d: try REP rep=%d mlen=%d\n", (int)(inr-base), opt[cur].rep, mlen); From 40dd4739e3a1b500e21289e54ae63581e9cb1386 Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 4 Feb 2016 15:52:35 +0100 Subject: [PATCH 038/113] removed llen --- lib/zstd_opt.c | 82 ++++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index d99cdda8f..25275945a 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -33,8 +33,6 @@ typedef struct #define ZSTD_OPT_NUM (1<<12) -#define ZSTD_LIT_COST(len) 0 //(((len)<<3)) - const int tab32[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, @@ -619,7 +617,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_match_t matches[ZSTD_OPT_NUM+1]; const uint8_t *inr; int cur, cur2, cur_min, skip_num = 0; - int llen, litlen, price, match_num, last_pos; + int litlen, price, match_num, last_pos; const int sufficient_len = 128; //ctx->params.sufficientLength; const int faster_get_matches = (ctx->params.strategy == ZSTD_opt); @@ -639,10 +637,10 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, int best_off=0; memset(opt, 0, sizeof(ZSTD_optimal_t)); last_pos = 0; - llen = ip - anchor; inr = ip; - - + opt[0].litlen = ip - anchor; + // opt[0].price = ZSTD_getLiteralPrice(seqStorePtr, opt[0].litlen, anchor); + /* check repCode */ if (MEM_read32(ip+1) == MEM_read32(ip+1 - rep_1)) { /* repcode : we take it */ @@ -657,9 +655,10 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, do { - price = ZSTD_getPrice(seqStorePtr, llen + 1, anchor, 0, mlen - MINMATCH) - ZSTD_LIT_COST(llen + 1); + litlen = opt[0].litlen + 1; + price = ZSTD_getPrice(seqStorePtr, litlen, anchor, 0, mlen - MINMATCH); if (mlen + 1 > last_pos || price < opt[mlen + 1].price) - SET_PRICE(mlen + 1, mlen, 0, 1, price); + SET_PRICE(mlen + 1, mlen, 0, litlen, price); mlen--; } while (mlen >= MINMATCH); @@ -679,8 +678,14 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); if (!last_pos && !match_num) { ip++; continue; } - opt[0].rep = rep_2; - opt[0].rep2 = rep_1; + if (opt[0].litlen) { + opt[0].rep = rep_1; + opt[0].rep2 = rep_2; + } + else { + opt[0].rep = rep_2; + opt[0].rep2 = rep_1; + } opt[0].mlen = 1; if (match_num && matches[match_num-1].len > sufficient_len) @@ -700,8 +705,8 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(ip-base), matches[i].len, matches[i].off, (int)best_mlen, (int)last_pos); while (mlen <= best_mlen) { - litlen = 0; - price = ZSTD_getPrice(seqStorePtr, llen + litlen, anchor, matches[i].off, mlen - MINMATCH) - ZSTD_LIT_COST(llen); + litlen = opt[0].litlen; + price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[i].off, mlen - MINMATCH); if (mlen > last_pos || price < opt[mlen].price) SET_PRICE(mlen, mlen, matches[i].off, litlen, price); mlen++; @@ -722,17 +727,13 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (opt[cur-1].mlen == 1) { litlen = opt[cur-1].litlen + 1; - if (cur > litlen) { price = opt[cur - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-litlen); ZSTD_LOG_TRY_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); } else - { - price = ZSTD_getLiteralPrice(seqStorePtr, llen + litlen, anchor) - ZSTD_LIT_COST(llen); - ZSTD_LOG_TRY_PRICE("%d: TRY2 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, cur, litlen, llen); - } + price = ZSTD_getLiteralPrice(seqStorePtr, litlen, anchor); } else { @@ -740,7 +741,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1); ZSTD_LOG_TRY_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)(inr-base), price, cur, litlen, (int)ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1)); } - + mlen = 1; best_mlen = 0; ZSTD_LOG_TRY_PRICE("%d: TRY4 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur, opt[cur].price); @@ -804,10 +805,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_LOG_TRY_PRICE("%d: TRY5 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); } else - { - price = ZSTD_getPrice(seqStorePtr, llen + litlen, anchor, 0, mlen - MINMATCH) - ZSTD_LIT_COST(llen); - ZSTD_LOG_TRY_PRICE("%d: TRY6 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, cur, litlen, llen); - } + price = ZSTD_getPrice(seqStorePtr, litlen, anchor, 0, mlen - MINMATCH); } else { @@ -870,11 +868,10 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (opt[cur2].mlen == 1) { litlen = opt[cur2].litlen; - if (cur2 > litlen) price = opt[cur2 - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, ip+cur2-litlen, matches[i].off, mlen - MINMATCH); else - price = ZSTD_getPrice(seqStorePtr, llen + litlen, anchor, matches[i].off, mlen - MINMATCH) - ZSTD_LIT_COST(llen); + price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[i].off, mlen - MINMATCH); } else { @@ -882,15 +879,15 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, price = opt[cur2].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[i].off, mlen - MINMATCH); } - // ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); - // ZSTD_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); + ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); + ZSTD_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); if (cur2 + mlen > last_pos || (price < opt[cur2 + mlen].price)) { SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); - // opt[cur2 + mlen].rep = matches[i].off; // update reps - // opt[cur2 + mlen].rep2 = opt[cur2].rep; + // opt[cur2 + mlen].rep = matches[i].off; // update reps + // opt[cur2 + mlen].rep2 = opt[cur2].rep; } mlen++; @@ -910,17 +907,14 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (opt[i-1].mlen == 1) { litlen = opt[i-1].litlen + 1; - + if (i > litlen) { price = opt[i - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, ip+i-litlen); - ZSTD_LOG_TRY_PRICE("%d: TRY9 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), i - litlen, opt[i - litlen].price, price, i, litlen); + ZSTD_LOG_TRY_PRICE("%d: TRY9 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), i - litlen, opt[i - litlen].price, price, i, litlen); } else - { - price = ZSTD_getLiteralPrice(seqStorePtr, llen + litlen, anchor) - ZSTD_LIT_COST(llen); - ZSTD_LOG_TRY_PRICE("%d: TRY10 price=%d cur=%d litlen=%d llen=%d\n", (int)(inr-base), price, i, litlen, llen); - } + price = ZSTD_getLiteralPrice(seqStorePtr, litlen, anchor); } else { @@ -934,9 +928,9 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_LOG_TRY_PRICE("%d: TRY12 price=%d opt[%d].price=%d\n", (int)(inr-base), price, i + mlen, opt[i + mlen].price); SET_PRICE(i, mlen, best_mlen, litlen, price); - // opt[i].rep = opt[i-1].rep; // copy reps - // opt[i].rep2 = opt[i-1].rep2; // copy reps - + // opt[i].rep = opt[i-1].rep; // copy reps + // opt[i].rep2 = opt[i-1].rep2; // copy reps + ZSTD_LOG_PARSER("%d: INVALIDATE pred=%d price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(inr-base), cur-cur_min, i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); } @@ -988,12 +982,22 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set mlen = opt[cur].mlen; if (mlen == 1) { ip++; cur++; continue; } offset = opt[cur].off; + int cur_rep = opt[cur].rep; cur += mlen; size_t litLength = ip - anchor; - ZSTD_LOG_ENCODE("%d/%d: BEFORE_ENCODE literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); + ZSTD_LOG_ENCODE("%d/%d: BEFORE_ENCODE literals=%d mlen=%d off=%d rep1=%d rep2=%d cur_rep=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2, cur_rep); + +#if 0 + if (rep_1 != cur_rep) + { + printf("%d: ERROR rep_1=%d rep_2=%d cur_rep=%d\n", (int)(ip - base), (int)rep_1, (int)rep_2, cur_rep); + exit(0); + } +#endif + if (offset) { rep_2 = rep_1; @@ -1022,7 +1026,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set if (ml2 < mlen && ml2 < MINMATCH) { - printf("%d: ERROR iend=%d mlen=%d offset=%d ml2=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset, (int)ml2); + printf("%d: ERROR iend=%d mlen=%d offset=%d cur_rep=%d ml2=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset, (int)cur_rep, (int)ml2); exit(0); } From baff8d6c1f9615f716e3f59bbd2669210d554eb6 Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 4 Feb 2016 16:02:05 +0100 Subject: [PATCH 039/113] gitignore --- .gitignore | 4 +++- lib/zstd_opt.c | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 8b7aa0c3c..a31ffdc79 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,6 @@ ipch/ _codelite _zstdbench -lib/zstd_opt_LZ5.c \ No newline at end of file +lib/zstd_opt_LZ5.c +lib/zstd_opt_llen.c +lib/zstd_opt_nollen.c \ No newline at end of file diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 25275945a..976c98774 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -150,7 +150,7 @@ FORCE_INLINE size_t ZSTD_getPrice(seqStore_t* seqStorePtr, size_t litLength, con size_t match_cost_old = ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); size_t match_cost = ZSTD_getMatchPriceReal(seqStorePtr, offset, matchLength); // printf("old=%d new=%d\n", (int)match_cost2, (int)match_cost); - return lit_cost + match_cost_old; + return lit_cost + match_cost; #else size_t lit_cost = (litLength<<3); size_t match_cost = ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); @@ -653,9 +653,9 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, goto _storeSequence; } + litlen = opt[0].litlen + 1; do { - litlen = opt[0].litlen + 1; price = ZSTD_getPrice(seqStorePtr, litlen, anchor, 0, mlen - MINMATCH); if (mlen + 1 > last_pos || price < opt[mlen + 1].price) SET_PRICE(mlen + 1, mlen, 0, litlen, price); @@ -703,9 +703,9 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, mlen = (i>0) ? matches[i-1].len+1 : best_mlen; best_mlen = (matches[i].len < ZSTD_OPT_NUM) ? matches[i].len : ZSTD_OPT_NUM; ZSTD_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(ip-base), matches[i].len, matches[i].off, (int)best_mlen, (int)last_pos); + litlen = opt[0].litlen; while (mlen <= best_mlen) { - litlen = opt[0].litlen; price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[i].off, mlen - MINMATCH); if (mlen > last_pos || price < opt[mlen].price) SET_PRICE(mlen, mlen, matches[i].off, litlen, price); From 59c914625894236c27031858f262528bf8cfbc7a Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 4 Feb 2016 17:48:33 +0100 Subject: [PATCH 040/113] 40099096 --- lib/zstd_opt.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 976c98774..edae7c5ad 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -678,14 +678,8 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); if (!last_pos && !match_num) { ip++; continue; } - if (opt[0].litlen) { - opt[0].rep = rep_1; - opt[0].rep2 = rep_2; - } - else { - opt[0].rep = rep_2; - opt[0].rep2 = rep_1; - } + opt[0].rep = rep_1; + opt[0].rep2 = rep_2; opt[0].mlen = 1; if (match_num && matches[match_num-1].len > sufficient_len) @@ -763,7 +757,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } else { - if (opt[cur-mlen].litlen == 0) + if (cur!=mlen && opt[cur-mlen].litlen == 0) { opt[cur].rep2 = opt[cur-mlen].rep; opt[cur].rep = opt[cur-mlen].rep2; @@ -780,10 +774,21 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, // best_mlen = 0; +#if 1 + if (!opt[cur].off && opt[cur].mlen != 1) { + mlen = ZSTD_count(inr, inr - opt[cur].rep2, iend); // check rep2 + ZSTD_LOG_PARSER("%d: try REP2 rep2=%d mlen=%d\n", (int)(inr-base), opt[cur].rep2, mlen); + } + else { + mlen = ZSTD_count(inr, inr - opt[cur].rep, iend); // check rep + ZSTD_LOG_PARSER("%d: try REP1 rep=%d mlen=%d\n", (int)(inr-base), opt[cur].rep, mlen); + } +#else mlen = ZSTD_count(inr, inr - opt[cur].rep, iend); // check rep +#endif + if (mlen >= MINMATCH && mlen > best_mlen) { - ZSTD_LOG_PARSER("%d: try REP rep=%d mlen=%d\n", (int)(inr-base), opt[cur].rep, mlen); ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep, cur, opt[cur].off); if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) @@ -879,8 +884,8 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, price = opt[cur2].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[i].off, mlen - MINMATCH); } - ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); - ZSTD_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); + // ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); + // ZSTD_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); if (cur2 + mlen > last_pos || (price < opt[cur2 + mlen].price)) { @@ -997,7 +1002,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set exit(0); } #endif - + if (offset) { rep_2 = rep_1; From 6f071867457aeab7958df4612db53035b7ecae72 Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 4 Feb 2016 17:57:50 +0100 Subject: [PATCH 041/113] clean code --- lib/zstd_opt.c | 68 +++----------------------------------------------- 1 file changed, 3 insertions(+), 65 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index edae7c5ad..7b7e10a04 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -138,18 +138,13 @@ FORCE_INLINE size_t ZSTD_getMatchPriceReal(seqStore_t* seqStorePtr, size_t offse return freq; } -// zstd v0.5 beta level 23 3.05 MB/s 448 MB/s 40868360 38.98 -// zstd v0.5 beta level 24 2.90 MB/s 472 MB/s 40392170 38.52 -// zstd v0.5 beta level 23 1.10 MB/s ERROR 40584556 38.70 -// zstd v0.5 beta level 24 0.87 MB/s ERROR 40103205 38.25 FORCE_INLINE size_t ZSTD_getPrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offset, size_t matchLength) { #if 1 size_t lit_cost = ZSTD_getLiteralPriceReal(seqStorePtr, litLength, literals); - size_t match_cost_old = ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); + // size_t match_cost_old = ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); size_t match_cost = ZSTD_getMatchPriceReal(seqStorePtr, offset, matchLength); - // printf("old=%d new=%d\n", (int)match_cost2, (int)match_cost); return lit_cost + match_cost; #else size_t lit_cost = (litLength<<3); @@ -898,53 +893,6 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, mlen++; } } - - if (cur_min < cur) - { - for (int i=cur_min-1; i<=last_pos; i++) - { - ZSTD_LOG_PARSER("%d: BEFORE price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); - } - - for (int i=cur_min+1; i<=last_pos; i++) - if (opt[i].price < (1<<30) && (opt[i].off) < 1 && i - opt[i].mlen > cur_min) // invalidate reps - { - if (opt[i-1].mlen == 1) - { - litlen = opt[i-1].litlen + 1; - - if (i > litlen) - { - price = opt[i - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, ip+i-litlen); - ZSTD_LOG_TRY_PRICE("%d: TRY9 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), i - litlen, opt[i - litlen].price, price, i, litlen); - } - else - price = ZSTD_getLiteralPrice(seqStorePtr, litlen, anchor); - } - else - { - litlen = 1; - price = opt[i - 1].price + ZSTD_getLiteralPrice(seqStorePtr, 1, ip+i-1); - ZSTD_LOG_TRY_PRICE("%d: TRY11 price=%d cur=%d litlen=%d\n", (int)(inr-base), price, i, litlen); - } - - mlen = 1; - best_mlen = 0; - ZSTD_LOG_TRY_PRICE("%d: TRY12 price=%d opt[%d].price=%d\n", (int)(inr-base), price, i + mlen, opt[i + mlen].price); - SET_PRICE(i, mlen, best_mlen, litlen, price); - - // opt[i].rep = opt[i-1].rep; // copy reps - // opt[i].rep2 = opt[i-1].rep2; // copy reps - - ZSTD_LOG_PARSER("%d: INVALIDATE pred=%d price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(inr-base), cur-cur_min, i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); - } - - for (int i=cur_min-1; i<=last_pos; i++) - { - ZSTD_LOG_PARSER("%d: AFTER price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep); - } - - } } // for (skip_num = 0, cur = 1; cur <= last_pos; cur++) @@ -987,21 +935,11 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set mlen = opt[cur].mlen; if (mlen == 1) { ip++; cur++; continue; } offset = opt[cur].off; - int cur_rep = opt[cur].rep; cur += mlen; size_t litLength = ip - anchor; - - ZSTD_LOG_ENCODE("%d/%d: BEFORE_ENCODE literals=%d mlen=%d off=%d rep1=%d rep2=%d cur_rep=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2, cur_rep); - -#if 0 - if (rep_1 != cur_rep) - { - printf("%d: ERROR rep_1=%d rep_2=%d cur_rep=%d\n", (int)(ip - base), (int)rep_1, (int)rep_2, cur_rep); - exit(0); - } -#endif + ZSTD_LOG_ENCODE("%d/%d: BEFORE_ENCODE literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); if (offset) { @@ -1031,7 +969,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set if (ml2 < mlen && ml2 < MINMATCH) { - printf("%d: ERROR iend=%d mlen=%d offset=%d cur_rep=%d ml2=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset, (int)cur_rep, (int)ml2); + printf("%d: ERROR iend=%d mlen=%d offset=%d ml2=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset, (int)ml2); exit(0); } From 08f500ca1062f63c3f39007be9799890a6fb2ace Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 4 Feb 2016 20:53:54 +0100 Subject: [PATCH 042/113] cur_min --- lib/zstd_opt.c | 89 +++++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 7b7e10a04..0510e945e 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -3,19 +3,19 @@ typedef struct { - int off; - int len; - int back; + int off; + int len; + int back; } ZSTD_match_t; typedef struct { - int price; - int off; - int mlen; - int litlen; - int rep; - int rep2; + int price; + int off; + int mlen; + int litlen; + int rep; + int rep2; } ZSTD_optimal_t; #if 1 @@ -330,15 +330,15 @@ size_t ZSTD_BtGetAllMatches ( FORCE_INLINE size_t ZSTD_BtGetAllMatches_selectMLS ( ZSTD_CCtx* zc, /* Index table will be updated */ - const BYTE* ip, const BYTE* const iLimit, + const BYTE* ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, size_t minml) { switch(matchLengthSearch) { default : - case 4 : return ZSTD_BtGetAllMatches(zc, ip, iLimit, maxNbAttempts, 4, matches, minml); - case 5 : return ZSTD_BtGetAllMatches(zc, ip, iLimit, maxNbAttempts, 5, matches, minml); - case 6 : return ZSTD_BtGetAllMatches(zc, ip, iLimit, maxNbAttempts, 6, matches, minml); + case 4 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minml); + case 5 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minml); + case 6 : return ZSTD_BtGetAllMatches(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minml); } } @@ -346,7 +346,7 @@ FORCE_INLINE size_t ZSTD_BtGetAllMatches_selectMLS ( FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ size_t ZSTD_HcGetAllMatches_generic ( ZSTD_CCtx* zc, /* Index table will be updated */ - const BYTE* const ip, const BYTE* const iLimit, + const BYTE* const ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, const U32 maxNbAttempts, const U32 mls, const U32 extDict, ZSTD_match_t* matches, size_t minml) { U32* const chainTable = zc->contentTable; @@ -371,15 +371,25 @@ size_t ZSTD_HcGetAllMatches_generic ( while ((matchIndex>lowLimit) && (nbAttempts)) { size_t currentMl=0; + size_t back = 0; nbAttempts--; if ((!extDict) || matchIndex >= dictLimit) { match = base + matchIndex; if (match[minml] == ip[minml]) /* potentially better */ - currentMl = ZSTD_count(ip, match, iLimit); + currentMl = ZSTD_count(ip, match, iHighLimit); +#if 0 + const BYTE* start = ip; + size_t offset = current - matchIndex; + while ((start > iLowLimit) && (start > base+offset) && (start[-1] == start[-1-offset])) start--; + back = ip - start; +#else + while ((match-back > base) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; +#endif + currentMl += back; } else { match = dictBase + matchIndex; if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */ - currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH; + currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iHighLimit, dictEnd, prefixStart) + MINMATCH; } /* save best solution */ @@ -387,10 +397,10 @@ size_t ZSTD_HcGetAllMatches_generic ( minml = currentMl; matches[mnum].off = current - matchIndex; matches[mnum].len = currentMl; - matches[mnum].back = 0; + matches[mnum].back = back; mnum++; if (currentMl > ZSTD_OPT_NUM) break; - if (ip+currentMl == iLimit) break; /* best possible, and avoid read overflow*/ + if (ip+currentMl == iHighLimit) break; /* best possible, and avoid read overflow*/ } if (matchIndex <= minChain) break; @@ -403,15 +413,15 @@ size_t ZSTD_HcGetAllMatches_generic ( FORCE_INLINE size_t ZSTD_HcGetAllMatches_selectMLS ( ZSTD_CCtx* zc, - const BYTE* ip, const BYTE* const iLimit, + const BYTE* ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, size_t minml) { switch(matchLengthSearch) { default : - case 4 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLimit, maxNbAttempts, 4, 0, matches, minml); - case 5 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLimit, maxNbAttempts, 5, 0, matches, minml); - case 6 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLimit, maxNbAttempts, 6, 0, matches, minml); + case 4 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLowLimit, iHighLimit, maxNbAttempts, 4, 0, matches, minml); + case 5 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLowLimit, iHighLimit, maxNbAttempts, 5, 0, matches, minml); + case 6 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLowLimit, iHighLimit, maxNbAttempts, 6, 0, matches, minml); } } @@ -604,14 +614,14 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, const U32 maxSearches = 1 << ctx->params.searchLog; const U32 mls = ctx->params.searchLength; - typedef size_t (*getAllMatches_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, + typedef size_t (*getAllMatches_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLowLimit, const BYTE* iHighLimit, U32 maxNbAttempts, U32 matchLengthSearch, ZSTD_match_t* matches, size_t minml); getAllMatches_f getAllMatches = searchMethod ? ZSTD_BtGetAllMatches_selectMLS : ZSTD_HcGetAllMatches_selectMLS; ZSTD_optimal_t opt[ZSTD_OPT_NUM+4]; ZSTD_match_t matches[ZSTD_OPT_NUM+1]; const uint8_t *inr; - int cur, cur2, cur_min, skip_num = 0; + int cur, cur2, skip_num = 0; int litlen, price, match_num, last_pos; const int sufficient_len = 128; //ctx->params.sufficientLength; @@ -667,7 +677,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, else { /* first search (depth 0) */ - match_num = getAllMatches(ctx, ip, iend, maxSearches, mls, matches, best_mlen); + match_num = getAllMatches(ctx, ip, ip, iend, maxSearches, mls, matches, best_mlen); } ZSTD_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); @@ -731,12 +741,10 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_LOG_TRY_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)(inr-base), price, cur, litlen, (int)ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1)); } - mlen = 1; - best_mlen = 0; ZSTD_LOG_TRY_PRICE("%d: TRY4 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur, opt[cur].price); if (cur > last_pos || price <= opt[cur].price) // || ((price == opt[cur].price) && (opt[cur-1].mlen == 1) && (cur != litlen))) - SET_PRICE(cur, mlen, best_mlen, litlen, price); + SET_PRICE(cur, 1, 0, litlen, price); if (cur == last_pos) break; @@ -756,11 +764,13 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, { opt[cur].rep2 = opt[cur-mlen].rep; opt[cur].rep = opt[cur-mlen].rep2; + ZSTD_LOG_PARSER("%d: COPYREP2 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); } else { opt[cur].rep2 = opt[cur-mlen].rep2; opt[cur].rep = opt[cur-mlen].rep; + ZSTD_LOG_PARSER("%d: COPYREP3 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); } } @@ -768,7 +778,6 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, - // best_mlen = 0; #if 1 if (!opt[cur].off && opt[cur].mlen != 1) { mlen = ZSTD_count(inr, inr - opt[cur].rep2, iend); // check rep2 @@ -782,7 +791,9 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, mlen = ZSTD_count(inr, inr - opt[cur].rep, iend); // check rep #endif - if (mlen >= MINMATCH && mlen > best_mlen) + best_mlen = 0; + + if (mlen >= MINMATCH) { ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep, cur, opt[cur].off); @@ -839,7 +850,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; - match_num = getAllMatches(ctx, inr, iend, maxSearches, mls, matches, best_mlen); + match_num = getAllMatches(ctx, inr, ip, iend, maxSearches, mls, matches, best_mlen); ZSTD_LOG_PARSER("%d: ZSTD_GetAllMatches match_num=%d\n", (int)(inr-base), match_num); @@ -852,8 +863,6 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, goto _storeSequence; } - cur_min = cur; - // set prices using matches at position = cur for (int i = 0; i < match_num; i++) { @@ -879,13 +888,12 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, price = opt[cur2].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[i].off, mlen - MINMATCH); } - // ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); - // ZSTD_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); + ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); + ZSTD_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); if (cur2 + mlen > last_pos || (price < opt[cur2 + mlen].price)) { SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); - // opt[cur2 + mlen].rep = matches[i].off; // update reps // opt[cur2 + mlen].rep2 = opt[cur2].rep; } @@ -904,15 +912,16 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, /* store sequence */ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set for (int i = 1; i <= last_pos; i++) - ZSTD_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); + ZSTD_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d back=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2, opt[i].back); ZSTD_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-base+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); opt[0].mlen = 1; size_t offset; - + while (cur >= 0) { mlen = opt[cur].mlen; + ZSTD_LOG_PARSER("%d: cur=%d mlen=%d\n", (int)(ip-base), cur, mlen); offset = opt[cur].off; opt[cur].mlen = best_mlen; opt[cur].off = best_off; @@ -923,7 +932,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set for (int i = 0; i <= last_pos;) { - ZSTD_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); + ZSTD_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); i += opt[i].mlen; } @@ -931,7 +940,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set while (cur < last_pos) { - ZSTD_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); + ZSTD_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); mlen = opt[cur].mlen; if (mlen == 1) { ip++; cur++; continue; } offset = opt[cur].off; From 4fa4098628ecdc3ef4495e2c2332cba5a8e5ccdf Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 4 Feb 2016 21:16:07 +0100 Subject: [PATCH 043/113] last match will start at a minimum distance of 8 from oend --- lib/zstd_decompress.c | 2 +- lib/zstd_opt.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index c9946f5fc..31d1fd07c 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -708,7 +708,7 @@ FORCE_INLINE size_t ZSTD_execSequence(BYTE* op, const BYTE* match = oLitEnd - sequence.offset; /* check */ - // if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of 8 from oend */ + if (oLitEnd > oend_8) return ERROR(dstSize_tooSmall); /* last match must start at a minimum distance of 8 from oend */ if (oMatchEnd > oend) return ERROR(dstSize_tooSmall); /* overwrite beyond dst buffer */ if (litEnd > litLimit_8) return ERROR(corruption_detected); /* risk read beyond lit buffer */ diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 0510e945e..8221bd250 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -383,7 +383,7 @@ size_t ZSTD_HcGetAllMatches_generic ( while ((start > iLowLimit) && (start > base+offset) && (start[-1] == start[-1-offset])) start--; back = ip - start; #else - while ((match-back > base) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; + // while ((match-back > base) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; #endif currentMl += back; } else { @@ -654,7 +654,6 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)(ip-base), (int)rep_1, (int)mlen); if (depth==0 || mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) { ip+=1; best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; - opt[0].rep = rep_1; goto _storeSequence; } @@ -748,7 +747,8 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (cur == last_pos) break; - + if (inr > ilimit) + continue; mlen = opt[cur].mlen; @@ -912,7 +912,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, /* store sequence */ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set for (int i = 1; i <= last_pos; i++) - ZSTD_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d back=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2, opt[i].back); + ZSTD_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); ZSTD_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-base+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); opt[0].mlen = 1; From b3df71e5386a2301619981231e5b16e5d5c4a8bc Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 4 Feb 2016 21:45:26 +0100 Subject: [PATCH 044/113] code cleaning --- lib/zstd_opt.c | 118 +++++++++++-------------------------------------- 1 file changed, 27 insertions(+), 91 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 8221bd250..e87374b02 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -31,7 +31,7 @@ typedef struct #define ZSTD_LOG_TRY_PRICE(fmt, args...) ;//printf(fmt, ##args) #define ZSTD_OPT_NUM (1<<12) - +#define ZSTD_FREQ_THRESHOLD (256) const int tab32[32] = { 0, 9, 1, 10, 13, 21, 2, 29, @@ -52,19 +52,15 @@ int log2_32 (uint32_t value) FORCE_INLINE size_t ZSTD_getLiteralPriceReal(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals) { - size_t freq; size_t price = 0; - size_t litBits, litLenBits; - // printf("litSum=%d litLengthSum=%d matchLengthSum=%d offCodeSum=%d\n", seqStorePtr->litSum, seqStorePtr->litLengthSum, seqStorePtr->matchLengthSum, seqStorePtr->offCodeSum); - /* literals */ - litBits = 0; if (litLength > 0) { + /* literals */ for (int i=litLength-1; i>=0; i--) -// litBits += -log2((double)seqStorePtr->litFreq[literals[i]]/(double)seqStorePtr->litSum); - litBits += log2_32(seqStorePtr->litSum) - log2_32(seqStorePtr->litFreq[literals[i]]); + price += log2_32(seqStorePtr->litSum) - log2_32(seqStorePtr->litFreq[literals[i]]); /* literal Length */ + size_t freq; if (litLength >= MaxLL) { freq = seqStorePtr->litLengthFreq[MaxLL]; if (litLength<255 + MaxLL) { @@ -73,53 +69,37 @@ FORCE_INLINE size_t ZSTD_getLiteralPriceReal(seqStore_t* seqStorePtr, size_t lit price += 8; if (litLength < (1<<15)) price += 16; else price += 24; } } - else freq = seqStorePtr->litLengthFreq[litLength]; -// litLenBits = -log2((double)freq/(double)seqStorePtr->litLengthSum); - litLenBits = log2_32(seqStorePtr->litLengthSum) - log2_32(freq); + else + freq = seqStorePtr->litLengthFreq[litLength]; + price += log2_32(seqStorePtr->litLengthSum) - log2_32(freq); } - else litLenBits = 0; -// freq = round(1.0f*(litBits + litLenBits + price)); - freq = litBits + litLenBits + price; -// printf("litLength=%d litBits=%.02f litLenBits=%.02f dumpsPrice=%d sum=%d\n", (int)litLength, litBits, litLenBits, (int)price, (int)freq); - - // printf("old=%d new=%d\n", (int)((litLength<<3)+1), (int)freq/8); - if (freq <= 0) freq = 1; - return freq; + return price + (price <= 0); } FORCE_INLINE size_t ZSTD_getLiteralPrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals) { -#if 1 - return ZSTD_getLiteralPriceReal(seqStorePtr, litLength, literals); -#else - size_t lit_cost = 1 + (litLength<<3); - return lit_cost; -#endif + if (seqStorePtr->litSum > ZSTD_FREQ_THRESHOLD) + return ZSTD_getLiteralPriceReal(seqStorePtr, litLength, literals); + + return 1 + (litLength<<3); } FORCE_INLINE size_t ZSTD_getMatchPriceReal(seqStore_t* seqStorePtr, size_t offset, size_t matchLength) { - size_t freq; - size_t price = 0; - size_t offCodeBits, matchBits; - // printf("litSum=%d litLengthSum=%d matchLengthSum=%d offCodeSum=%d\n", seqStorePtr->litSum, seqStorePtr->litLengthSum, seqStorePtr->matchLengthSum, seqStorePtr->offCodeSum); - /* match offset */ BYTE offCode = (BYTE)ZSTD_highbit(offset) + 1; if (offset==0) offCode = 0; - // offCodeBits = -log2((double)seqStorePtr->offCodeFreq[offCode]/(double)seqStorePtr->offCodeSum); - offCodeBits = log2_32(seqStorePtr->offCodeSum) - log2_32(seqStorePtr->offCodeFreq[offCode]); - // printf("offCodeBits=%.02f matchBits=%.02f dumpsPrice=%d sum=%d\n", offCodeBits, matchBits, (int)price, (int)freq); - - offCodeBits += offCode; + size_t price = log2_32(seqStorePtr->offCodeSum) - log2_32(seqStorePtr->offCodeFreq[offCode]); + price += offCode; /* match Length */ + size_t freq; if (matchLength >= MaxML) { freq = seqStorePtr->matchLengthFreq[MaxML]; if (matchLength < 255+MaxML) { @@ -129,28 +109,18 @@ FORCE_INLINE size_t ZSTD_getMatchPriceReal(seqStore_t* seqStorePtr, size_t offse if (matchLength < (1<<15)) price += 16; else price += 24; } } else freq = seqStorePtr->matchLengthFreq[matchLength]; -// matchBits = -log2((double)freq/(double)seqStorePtr->matchLengthSum); - matchBits = log2_32(seqStorePtr->matchLengthSum) - log2_32(freq); + price += log2_32(seqStorePtr->matchLengthSum) - log2_32(freq); -// freq = round(1.0f*(offCodeBits + matchBits + price)); - freq = offCodeBits + matchBits + price; -// printf("offCodeBits=%.02f matchBits=%.02f dumpsPrice=%d sum=%d\n", offCodeBits, matchBits, (int)price, (int)freq); - return freq; + return price; } FORCE_INLINE size_t ZSTD_getPrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offset, size_t matchLength) { -#if 1 - size_t lit_cost = ZSTD_getLiteralPriceReal(seqStorePtr, litLength, literals); - // size_t match_cost_old = ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); - size_t match_cost = ZSTD_getMatchPriceReal(seqStorePtr, offset, matchLength); - return lit_cost + match_cost; -#else - size_t lit_cost = (litLength<<3); - size_t match_cost = ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); - return lit_cost + match_cost; -#endif + if (seqStorePtr->litSum > ZSTD_FREQ_THRESHOLD) + return ZSTD_getLiteralPriceReal(seqStorePtr, litLength, literals) + ZSTD_getMatchPriceReal(seqStorePtr, offset, matchLength); + + return (litLength<<3) + ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); } @@ -232,11 +202,7 @@ size_t ZSTD_insertBtAndGetAllMatches ( U32 dummy32; /* to be nullified at the end */ size_t mnum = 0; -#if 1 bestLength = 0; -#else - bestLength--; -#endif hashTable[h] = current; /* Update Hash Table */ while (nbCompares-- && (matchIndex > windowLow)) { @@ -255,7 +221,6 @@ size_t ZSTD_insertBtAndGetAllMatches ( match = base + matchIndex; /* to prepare for next usage of match[matchLength] */ } -#if 1 if (matchLength > bestLength) { if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; @@ -272,24 +237,6 @@ size_t ZSTD_insertBtAndGetAllMatches ( if (ip+matchLength == iend) /* equal : no way to know if inf or sup */ break; /* drop, to guarantee consistency (miss a little bit of compression) */ } -#else - if (matchLength > matchEndIdx - matchIndex) - matchEndIdx = matchIndex + (U32)matchLength; - - if (matchLength > bestLength) { - bestLength = matchLength; - matches[mnum].off = current - matchIndex; - matches[mnum].len = matchLength; - matches[mnum].back = 0; - mnum++; - - if (matchLength > ZSTD_OPT_NUM) break; - } - - if (ip+matchLength == iend) /* equal : no way to know if inf or sup */ - break; /* drop, to guarantee consistency (miss a little bit of compression) */ -#endif - if (match[matchLength] < ip[matchLength]) { /* match is smaller than current */ @@ -447,7 +394,7 @@ void print_hex_text(uint8_t* buf, int bufsize, int endline) /* ******************************* -* Optimal parser OLD +* Old parser *********************************/ FORCE_INLINE void ZSTD_compressBlock_opt2_generic(ZSTD_CCtx* ctx, @@ -644,8 +591,8 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, last_pos = 0; inr = ip; opt[0].litlen = ip - anchor; - // opt[0].price = ZSTD_getLiteralPrice(seqStorePtr, opt[0].litlen, anchor); - + + /* check repCode */ if (MEM_read32(ip+1) == MEM_read32(ip+1 - rep_1)) { /* repcode : we take it */ @@ -674,10 +621,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (faster_get_matches && last_pos) match_num = 0; else - { - /* first search (depth 0) */ - match_num = getAllMatches(ctx, ip, ip, iend, maxSearches, mls, matches, best_mlen); - } + match_num = getAllMatches(ctx, ip, ip, iend, maxSearches, mls, matches, best_mlen); /* first search (depth 0) */ ZSTD_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); if (!last_pos && !match_num) { ip++; continue; } @@ -747,7 +691,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (cur == last_pos) break; - if (inr > ilimit) + if (inr > ilimit) // last match must start at a minimum distance of 8 from oend continue; mlen = opt[cur].mlen; @@ -778,7 +722,6 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, -#if 1 if (!opt[cur].off && opt[cur].mlen != 1) { mlen = ZSTD_count(inr, inr - opt[cur].rep2, iend); // check rep2 ZSTD_LOG_PARSER("%d: try REP2 rep2=%d mlen=%d\n", (int)(inr-base), opt[cur].rep2, mlen); @@ -787,9 +730,6 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, mlen = ZSTD_count(inr, inr - opt[cur].rep, iend); // check rep ZSTD_LOG_PARSER("%d: try REP1 rep=%d mlen=%d\n", (int)(inr-base), opt[cur].rep, mlen); } -#else - mlen = ZSTD_count(inr, inr - opt[cur].rep, iend); // check rep -#endif best_mlen = 0; @@ -892,11 +832,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); if (cur2 + mlen > last_pos || (price < opt[cur2 + mlen].price)) - { SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); - // opt[cur2 + mlen].rep = matches[i].off; // update reps - // opt[cur2 + mlen].rep2 = opt[cur2].rep; - } mlen++; } @@ -969,7 +905,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set // printf("orig="); print_hex_text(ip, mlen, 0); // printf("match="); print_hex_text(ip-offset, mlen, 0); -#if 1 +#if 0 // for debugging size_t ml2; if (offset) ml2 = ZSTD_count(ip, ip-offset, iend); From 34608aaa292d2f8be357835537491e75aa72a370 Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 4 Feb 2016 22:18:02 +0100 Subject: [PATCH 045/113] ssize_t --- lib/zstd_opt.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index e87374b02..f5e8c3b52 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -74,7 +74,7 @@ FORCE_INLINE size_t ZSTD_getLiteralPriceReal(seqStore_t* seqStorePtr, size_t lit price += log2_32(seqStorePtr->litLengthSum) - log2_32(freq); } - return price + (price <= 0); + return price + (price == 0); } @@ -568,11 +568,10 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_optimal_t opt[ZSTD_OPT_NUM+4]; ZSTD_match_t matches[ZSTD_OPT_NUM+1]; const uint8_t *inr; - int cur, cur2, skip_num = 0; - int litlen, price, match_num, last_pos; + ssize_t skip_num = 0, cur, cur2, last_pos, litlen, price, match_num; - const int sufficient_len = 128; //ctx->params.sufficientLength; - const int faster_get_matches = (ctx->params.strategy == ZSTD_opt); + const ssize_t sufficient_len = 128; //ctx->params.sufficientLength; + const size_t faster_get_matches = (ctx->params.strategy == ZSTD_opt); // printf("orig_file="); print_hex_text(ip, srcSize, 0); @@ -584,9 +583,9 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, /* Match Loop */ while (ip < ilimit) { - int mlen=0; - int best_mlen=0; - int best_off=0; + ssize_t mlen=0; + ssize_t best_mlen=0; + ssize_t best_off=0; memset(opt, 0, sizeof(ZSTD_optimal_t)); last_pos = 0; inr = ip; From 55a444764b786b6c547eff58f1c68ad3fc260f2c Mon Sep 17 00:00:00 2001 From: inikep Date: Thu, 4 Feb 2016 22:22:47 +0100 Subject: [PATCH 046/113] sufficient_len = 32 --- lib/zstd_opt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index f5e8c3b52..5e7c42d8f 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -570,7 +570,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, const uint8_t *inr; ssize_t skip_num = 0, cur, cur2, last_pos, litlen, price, match_num; - const ssize_t sufficient_len = 128; //ctx->params.sufficientLength; + const ssize_t sufficient_len = 32; //ctx->params.sufficientLength; const size_t faster_get_matches = (ctx->params.strategy == ZSTD_opt); From f967753bc2dfd5ae7ee386d8c9c7412c0f23d1c3 Mon Sep 17 00:00:00 2001 From: inikep Date: Fri, 5 Feb 2016 09:07:22 +0100 Subject: [PATCH 047/113] ssize_t -> int --- lib/zstd_internal.h | 2 +- lib/zstd_opt.c | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/zstd_internal.h b/lib/zstd_internal.h index ca291bd53..a0280b58c 100644 --- a/lib/zstd_internal.h +++ b/lib/zstd_internal.h @@ -79,7 +79,7 @@ static const size_t ZSTD_frameHeaderSize_min = 5; #define IS_RAW 2 #define IS_RLE 3 -#define MINMATCH 4 +#define MINMATCH 3 #define REPCODE_STARTVALUE 1 #define Litbits 8 diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 5e7c42d8f..83a8d8cda 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -18,6 +18,9 @@ typedef struct int rep2; } ZSTD_optimal_t; + +#define ZSTD_OPT_DEBUG 0 // 5 = check encoded sequences + #if 1 #define ZSTD_LOG_PARSER(fmt, args...) ;// printf(fmt, ##args) #define ZSTD_LOG_PRICE(fmt, args...) ;//printf(fmt, ##args) @@ -568,9 +571,9 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_optimal_t opt[ZSTD_OPT_NUM+4]; ZSTD_match_t matches[ZSTD_OPT_NUM+1]; const uint8_t *inr; - ssize_t skip_num = 0, cur, cur2, last_pos, litlen, price, match_num; + int skip_num = 0, cur, cur2, last_pos, litlen, price, match_num; - const ssize_t sufficient_len = 32; //ctx->params.sufficientLength; + const int sufficient_len = 32; //ctx->params.sufficientLength; const size_t faster_get_matches = (ctx->params.strategy == ZSTD_opt); @@ -583,9 +586,9 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, /* Match Loop */ while (ip < ilimit) { - ssize_t mlen=0; - ssize_t best_mlen=0; - ssize_t best_off=0; + int mlen=0; + int best_mlen=0; + int best_off=0; memset(opt, 0, sizeof(ZSTD_optimal_t)); last_pos = 0; inr = ip; @@ -904,7 +907,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set // printf("orig="); print_hex_text(ip, mlen, 0); // printf("match="); print_hex_text(ip-offset, mlen, 0); -#if 0 // for debugging +#if ZSTD_OPT_DEBUG >= 5 size_t ml2; if (offset) ml2 = ZSTD_count(ip, ip-offset, iend); From 3379c5df3668591d71220c664de24272d9f56ced Mon Sep 17 00:00:00 2001 From: inikep Date: Fri, 5 Feb 2016 09:21:20 +0100 Subject: [PATCH 048/113] ZSTD_OPT_DEBUG --- lib/zstd_compress.c | 4 +++- lib/zstd_internal.h | 2 +- lib/zstd_opt.c | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index f2daf0f68..350159520 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -2442,7 +2442,9 @@ ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint) int tableID = ((srcSizeHint-1) <= 256 KB) + ((srcSizeHint-1) <= 128 KB) + ((srcSizeHint-1) <= 16 KB); /* intentional underflow for srcSizeHint == 0 */ if (compressionLevel<=0) compressionLevel = 1; if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL; -tableID=0; +#if ZSTD_OPT_DEBUG >= 1 + tableID=0; +#endif result = ZSTD_defaultParameters[tableID][compressionLevel]; result.srcSize = srcSizeHint; return result; diff --git a/lib/zstd_internal.h b/lib/zstd_internal.h index a0280b58c..ca291bd53 100644 --- a/lib/zstd_internal.h +++ b/lib/zstd_internal.h @@ -79,7 +79,7 @@ static const size_t ZSTD_frameHeaderSize_min = 5; #define IS_RAW 2 #define IS_RLE 3 -#define MINMATCH 3 +#define MINMATCH 4 #define REPCODE_STARTVALUE 1 #define Litbits 8 diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 83a8d8cda..7d37a1f79 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -19,7 +19,7 @@ typedef struct } ZSTD_optimal_t; -#define ZSTD_OPT_DEBUG 0 // 5 = check encoded sequences +#define ZSTD_OPT_DEBUG 0 // 1 = tableID=0; 5 = check encoded sequences #if 1 #define ZSTD_LOG_PARSER(fmt, args...) ;// printf(fmt, ##args) From 5b0749715d5822abf0b138fc7fa18ce3bd8c92fe Mon Sep 17 00:00:00 2001 From: inikep Date: Fri, 5 Feb 2016 19:25:40 +0100 Subject: [PATCH 049/113] backward match extension --- lib/zstd_opt.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 7d37a1f79..82f46456e 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -36,6 +36,8 @@ typedef struct #define ZSTD_OPT_NUM (1<<12) #define ZSTD_FREQ_THRESHOLD (256) + +// log2_32 is from http://stackoverflow.com/questions/11376288/fast-computing-of-log2-for-64-bit-integers const int tab32[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, @@ -327,15 +329,11 @@ size_t ZSTD_HcGetAllMatches_generic ( match = base + matchIndex; if (match[minml] == ip[minml]) /* potentially better */ currentMl = ZSTD_count(ip, match, iHighLimit); -#if 0 - const BYTE* start = ip; - size_t offset = current - matchIndex; - while ((start > iLowLimit) && (start > base+offset) && (start[-1] == start[-1-offset])) start--; - back = ip - start; -#else - // while ((match-back > base) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; -#endif - currentMl += back; + + if (currentMl > 0) { + while ((match-back > base) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ + currentMl += back; + } } else { match = dictBase + matchIndex; if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */ @@ -805,6 +803,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, goto _storeSequence; } + // set prices using matches at position = cur for (int i = 0; i < match_num; i++) { @@ -908,7 +907,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set // printf("match="); print_hex_text(ip-offset, mlen, 0); #if ZSTD_OPT_DEBUG >= 5 - size_t ml2; + int ml2; if (offset) ml2 = ZSTD_count(ip, ip-offset, iend); else From f2fee4c3166a83c647800b231686007d642e839f Mon Sep 17 00:00:00 2001 From: inikep Date: Fri, 5 Feb 2016 19:45:25 +0100 Subject: [PATCH 050/113] added params.sufficientLength --- lib/zstd_compress.c | 206 +++++++++++++++++++++--------------------- lib/zstd_decompress.c | 5 - lib/zstd_opt.c | 2 +- lib/zstd_static.h | 1 + 4 files changed, 104 insertions(+), 110 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 1da652f1c..d5682811f 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -100,7 +100,6 @@ typedef struct { static void ZSTD_resetFreqs(seqStore_t* ssPtr) { - // printf("litSum=%d litLengthSum=%d matchLengthSum=%d offCodeSum=%d\n", ssPtr->litSum, ssPtr->litLengthSum, ssPtr->matchLengthSum, ssPtr->offCodeSum); ssPtr->matchLengthSum = (1<litLengthSum = (1<litSum = (1<seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (1<seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (1<seqStore.XXX = zc->seqStore.offCodeFreq + (1<seqStore); zc->hbSize = 0; zc->stage = 0; @@ -2319,116 +2317,116 @@ unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { /* "default" */ - /* W, C, H, S, L, strat */ - { 0, 18, 12, 12, 1, 4, ZSTD_fast }, /* level 0 - never used */ - { 0, 19, 13, 14, 1, 7, ZSTD_fast }, /* level 1 */ - { 0, 19, 15, 16, 1, 6, ZSTD_fast }, /* level 2 */ - { 0, 20, 18, 20, 1, 6, ZSTD_fast }, /* level 3 */ - { 0, 21, 19, 21, 1, 6, ZSTD_fast }, /* level 4 */ - { 0, 20, 14, 18, 3, 5, ZSTD_greedy }, /* level 5 */ - { 0, 20, 18, 19, 3, 5, ZSTD_greedy }, /* level 6 */ - { 0, 21, 17, 20, 3, 5, ZSTD_lazy }, /* level 7 */ - { 0, 21, 19, 20, 3, 5, ZSTD_lazy }, /* level 8 */ - { 0, 21, 20, 20, 3, 5, ZSTD_lazy2 }, /* level 9 */ - { 0, 21, 19, 21, 4, 5, ZSTD_lazy2 }, /* level 10 */ - { 0, 22, 20, 22, 4, 5, ZSTD_lazy2 }, /* level 11 */ // 42498419 - { 0, 22, 20, 22, 5, 5, ZSTD_lazy2 }, /* level 12 */ - { 0, 22, 21, 22, 5, 5, ZSTD_lazy2 }, /* level 13 */ - { 0, 22, 22, 23, 5, 5, ZSTD_lazy2 }, /* level 14 */ - { 0, 23, 23, 23, 5, 5, ZSTD_lazy2 }, /* level 15 */ - { 0, 23, 21, 22, 5, 5, ZSTD_btlazy2 }, /* level 16 */ // 42113689 - { 0, 23, 24, 23, 4, 5, ZSTD_btlazy2 }, /* level 17 */ - { 0, 25, 24, 23, 5, 5, ZSTD_btlazy2 }, /* level 18 */ - { 0, 25, 26, 23, 5, 5, ZSTD_btlazy2 }, /* level 19 */ - { 0, 26, 27, 25, 9, 5, ZSTD_btlazy2 }, /* level 20 */ - { 0, 22, 20, 22, 4, 4, ZSTD_lazy2 }, /* level 11 + L=4 */ // 41902762 lazy1=42087013 norep1=42911693 - { 0, 23, 21, 22, 5, 4, ZSTD_btlazy2 }, /* level 16 + L=4 */ // 41233150 btlazy1=41560211 norep1=42322286 - { 0, 23, 21, 22, 5, 4, ZSTD_opt }, /* level 23 */ - { 0, 23, 21, 22, 5, 4, ZSTD_opt_bt }, /* level 24 */ + /* SL, W, C, H, S, L, strat */ + { 0, 0, 18, 12, 12, 1, 4, ZSTD_fast }, /* level 0 - never used */ + { 0, 0, 19, 13, 14, 1, 7, ZSTD_fast }, /* level 1 */ + { 0, 0, 19, 15, 16, 1, 6, ZSTD_fast }, /* level 2 */ + { 0, 0, 20, 18, 20, 1, 6, ZSTD_fast }, /* level 3 */ + { 0, 0, 21, 19, 21, 1, 6, ZSTD_fast }, /* level 4 */ + { 0, 0, 20, 14, 18, 3, 5, ZSTD_greedy }, /* level 5 */ + { 0, 0, 20, 18, 19, 3, 5, ZSTD_greedy }, /* level 6 */ + { 0, 0, 21, 17, 20, 3, 5, ZSTD_lazy }, /* level 7 */ + { 0, 0, 21, 19, 20, 3, 5, ZSTD_lazy }, /* level 8 */ + { 0, 0, 21, 20, 20, 3, 5, ZSTD_lazy2 }, /* level 9 */ + { 0, 0, 21, 19, 21, 4, 5, ZSTD_lazy2 }, /* level 10 */ + { 0, 0, 22, 20, 22, 4, 5, ZSTD_lazy2 }, /* level 11 */ // 42498419 + { 0, 0, 22, 20, 22, 5, 5, ZSTD_lazy2 }, /* level 12 */ + { 0, 0, 22, 21, 22, 5, 5, ZSTD_lazy2 }, /* level 13 */ + { 0, 0, 22, 22, 23, 5, 5, ZSTD_lazy2 }, /* level 14 */ + { 0, 0, 23, 23, 23, 5, 5, ZSTD_lazy2 }, /* level 15 */ + { 0, 0, 23, 21, 22, 5, 5, ZSTD_btlazy2 }, /* level 16 */ // 42113689 + { 0, 0, 23, 24, 23, 4, 5, ZSTD_btlazy2 }, /* level 17 */ + { 0, 0, 25, 24, 23, 5, 5, ZSTD_btlazy2 }, /* level 18 */ + { 0, 0, 25, 26, 23, 5, 5, ZSTD_btlazy2 }, /* level 19 */ + { 0, 0, 26, 27, 25, 9, 5, ZSTD_btlazy2 }, /* level 20 */ + { 0, 0, 22, 20, 22, 4, 4, ZSTD_lazy2 }, /* level 21 = 11 + L=4 */ // 41902762 lazy1=42087013 norep1=42911693 + { 0, 0, 23, 21, 22, 5, 4, ZSTD_btlazy2 }, /* level 22 = 16 + L=4 */ // 41233150 btlazy1=41560211 norep1=42322286 + { 0, 32, 23, 21, 22, 5, 4, ZSTD_opt }, /* level 23 */ + { 0, 32, 23, 21, 22, 5, 4, ZSTD_opt_bt }, /* level 24 */ }, { /* for srcSize <= 256 KB */ - /* W, C, H, S, L, strat */ - { 0, 18, 13, 14, 1, 7, ZSTD_fast }, /* level 0 - never used */ - { 0, 18, 14, 15, 1, 6, ZSTD_fast }, /* level 1 */ - { 0, 18, 14, 15, 1, 5, ZSTD_fast }, /* level 2 */ - { 0, 18, 12, 15, 3, 4, ZSTD_greedy }, /* level 3 */ - { 0, 18, 13, 15, 4, 4, ZSTD_greedy }, /* level 4 */ - { 0, 18, 14, 15, 5, 4, ZSTD_greedy }, /* level 5 */ - { 0, 18, 13, 15, 4, 4, ZSTD_lazy }, /* level 6 */ - { 0, 18, 14, 16, 5, 4, ZSTD_lazy }, /* level 7 */ - { 0, 18, 15, 16, 6, 4, ZSTD_lazy }, /* level 8 */ - { 0, 18, 15, 15, 7, 4, ZSTD_lazy }, /* level 9 */ - { 0, 18, 16, 16, 7, 4, ZSTD_lazy }, /* level 10 */ - { 0, 18, 16, 16, 8, 4, ZSTD_lazy }, /* level 11 */ - { 0, 18, 17, 16, 8, 4, ZSTD_lazy }, /* level 12 */ - { 0, 18, 17, 16, 9, 4, ZSTD_lazy }, /* level 13 */ - { 0, 18, 18, 16, 9, 4, ZSTD_lazy }, /* level 14 */ - { 0, 18, 17, 17, 9, 4, ZSTD_lazy2 }, /* level 15 */ - { 0, 18, 18, 18, 9, 4, ZSTD_lazy2 }, /* level 16 */ - { 0, 18, 18, 18, 10, 4, ZSTD_lazy2 }, /* level 17 */ - { 0, 18, 18, 18, 11, 4, ZSTD_lazy2 }, /* level 18 */ - { 0, 18, 18, 18, 12, 4, ZSTD_lazy2 }, /* level 19 */ - { 0, 18, 18, 18, 13, 4, ZSTD_lazy2 }, /* level 20 */ - { 0, 18, 18, 18, 10, 4, ZSTD_lazy2 }, /* level 17 */ - { 0, 18, 18, 18, 11, 4, ZSTD_lazy2 }, /* level 18 */ - { 0, 18, 18, 18, 12, 4, ZSTD_lazy2 }, /* level 19 */ - { 0, 18, 18, 18, 13, 4, ZSTD_lazy2 }, /* level 20 */ + /* SL, W, C, H, S, L, strat */ + { 0, 0, 18, 13, 14, 1, 7, ZSTD_fast }, /* level 0 - never used */ + { 0, 0, 18, 14, 15, 1, 6, ZSTD_fast }, /* level 1 */ + { 0, 0, 18, 14, 15, 1, 5, ZSTD_fast }, /* level 2 */ + { 0, 0, 18, 12, 15, 3, 4, ZSTD_greedy }, /* level 3 */ + { 0, 0, 18, 13, 15, 4, 4, ZSTD_greedy }, /* level 4 */ + { 0, 0, 18, 14, 15, 5, 4, ZSTD_greedy }, /* level 5 */ + { 0, 0, 18, 13, 15, 4, 4, ZSTD_lazy }, /* level 6 */ + { 0, 0, 18, 14, 16, 5, 4, ZSTD_lazy }, /* level 7 */ + { 0, 0, 18, 15, 16, 6, 4, ZSTD_lazy }, /* level 8 */ + { 0, 0, 18, 15, 15, 7, 4, ZSTD_lazy }, /* level 9 */ + { 0, 0, 18, 16, 16, 7, 4, ZSTD_lazy }, /* level 10 */ + { 0, 0, 18, 16, 16, 8, 4, ZSTD_lazy }, /* level 11 */ + { 0, 0, 18, 17, 16, 8, 4, ZSTD_lazy }, /* level 12 */ + { 0, 0, 18, 17, 16, 9, 4, ZSTD_lazy }, /* level 13 */ + { 0, 0, 18, 18, 16, 9, 4, ZSTD_lazy }, /* level 14 */ + { 0, 0, 18, 17, 17, 9, 4, ZSTD_lazy2 }, /* level 15 */ + { 0, 0, 18, 18, 18, 9, 4, ZSTD_lazy2 }, /* level 16 */ + { 0, 0, 18, 18, 18, 10, 4, ZSTD_lazy2 }, /* level 17 */ + { 0, 0, 18, 18, 18, 11, 4, ZSTD_lazy2 }, /* level 18 */ + { 0, 0, 18, 18, 18, 12, 4, ZSTD_lazy2 }, /* level 19 */ + { 0, 0, 18, 18, 18, 13, 4, ZSTD_lazy2 }, /* level 20 */ + { 0, 0, 18, 18, 18, 10, 4, ZSTD_lazy2 }, /* level ??? */ + { 0, 0, 18, 18, 18, 11, 4, ZSTD_lazy2 }, /* level ??? */ + { 0, 0, 18, 18, 18, 12, 4, ZSTD_lazy2 }, /* level ??? */ + { 0, 0, 18, 18, 18, 13, 4, ZSTD_lazy2 }, /* level ??? */ }, { /* for srcSize <= 128 KB */ /* W, C, H, S, L, strat */ - { 0, 17, 12, 12, 1, 4, ZSTD_fast }, /* level 0 - never used */ - { 0, 17, 12, 13, 1, 6, ZSTD_fast }, /* level 1 */ - { 0, 17, 14, 16, 1, 5, ZSTD_fast }, /* level 2 */ - { 0, 17, 15, 17, 1, 5, ZSTD_fast }, /* level 3 */ - { 0, 17, 13, 15, 2, 4, ZSTD_greedy }, /* level 4 */ - { 0, 17, 15, 17, 3, 4, ZSTD_greedy }, /* level 5 */ - { 0, 17, 14, 17, 3, 4, ZSTD_lazy }, /* level 6 */ - { 0, 17, 16, 17, 4, 4, ZSTD_lazy }, /* level 7 */ - { 0, 17, 16, 17, 4, 4, ZSTD_lazy2 }, /* level 8 */ - { 0, 17, 17, 16, 5, 4, ZSTD_lazy2 }, /* level 9 */ - { 0, 17, 17, 16, 6, 4, ZSTD_lazy2 }, /* level 10 */ - { 0, 17, 17, 16, 7, 4, ZSTD_lazy2 }, /* level 11 */ - { 0, 17, 17, 16, 8, 4, ZSTD_lazy2 }, /* level 12 */ - { 0, 17, 18, 16, 4, 4, ZSTD_btlazy2 }, /* level 13 */ - { 0, 17, 18, 16, 5, 4, ZSTD_btlazy2 }, /* level 14 */ - { 0, 17, 18, 16, 6, 4, ZSTD_btlazy2 }, /* level 15 */ - { 0, 17, 18, 16, 7, 4, ZSTD_btlazy2 }, /* level 16 */ - { 0, 17, 18, 16, 8, 4, ZSTD_btlazy2 }, /* level 17 */ - { 0, 17, 18, 16, 9, 4, ZSTD_btlazy2 }, /* level 18 */ - { 0, 17, 18, 16, 10, 4, ZSTD_btlazy2 }, /* level 19 */ - { 0, 17, 18, 18, 12, 4, ZSTD_btlazy2 }, /* level 20 */ - { 0, 17, 18, 16, 8, 4, ZSTD_btlazy2 }, /* level 17 */ - { 0, 17, 18, 16, 9, 4, ZSTD_btlazy2 }, /* level 18 */ - { 0, 17, 18, 16, 10, 4, ZSTD_btlazy2 }, /* level 19 */ - { 0, 17, 18, 18, 12, 4, ZSTD_btlazy2 }, /* level 20 */ + { 0, 0, 17, 12, 12, 1, 4, ZSTD_fast }, /* level 0 - never used */ + { 0, 0, 17, 12, 13, 1, 6, ZSTD_fast }, /* level 1 */ + { 0, 0, 17, 14, 16, 1, 5, ZSTD_fast }, /* level 2 */ + { 0, 0, 17, 15, 17, 1, 5, ZSTD_fast }, /* level 3 */ + { 0, 0, 17, 13, 15, 2, 4, ZSTD_greedy }, /* level 4 */ + { 0, 0, 17, 15, 17, 3, 4, ZSTD_greedy }, /* level 5 */ + { 0, 0, 17, 14, 17, 3, 4, ZSTD_lazy }, /* level 6 */ + { 0, 0, 17, 16, 17, 4, 4, ZSTD_lazy }, /* level 7 */ + { 0, 0, 17, 16, 17, 4, 4, ZSTD_lazy2 }, /* level 8 */ + { 0, 0, 17, 17, 16, 5, 4, ZSTD_lazy2 }, /* level 9 */ + { 0, 0, 17, 17, 16, 6, 4, ZSTD_lazy2 }, /* level 10 */ + { 0, 0, 17, 17, 16, 7, 4, ZSTD_lazy2 }, /* level 11 */ + { 0, 0, 17, 17, 16, 8, 4, ZSTD_lazy2 }, /* level 12 */ + { 0, 0, 17, 18, 16, 4, 4, ZSTD_btlazy2 }, /* level 13 */ + { 0, 0, 17, 18, 16, 5, 4, ZSTD_btlazy2 }, /* level 14 */ + { 0, 0, 17, 18, 16, 6, 4, ZSTD_btlazy2 }, /* level 15 */ + { 0, 0, 17, 18, 16, 7, 4, ZSTD_btlazy2 }, /* level 16 */ + { 0, 0, 17, 18, 16, 8, 4, ZSTD_btlazy2 }, /* level 17 */ + { 0, 0, 17, 18, 16, 9, 4, ZSTD_btlazy2 }, /* level 18 */ + { 0, 0, 17, 18, 16, 10, 4, ZSTD_btlazy2 }, /* level 19 */ + { 0, 0, 17, 18, 18, 12, 4, ZSTD_btlazy2 }, /* level 20 */ + { 0, 0, 17, 18, 16, 8, 4, ZSTD_btlazy2 }, /* level ??? */ + { 0, 0, 17, 18, 16, 9, 4, ZSTD_btlazy2 }, /* level ??? */ + { 0, 0, 17, 18, 16, 10, 4, ZSTD_btlazy2 }, /* level ??? */ + { 0, 0, 17, 18, 18, 12, 4, ZSTD_btlazy2 }, /* level ??? */ }, { /* for srcSize <= 16 KB */ /* W, C, H, S, L, strat */ - { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */ - { 0, 14, 14, 14, 1, 4, ZSTD_fast }, /* level 1 */ - { 0, 14, 14, 16, 1, 4, ZSTD_fast }, /* level 2 */ - { 0, 14, 14, 14, 5, 4, ZSTD_greedy }, /* level 3 */ - { 0, 14, 14, 14, 8, 4, ZSTD_greedy }, /* level 4 */ - { 0, 14, 11, 14, 6, 4, ZSTD_lazy }, /* level 5 */ - { 0, 14, 14, 13, 6, 5, ZSTD_lazy }, /* level 6 */ - { 0, 14, 14, 14, 7, 6, ZSTD_lazy }, /* level 7 */ - { 0, 14, 14, 14, 8, 4, ZSTD_lazy }, /* level 8 */ - { 0, 14, 14, 15, 9, 4, ZSTD_lazy }, /* level 9 */ - { 0, 14, 14, 15, 10, 4, ZSTD_lazy }, /* level 10 */ - { 0, 14, 15, 15, 6, 4, ZSTD_btlazy2 }, /* level 11 */ - { 0, 14, 15, 15, 7, 4, ZSTD_btlazy2 }, /* level 12 */ - { 0, 14, 15, 15, 8, 4, ZSTD_btlazy2 }, /* level 13 */ - { 0, 14, 15, 15, 9, 4, ZSTD_btlazy2 }, /* level 14 */ - { 0, 14, 15, 15, 10, 4, ZSTD_btlazy2 }, /* level 15 */ - { 0, 14, 15, 15, 11, 4, ZSTD_btlazy2 }, /* level 16 */ - { 0, 14, 15, 15, 12, 4, ZSTD_btlazy2 }, /* level 17 */ - { 0, 14, 15, 15, 13, 4, ZSTD_btlazy2 }, /* level 18 */ - { 0, 14, 15, 15, 14, 4, ZSTD_btlazy2 }, /* level 19 */ - { 0, 14, 15, 15, 15, 4, ZSTD_btlazy2 }, /* level 20 */ - { 0, 14, 15, 15, 12, 4, ZSTD_btlazy2 }, /* level 17 */ - { 0, 14, 15, 15, 13, 4, ZSTD_btlazy2 }, /* level 18 */ - { 0, 14, 15, 15, 14, 4, ZSTD_btlazy2 }, /* level 19 */ - { 0, 14, 15, 15, 15, 4, ZSTD_btlazy2 }, /* level 20 */ + { 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */ + { 0, 0, 14, 14, 14, 1, 4, ZSTD_fast }, /* level 1 */ + { 0, 0, 14, 14, 16, 1, 4, ZSTD_fast }, /* level 2 */ + { 0, 0, 14, 14, 14, 5, 4, ZSTD_greedy }, /* level 3 */ + { 0, 0, 14, 14, 14, 8, 4, ZSTD_greedy }, /* level 4 */ + { 0, 0, 14, 11, 14, 6, 4, ZSTD_lazy }, /* level 5 */ + { 0, 0, 14, 14, 13, 6, 5, ZSTD_lazy }, /* level 6 */ + { 0, 0, 14, 14, 14, 7, 6, ZSTD_lazy }, /* level 7 */ + { 0, 0, 14, 14, 14, 8, 4, ZSTD_lazy }, /* level 8 */ + { 0, 0, 14, 14, 15, 9, 4, ZSTD_lazy }, /* level 9 */ + { 0, 0, 14, 14, 15, 10, 4, ZSTD_lazy }, /* level 10 */ + { 0, 0, 14, 15, 15, 6, 4, ZSTD_btlazy2 }, /* level 11 */ + { 0, 0, 14, 15, 15, 7, 4, ZSTD_btlazy2 }, /* level 12 */ + { 0, 0, 14, 15, 15, 8, 4, ZSTD_btlazy2 }, /* level 13 */ + { 0, 0, 14, 15, 15, 9, 4, ZSTD_btlazy2 }, /* level 14 */ + { 0, 0, 14, 15, 15, 10, 4, ZSTD_btlazy2 }, /* level 15 */ + { 0, 0, 14, 15, 15, 11, 4, ZSTD_btlazy2 }, /* level 16 */ + { 0, 0, 14, 15, 15, 12, 4, ZSTD_btlazy2 }, /* level 17 */ + { 0, 0, 14, 15, 15, 13, 4, ZSTD_btlazy2 }, /* level 18 */ + { 0, 0, 14, 15, 15, 14, 4, ZSTD_btlazy2 }, /* level 19 */ + { 0, 0, 14, 15, 15, 15, 4, ZSTD_btlazy2 }, /* level 20 */ + { 0, 0, 14, 15, 15, 12, 4, ZSTD_btlazy2 }, /* level ??? */ + { 0, 0, 14, 15, 15, 13, 4, ZSTD_btlazy2 }, /* level ??? */ + { 0, 0, 14, 15, 15, 14, 4, ZSTD_btlazy2 }, /* level ??? */ + { 0, 0, 14, 15, 15, 15, 4, ZSTD_btlazy2 }, /* level ??? */ }, }; diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index b4c63f2ac..bfa0ea334 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -637,11 +637,6 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) if (dumps >= de) dumps = de-1; /* late correction, to avoid read overflow (data is now corrupted anyway) */ } -// litLength==0 offsetCode==0 offset = seqState->prevOffset seqState->prevOffset = seq->offset -// litLength==0 offsetCode>0 seqState->prevOffset = seq->offset; -// litLength>0 offsetCode==0 -// litLength>0 offsetCode>0 seqState->prevOffset = seq->offset; - /* Offset */ { static const U32 offsetPrefix[MaxOff+1] = { diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 82f46456e..a346a9f5b 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -571,7 +571,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, const uint8_t *inr; int skip_num = 0, cur, cur2, last_pos, litlen, price, match_num; - const int sufficient_len = 32; //ctx->params.sufficientLength; + const int sufficient_len = ctx->params.sufficientLength; const size_t faster_get_matches = (ctx->params.strategy == ZSTD_opt); diff --git a/lib/zstd_static.h b/lib/zstd_static.h index bedfa6e42..da2335bd3 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -69,6 +69,7 @@ typedef enum { ZSTD_fast, ZSTD_greedy, ZSTD_lazy, ZSTD_lazy2, ZSTD_btlazy2, ZSTD typedef struct { U64 srcSize; /* optional : tells how much bytes are present in the frame. Use 0 if not known. */ + U32 sufficientLength; /* size of matches which is acceptable (used only by the optimal parser): larger == more compression, slower */ U32 windowLog; /* largest match distance : larger == more compression, more memory needed during decompression */ U32 contentLog; /* full search segment : larger == more compression, slower, more memory (useless for fast) */ U32 hashLog; /* dispatch table : larger == more memory, faster */ From dbade7c263c4a062f26d3bba93aad753b10ebffd Mon Sep 17 00:00:00 2001 From: inikep Date: Fri, 5 Feb 2016 20:29:31 +0100 Subject: [PATCH 051/113] remove ZSTD_compressBlock_opt2_generic --- lib/zstd_opt.c | 146 ------------------------------------------------- 1 file changed, 146 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index a346a9f5b..b945b69e1 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -394,152 +394,6 @@ void print_hex_text(uint8_t* buf, int bufsize, int endline) } -/* ******************************* -* Old parser -*********************************/ -FORCE_INLINE -void ZSTD_compressBlock_opt2_generic(ZSTD_CCtx* ctx, - const void* src, size_t srcSize, - const U32 searchMethod, const U32 depth) -{ - seqStore_t* seqStorePtr = &(ctx->seqStore); - const BYTE* const istart = (const BYTE*)src; - const BYTE* ip = istart; - const BYTE* anchor = istart; - const BYTE* const iend = istart + srcSize; - const BYTE* const ilimit = iend - 8; - const BYTE* const base = ctx->base + ctx->dictLimit; - - size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE; - const U32 maxSearches = 1 << ctx->params.searchLog; - const U32 mls = ctx->params.searchLength; - - typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, - size_t* offsetPtr, - U32 maxNbAttempts, U32 matchLengthSearch); - searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS; - -#if 0 - typedef size_t (*getAllMatches_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit, - U32 maxNbAttempts, U32 matchLengthSearch, ZSTD_match_t* matches); - getAllMatches_f getAllMatches = searchMethod ? ZSTD_BtGetAllMatches_selectMLS : ZSTD_HcGetAllMatches_selectMLS; - - ZSTD_match_t matches[ZSTD_OPT_NUM+1]; -#endif - - /* init */ - ZSTD_resetSeqStore(seqStorePtr); - if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE; - - /* Match Loop */ - while (ip < ilimit) { - size_t matchLength=0; - size_t offset=0; - const BYTE* start=ip+1; - -#define ZSTD_USE_REP -#ifdef ZSTD_USE_REP - /* check repCode */ - if (MEM_read32(start) == MEM_read32(start - offset_1)) { - /* repcode : we take it */ - matchLength = ZSTD_count(start+MINMATCH, start+MINMATCH-offset_1, iend) + MINMATCH; - if (depth==0) goto _storeSequence; - } -#endif - - { - /* first search (depth 0) */ -#if 1 - size_t offsetFound = 99999999; - size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls); - if (ml2 > matchLength) - start=ip, matchLength = ml2, offset=offsetFound; -#else - size_t mnum = getAllMatches(ctx, ip, iend, maxSearches, mls, matches); - if (mnum > 0) { - if (matches[mnum-1].len > matchLength) - start=ip, matchLength = matches[mnum-1].len, offset=matches[mnum-1].off; - } -#endif - } - - if (matchLength < MINMATCH) { - // ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */ - ip++; - continue; - } - -#if 1 - /* let's try to find a better solution */ - if (depth>=1) - while (ip= MINMATCH) && (gain2 > gain1)) - matchLength = mlRep, offset = 0, start = ip; - } -#endif - { - size_t offset2=999999; - size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls); - int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */ - int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4); - if ((ml2 >= MINMATCH) && (gain2 > gain1)) { - matchLength = ml2, offset = offset2, start = ip; - continue; /* search a better one */ - } } - - break; /* nothing found : store previous solution */ - } -#endif - - /* store sequence */ -_storeSequence: - - /* catch up */ - if (offset) { - while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) /* only search for offset within prefix */ - { start--; matchLength++; } - offset_2 = offset_1; offset_1 = offset; - } - - { - size_t litLength = start - anchor; - ZSTD_LOG_ENCODE("%d/%d: ENCODE literals=%d off=%d mlen=%d offset_1=%d offset_2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)(offset), (int)matchLength, (int)offset_1, (int)offset_2); - ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH); - anchor = ip = start + matchLength; - } - -#ifdef ZSTD_USE_REP /* check immediate repcode */ - while ( (ip <= ilimit) - && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) { - /* store sequence */ - matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend); - offset = offset_2; - offset_2 = offset_1; - offset_1 = offset; - ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength); - ip += matchLength+MINMATCH; - anchor = ip; - continue; /* faster when present ... (?) */ - } -#endif - } - - /* Last Literals */ - { - size_t lastLLSize = iend - anchor; - ZSTD_LOG_ENCODE("%d/%d: ENCODE lastLLSize=%d\n", (int)(ip-base), (int)(iend-base), (int)(lastLLSize)); - memcpy(seqStorePtr->lit, anchor, lastLLSize); - seqStorePtr->lit += lastLLSize; - } -} - - /* ******************************* From da730ff092bb6c76330b71d9b449aa55eee2d313 Mon Sep 17 00:00:00 2001 From: inikep Date: Sat, 6 Feb 2016 15:18:26 +0100 Subject: [PATCH 052/113] a bugfix for backward matches --- lib/zstd_opt.c | 86 ++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index b945b69e1..d36b61a31 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -185,20 +185,22 @@ size_t ZSTD_insertBtAndGetAllMatches ( U32 nbCompares, const U32 mls, U32 extDict, ZSTD_match_t* matches, size_t bestLength) { - U32* const hashTable = zc->hashTable; + const BYTE* const base = zc->base; + const U32 current = (U32)(ip-base); const U32 hashLog = zc->params.hashLog; const size_t h = ZSTD_hashPtr(ip, hashLog, mls); + U32* const hashTable = zc->hashTable; + U32 matchIndex = hashTable[h]; + if (matchIndex >= current) return 0; + U32* const bt = zc->contentTable; const U32 btLog = zc->params.contentLog - 1; const U32 btMask= (1 << btLog) - 1; - U32 matchIndex = hashTable[h]; size_t commonLengthSmaller=0, commonLengthLarger=0; - const BYTE* const base = zc->base; const BYTE* const dictBase = zc->dictBase; const U32 dictLimit = zc->dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; const BYTE* const prefixStart = base + dictLimit; - const U32 current = (U32)(ip-base); const U32 btLow = btMask >= current ? 0 : current - btMask; const U32 windowLow = zc->lowLimit; U32* smallerPtr = bt + 2*(current&btMask); @@ -285,6 +287,8 @@ FORCE_INLINE size_t ZSTD_BtGetAllMatches_selectMLS ( const BYTE* ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, size_t minml) { + if (iLowLimit) {}; // skip warnings + switch(matchLengthSearch) { default : @@ -320,6 +324,7 @@ size_t ZSTD_HcGetAllMatches_generic ( /* HC4 match finder */ matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls); + if (matchIndex >= current) return 0; while ((matchIndex>lowLimit) && (nbAttempts)) { size_t currentMl=0; @@ -329,7 +334,6 @@ size_t ZSTD_HcGetAllMatches_generic ( match = base + matchIndex; if (match[minml] == ip[minml]) /* potentially better */ currentMl = ZSTD_count(ip, match, iHighLimit); - if (currentMl > 0) { while ((match-back > base) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ currentMl += back; @@ -338,6 +342,10 @@ size_t ZSTD_HcGetAllMatches_generic ( match = dictBase + matchIndex; if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */ currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iHighLimit, dictEnd, prefixStart) + MINMATCH; + if (currentMl > 0) { + while ((match-back > dictBase) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ + currentMl += back; + } } /* save best solution */ @@ -576,19 +584,22 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, - if (!opt[cur].off && opt[cur].mlen != 1) { - mlen = ZSTD_count(inr, inr - opt[cur].rep2, iend); // check rep2 - ZSTD_LOG_PARSER("%d: try REP2 rep2=%d mlen=%d\n", (int)(inr-base), opt[cur].rep2, mlen); - } - else { - mlen = ZSTD_count(inr, inr - opt[cur].rep, iend); // check rep - ZSTD_LOG_PARSER("%d: try REP1 rep=%d mlen=%d\n", (int)(inr-base), opt[cur].rep, mlen); - } - + size_t cur_rep; best_mlen = 0; - if (mlen >= MINMATCH) + if (!opt[cur].off && opt[cur].mlen != 1) { + cur_rep = opt[cur].rep2; + ZSTD_LOG_PARSER("%d: try REP2 rep2=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); + } + else { + cur_rep = opt[cur].rep; + ZSTD_LOG_PARSER("%d: try REP1 rep=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); + } + + + if (MEM_read32(inr) == MEM_read32(inr - cur_rep)) // check rep { + mlen = ZSTD_count(inr+MINMATCH, inr+MINMATCH - cur_rep, iend) + MINMATCH; ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep, cur, opt[cur].off); if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) @@ -666,6 +677,8 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, best_mlen = (cur2 + matches[i].len < ZSTD_OPT_NUM) ? matches[i].len : ZSTD_OPT_NUM - cur2; ZSTD_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(inr-base), cur, cur2, matches[i].len, matches[i].off, best_mlen, last_pos); + if (mlen < matches[i].back + 1) + mlen = matches[i].back + 1; while (mlen <= best_mlen) { @@ -739,7 +752,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set size_t litLength = ip - anchor; - ZSTD_LOG_ENCODE("%d/%d: BEFORE_ENCODE literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); + ZSTD_LOG_ENCODE("%d/%d: ENCODE1 literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); if (offset) { @@ -756,7 +769,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set } } - ZSTD_LOG_ENCODE("%d/%d: ENCODE literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); + ZSTD_LOG_ENCODE("%d/%d: ENCODE2 literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); // printf("orig="); print_hex_text(ip, mlen, 0); // printf("match="); print_hex_text(ip-offset, mlen, 0); @@ -766,33 +779,18 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set ml2 = ZSTD_count(ip, ip-offset, iend); else ml2 = ZSTD_count(ip, ip-rep_1, iend); - - if (ml2 < mlen && ml2 < MINMATCH) - { - printf("%d: ERROR iend=%d mlen=%d offset=%d ml2=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset, (int)ml2); - exit(0); - } - - if (ip < anchor) - { - printf("%d: ERROR ip < anchor iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); - exit(0); - } - if (ip - offset < base) - { - printf("%d: ERROR ip - offset < base iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); - exit(0); - } - if (mlen < MINMATCH) - { - printf("%d: ERROR mlen < MINMATCH iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); - exit(0); - } - if (ip + mlen > iend) - { - printf("%d: ERROR ip + mlen >= iend iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); - exit(0); - } + if (ml2 < mlen && ml2 < MINMATCH) { + printf("%d: ERROR iend=%d mlen=%d offset=%d ml2=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset, (int)ml2); exit(0); } + if (ip < anchor) { + printf("%d: ERROR ip < anchor iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } + if (ip - offset < ctx->base) { + printf("%d: ERROR ip - offset < base iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } + if ((int)offset >= (1 << ctx->params.windowLog)) { + printf("%d: offset >= (1 << params.windowLog) iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } + if (mlen < MINMATCH) { + printf("%d: ERROR mlen < MINMATCH iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } + if (ip + mlen > iend) { + printf("%d: ERROR ip + mlen >= iend iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } #endif ZSTD_updatePrice(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); From ef37063503b6590dadce1bf208d489294133790e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 7 Feb 2016 03:53:12 +0100 Subject: [PATCH 053/113] fix big-endian compression error --- programs/playTests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/playTests.sh b/programs/playTests.sh index 5d641ec59..0fe8db23c 100755 --- a/programs/playTests.sh +++ b/programs/playTests.sh @@ -16,7 +16,7 @@ roundTripTest() { rm -f tmp1 tmp2 echo "roundTripTest: ./datagen $1 $p | $ZSTD -v$c | $ZSTD -d" ./datagen $1 $p | md5sum > tmp1 - ./datagen $1 $p | $ZSTD -v$c | $ZSTD -d | md5sum > tmp2 + ./datagen $1 $p | $ZSTD -vq$c | $ZSTD -d | md5sum > tmp2 diff -q tmp1 tmp2 } From 4f0a3931c8d123d07cdb5aa0b9bbd217fe655144 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 7 Feb 2016 04:00:27 +0100 Subject: [PATCH 054/113] added missing patches --- Makefile | 3 +-- lib/zstd_compress.c | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 9ff867fbb..6f6c76ea7 100644 --- a/Makefile +++ b/Makefile @@ -27,8 +27,7 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # You can contact the author at : -# - zstd source repository : https://github.com/Cyan4973/zstd -# - Public forum : https://groups.google.com/forum/#!forum/lz4c +# - zstd homepage : http://www.zstd.net/ # ################################################################ # force a version number : uncomment below export (otherwise, default to the one declared into zstd.h) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index d5682811f..864d0ed6a 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -927,15 +927,15 @@ static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read static const U64 prime5bytes = 889523592379ULL; static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; } -static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_read64(p), h); } +static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); } static const U64 prime6bytes = 227718039650203ULL; static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; } -static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_read64(p), h); } +static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); } static const U64 prime7bytes = 58295818150454627ULL; static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; } -static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_read64(p), h); } +static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); } static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) { From 648959a9ed854d6d6bbee79c0a831703ba8ba588 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 7 Feb 2016 23:58:32 +0100 Subject: [PATCH 055/113] new : ARM tests with Qemu user-mode --- .travis.yml | 3 +++ Makefile | 7 ++++--- programs/Makefile | 7 ++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 065e6f143..8663b286b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,9 @@ before_install: - sudo apt-get install -qq g++-multilib - sudo apt-get install -qq gcc-multilib - sudo apt-get install -qq valgrind + - sudo apt-get install -qq qemu + - sudo apt-get install -qq binfmt-support + - sudo apt-get install -qq qemu-user-static env: - ZSTD_TRAVIS_CI_ENV=travis-install diff --git a/Makefile b/Makefile index 6f6c76ea7..60a083fdb 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # ################################################################ # zstd - Makefile -# Copyright (C) Yann Collet 2014-2015 +# Copyright (C) Yann Collet 2014-2016 # All rights reserved. # # BSD license @@ -93,8 +93,9 @@ gpptest: clean $(MAKE) all CC=g++ CFLAGS="-O3 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror" armtest: clean - $(MAKE) -C $(ZSTDDIR) all CC=arm-linux-gnueabi-gcc MOREFLAGS="-Werror" - $(MAKE) -C $(PRGDIR) CC=arm-linux-gnueabi-gcc MOREFLAGS="-Werror -static" +# $(MAKE) -C $(ZSTDDIR) all CC=arm-linux-gnueabi-gcc MOREFLAGS="-Werror" + $(MAKE) -C $(PRGDIR) datagen # use native, faster + $(MAKE) -C $(PRGDIR) test CC=arm-linux-gnueabi-gcc MOREFLAGS=-static # MOREFLAGS="-Werror -static" usan: clean $(MAKE) test CC=clang MOREFLAGS="-g -fsanitize=undefined" diff --git a/programs/Makefile b/programs/Makefile index 77b4cb46b..3db80a7cd 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -1,6 +1,6 @@ # ########################################################################## # ZSTD programs - Makefile -# Copyright (C) Yann Collet 2015 +# Copyright (C) Yann Collet 2015-2016 # # GPL v2 License # @@ -19,13 +19,14 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # # You can contact the author at : -# - ZSTD source repository : http://code.google.com/p/zstd/ -# - Public forum : https://groups.google.com/forum/#!forum/lz4c +# - zstd homepage : http://www.zstd.net/ # ########################################################################## # zstd : Command Line Utility, supporting gzip-like arguments # datagen : Synthetic and parametrable data generator, for tests # fuzzer : Test tool, to check zstd integrity on target platform # fuzzer32: Same as fuzzer, but forced to compile in 32-bits mode +# zbufftest : Test tool, to check ZBUFF integrity on target platform +# zbufftest32: Same as zbufftest, but forced to compile in 32-bits mode # fullbench : Precisely measure speed for each zstd inner function # fullbench32: Same as fullbench, but forced to compile in 32-bits mode # ########################################################################## From 521b0108dd2e4e61d36e10b6f55232f308e85168 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 8 Feb 2016 01:27:59 +0100 Subject: [PATCH 056/113] Added PowerPC tests with Qemu user more Shortened tests for emulated platforms removed date from CLI for reproducibility --- .travis.yml | 7 ++----- Makefile | 26 +++++++++++++++++++++++++- programs/Makefile | 3 ++- programs/zstdcli.c | 2 +- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8663b286b..b67b986e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,21 +2,18 @@ language: c before_install: - sudo apt-get update -qq - - sudo apt-get install -qq gcc-arm-linux-gnueabi - sudo apt-get install -qq clang - sudo apt-get install -qq g++-multilib - sudo apt-get install -qq gcc-multilib - sudo apt-get install -qq valgrind - - sudo apt-get install -qq qemu - - sudo apt-get install -qq binfmt-support - - sudo apt-get install -qq qemu-user-static env: - ZSTD_TRAVIS_CI_ENV=travis-install - ZSTD_TRAVIS_CI_ENV=cmaketest - ZSTD_TRAVIS_CI_ENV=clangtest - ZSTD_TRAVIS_CI_ENV=gpptest - - ZSTD_TRAVIS_CI_ENV=armtest + - ZSTD_TRAVIS_CI_ENV=armtest-w-install + - ZSTD_TRAVIS_CI_ENV=ppctest-w-install - ZSTD_TRAVIS_CI_ENV=test - ZSTD_TRAVIS_CI_ENV="-C programs test32" - ZSTD_TRAVIS_CI_ENV="-C programs test-zstd_nolegacy" diff --git a/Makefile b/Makefile index 60a083fdb..566f82b0d 100644 --- a/Makefile +++ b/Makefile @@ -95,7 +95,31 @@ gpptest: clean armtest: clean # $(MAKE) -C $(ZSTDDIR) all CC=arm-linux-gnueabi-gcc MOREFLAGS="-Werror" $(MAKE) -C $(PRGDIR) datagen # use native, faster - $(MAKE) -C $(PRGDIR) test CC=arm-linux-gnueabi-gcc MOREFLAGS=-static # MOREFLAGS="-Werror -static" + $(MAKE) -C $(PRGDIR) test CC=arm-linux-gnueabi-gcc ZSTDRTTEST= MOREFLAGS=-static # MOREFLAGS="-Werror -static" + +# for Travis CI +arminstall: clean + sudo apt-get install -q qemu + sudo apt-get install -q binfmt-support + sudo apt-get install -q qemu-user-static + sudo apt-get install -q gcc-arm-linux-gnueabi + +# for Travis CI +armtest-w-install: clean arminstall armtest + +ppctest: clean + $(MAKE) -C $(PRGDIR) datagen # use native, faster + $(MAKE) -C $(PRGDIR) test CC=powerpc-linux-gnu-gcc ZSTDRTTEST= MOREFLAGS=-static # MOREFLAGS="-Werror -static" + +# for Travis CI +ppcinstall: clean + sudo apt-get install -q qemu + sudo apt-get install -q binfmt-support + sudo apt-get install -q qemu-user-static + sudo apt-get install -q gcc-powerpc-linux-gnu + +# for Travis CI +ppctest-w-install: clean ppcinstall ppctest usan: clean $(MAKE) test CC=clang MOREFLAGS="-g -fsanitize=undefined" diff --git a/programs/Makefile b/programs/Makefile index 3db80a7cd..a23b2f7f1 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -76,6 +76,7 @@ endif ZBUFFTEST = -T2mn FUZZERTEST= -T5mn +ZSTDRTTEST= --test-large-data .PHONY: default all clean install uninstall test test32 test-all @@ -179,7 +180,7 @@ test32: test-zstd32 test-fullbench32 test-fuzzer32 test-zbuff32 test-all: test test32 valgrindTest zstd-playTests: datagen - ZSTD=$(ZSTD) ./playTests.sh --test-large-data + ZSTD=$(ZSTD) ./playTests.sh $(ZSTDRTTEST) test-zstd: ZSTD = ./zstd test-zstd: zstd zstd-playTests diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 1fe1b8b32..89027afd8 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -78,7 +78,7 @@ # define ZSTD_VERSION "v" EXPAND_AND_QUOTE(ZSTD_VERSION_MAJOR) "." EXPAND_AND_QUOTE(ZSTD_VERSION_MINOR) "." EXPAND_AND_QUOTE(ZSTD_VERSION_RELEASE) #endif #define AUTHOR "Yann Collet" -#define WELCOME_MESSAGE "*** %s %i-bits %s, by %s (%s) ***\n", COMPRESSOR_NAME, (int)(sizeof(void*)*8), ZSTD_VERSION, AUTHOR, __DATE__ +#define WELCOME_MESSAGE "*** %s %i-bits %s, by %s ***\n", COMPRESSOR_NAME, (int)(sizeof(void*)*8), ZSTD_VERSION, AUTHOR #define ZSTD_EXTENSION ".zst" #define ZSTD_CAT "zstdcat" #define ZSTD_UNZSTD "unzstd" From ee602ce68c531fbb8b11e7c5f33e7a97569d3656 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 8 Feb 2016 18:46:26 +0100 Subject: [PATCH 057/113] Added btlazy2 to short tests --- programs/playTests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/programs/playTests.sh b/programs/playTests.sh index 0fe8db23c..af5215701 100755 --- a/programs/playTests.sh +++ b/programs/playTests.sh @@ -69,6 +69,7 @@ echo "**** zstd round-trip tests **** " roundTripTest roundTripTest '' 6 +roundTripTest '' 16 if [ "$1" != "--test-large-data" ]; then echo "Skipping large data tests" From 0cd3ab5d660a81136fe1f5d211e39c51661bf1b1 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 8 Feb 2016 20:24:07 +0100 Subject: [PATCH 058/113] tests for powerpc target on travis ci --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 566f82b0d..4b27cfd85 100644 --- a/Makefile +++ b/Makefile @@ -116,6 +116,8 @@ ppcinstall: clean sudo apt-get install -q qemu sudo apt-get install -q binfmt-support sudo apt-get install -q qemu-user-static + apt-cache search powerpc + sudo apt-get update sudo apt-get install -q gcc-powerpc-linux-gnu # for Travis CI From 62ba4b49c185cce49285f807c680f16d7d7caf14 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 8 Feb 2016 20:29:59 +0100 Subject: [PATCH 059/113] more tests --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4b27cfd85..5054a7e0b 100644 --- a/Makefile +++ b/Makefile @@ -116,8 +116,9 @@ ppcinstall: clean sudo apt-get install -q qemu sudo apt-get install -q binfmt-support sudo apt-get install -q qemu-user-static - apt-cache search powerpc sudo apt-get update + apt-cache search powerpc + apt-cache search gcc sudo apt-get install -q gcc-powerpc-linux-gnu # for Travis CI From 991b3903b5f5a9c9e746ed5825eb077d752e5ca7 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 8 Feb 2016 20:58:37 +0100 Subject: [PATCH 060/113] removed PowerPC target on Travis CI (unfortunately unsupported) --- .travis.yml | 1 - Makefile | 6 ++---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index b67b986e5..fda0b05b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,6 @@ env: - ZSTD_TRAVIS_CI_ENV=clangtest - ZSTD_TRAVIS_CI_ENV=gpptest - ZSTD_TRAVIS_CI_ENV=armtest-w-install - - ZSTD_TRAVIS_CI_ENV=ppctest-w-install - ZSTD_TRAVIS_CI_ENV=test - ZSTD_TRAVIS_CI_ENV="-C programs test32" - ZSTD_TRAVIS_CI_ENV="-C programs test-zstd_nolegacy" diff --git a/Makefile b/Makefile index 5054a7e0b..e8b797da1 100644 --- a/Makefile +++ b/Makefile @@ -116,10 +116,8 @@ ppcinstall: clean sudo apt-get install -q qemu sudo apt-get install -q binfmt-support sudo apt-get install -q qemu-user-static - sudo apt-get update - apt-cache search powerpc - apt-cache search gcc - sudo apt-get install -q gcc-powerpc-linux-gnu + sudo apt-get update -q + sudo apt-get install -q gcc-powerpc-linux-gnu # unfortunately, doesn't work on Travis CI (package not available) # for Travis CI ppctest-w-install: clean ppcinstall ppctest From 6bff748e43d616788da3ea70f6df7b7e2c5ed033 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 9 Feb 2016 17:55:01 +0100 Subject: [PATCH 061/113] Fixed minor warnings in legacy modes --- lib/legacy/zstd_v02.c | 7 +++++-- lib/legacy/zstd_v03.c | 6 ++++-- lib/legacy/zstd_v04.c | 20 ++++++++++++-------- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/lib/legacy/zstd_v02.c b/lib/legacy/zstd_v02.c index 73136f81a..860df94a6 100644 --- a/lib/legacy/zstd_v02.c +++ b/lib/legacy/zstd_v02.c @@ -2133,7 +2133,8 @@ static size_t HUF_readDTableX4 (U32* DTable, const void* src, size_t srcSize) if (tableLog > memLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */ /* find maxWeight */ - for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ + for (maxW = tableLog; rankStats[maxW]==0; maxW--) + {if (!maxW) return ERROR(GENERIC); } /* necessarily finds a solution before maxW==0 */ /* Get start index of each weight */ { @@ -2465,7 +2466,9 @@ static size_t HUF_readDTableX6 (U32* DTable, const void* src, size_t srcSize) if (tableLog > memLog) return ERROR(tableLog_tooLarge); /* DTable is too small */ /* find maxWeight */ - for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ + for (maxW = tableLog; rankStats[maxW]==0; maxW--) + { if (!maxW) return ERROR(GENERIC); } /* necessarily finds a solution before maxW==0 */ + /* Get start index of each weight */ { diff --git a/lib/legacy/zstd_v03.c b/lib/legacy/zstd_v03.c index 5c75eb4e4..6a048fd27 100644 --- a/lib/legacy/zstd_v03.c +++ b/lib/legacy/zstd_v03.c @@ -2133,7 +2133,8 @@ static size_t HUF_readDTableX4 (U32* DTable, const void* src, size_t srcSize) if (tableLog > memLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */ /* find maxWeight */ - for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ + for (maxW = tableLog; rankStats[maxW]==0; maxW--) + { if (!maxW) return ERROR(GENERIC); } /* necessarily finds a solution before maxW==0 */ /* Get start index of each weight */ { @@ -2465,7 +2466,8 @@ static size_t HUF_readDTableX6 (U32* DTable, const void* src, size_t srcSize) if (tableLog > memLog) return ERROR(tableLog_tooLarge); /* DTable is too small */ /* find maxWeight */ - for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ + for (maxW = tableLog; rankStats[maxW]==0; maxW--) + { if (!maxW) return ERROR(GENERIC); } /* necessarily finds a solution before maxW==0 */ /* Get start index of each weight */ { diff --git a/lib/legacy/zstd_v04.c b/lib/legacy/zstd_v04.c index 45a3f61cc..4a1399ec9 100644 --- a/lib/legacy/zstd_v04.c +++ b/lib/legacy/zstd_v04.c @@ -1342,9 +1342,9 @@ typedef struct MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt) { - const void* ptr = dt; - const FSE_DTableHeader* const DTableH = (const FSE_DTableHeader*)ptr; - DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog); + FSE_DTableHeader DTableH; + memcpy(&DTableH, dt, sizeof(DTableH)); + DStatePtr->state = BIT_readBits(bitD, DTableH.tableLog); BIT_reloadDStream(bitD); DStatePtr->table = dt + 1; } @@ -1841,9 +1841,11 @@ static size_t FSE_decompress_usingDTable(void* dst, size_t originalSize, const void* cSrc, size_t cSrcSize, const FSE_DTable* dt) { - const void* ptr = dt; - const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr; - const U32 fastMode = DTableH->fastMode; + FSE_DTableHeader DTableH; + U32 fastMode; + + memcpy(&DTableH, dt, sizeof(DTableH)); + fastMode = DTableH.fastMode; /* select fast mode (static) */ if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1); @@ -2561,7 +2563,8 @@ static size_t HUF_readDTableX4 (U32* DTable, const void* src, size_t srcSize) if (tableLog > memLog) return ERROR(tableLog_tooLarge); /* DTable can't fit code depth */ /* find maxWeight */ - for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ + for (maxW = tableLog; rankStats[maxW]==0; maxW--) + { if (!maxW) return ERROR(GENERIC); } /* necessarily finds a solution before maxW==0 */ /* Get start index of each weight */ { @@ -2889,7 +2892,8 @@ static size_t HUF_readDTableX6 (U32* DTable, const void* src, size_t srcSize) if (tableLog > memLog) return ERROR(tableLog_tooLarge); /* DTable is too small */ /* find maxWeight */ - for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ + for (maxW = tableLog; rankStats[maxW]==0; maxW--) + { if (!maxW) return ERROR(GENERIC); } /* necessarily finds a solution before maxW==0 */ /* Get start index of each weight */ { From 31314ae0d18f338093bb173c3a2546996e3c2dc1 Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 9 Feb 2016 20:47:39 +0100 Subject: [PATCH 062/113] int to U32 --- lib/zstd_opt.c | 151 +++++++++++++++++++++---------------------------- 1 file changed, 64 insertions(+), 87 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index d36b61a31..576ee133e 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -3,19 +3,19 @@ typedef struct { - int off; - int len; - int back; + U32 off; + U32 len; + U32 back; } ZSTD_match_t; typedef struct { - int price; - int off; - int mlen; - int litlen; - int rep; - int rep2; + U32 price; + U32 off; + U32 mlen; + U32 litlen; + U32 rep; + U32 rep2; } ZSTD_optimal_t; @@ -38,34 +38,34 @@ typedef struct // log2_32 is from http://stackoverflow.com/questions/11376288/fast-computing-of-log2-for-64-bit-integers -const int tab32[32] = { +const U32 tab32[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31}; -int log2_32 (uint32_t value) +U32 log2_32 (U32 value) { value |= value >> 1; value |= value >> 2; value |= value >> 4; value |= value >> 8; value |= value >> 16; - return tab32[(uint32_t)(value*0x07C4ACDD) >> 27]; + return tab32[(U32)(value*0x07C4ACDD) >> 27]; } -FORCE_INLINE size_t ZSTD_getLiteralPriceReal(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals) +FORCE_INLINE U32 ZSTD_getLiteralPriceReal(seqStore_t* seqStorePtr, U32 litLength, const BYTE* literals) { - size_t price = 0; + U32 price = 0; if (litLength > 0) { /* literals */ - for (int i=litLength-1; i>=0; i--) + for (U32 i=0; i < litLength; i++) price += log2_32(seqStorePtr->litSum) - log2_32(seqStorePtr->litFreq[literals[i]]); /* literal Length */ - size_t freq; + U32 freq; if (litLength >= MaxLL) { freq = seqStorePtr->litLengthFreq[MaxLL]; if (litLength<255 + MaxLL) { @@ -84,7 +84,7 @@ FORCE_INLINE size_t ZSTD_getLiteralPriceReal(seqStore_t* seqStorePtr, size_t lit -FORCE_INLINE size_t ZSTD_getLiteralPrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals) +FORCE_INLINE U32 ZSTD_getLiteralPrice(seqStore_t* seqStorePtr, U32 litLength, const BYTE* literals) { if (seqStorePtr->litSum > ZSTD_FREQ_THRESHOLD) return ZSTD_getLiteralPriceReal(seqStorePtr, litLength, literals); @@ -94,17 +94,17 @@ FORCE_INLINE size_t ZSTD_getLiteralPrice(seqStore_t* seqStorePtr, size_t litLeng -FORCE_INLINE size_t ZSTD_getMatchPriceReal(seqStore_t* seqStorePtr, size_t offset, size_t matchLength) +FORCE_INLINE U32 ZSTD_getMatchPriceReal(seqStore_t* seqStorePtr, U32 offset, U32 matchLength) { /* match offset */ BYTE offCode = (BYTE)ZSTD_highbit(offset) + 1; if (offset==0) offCode = 0; - size_t price = log2_32(seqStorePtr->offCodeSum) - log2_32(seqStorePtr->offCodeFreq[offCode]); + U32 price = log2_32(seqStorePtr->offCodeSum) - log2_32(seqStorePtr->offCodeFreq[offCode]); price += offCode; /* match Length */ - size_t freq; + U32 freq; if (matchLength >= MaxML) { freq = seqStorePtr->matchLengthFreq[MaxML]; if (matchLength < 255+MaxML) { @@ -120,7 +120,7 @@ FORCE_INLINE size_t ZSTD_getMatchPriceReal(seqStore_t* seqStorePtr, size_t offse } -FORCE_INLINE size_t ZSTD_getPrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offset, size_t matchLength) +FORCE_INLINE U32 ZSTD_getPrice(seqStore_t* seqStorePtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength) { if (seqStorePtr->litSum > ZSTD_FREQ_THRESHOLD) return ZSTD_getLiteralPriceReal(seqStorePtr, litLength, literals) + ZSTD_getMatchPriceReal(seqStorePtr, offset, matchLength); @@ -130,7 +130,7 @@ FORCE_INLINE size_t ZSTD_getPrice(seqStore_t* seqStorePtr, size_t litLength, con -MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offset, size_t matchLength) +MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength) { #if 0 static const BYTE* g_start = NULL; @@ -141,7 +141,7 @@ MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, size_t litLength, cons #endif /* literals */ seqStorePtr->litSum += litLength; - for (int i=litLength-1; i>=0; i--) + for (U32 i=0; i < litLength; i++) seqStorePtr->litFreq[literals[i]]++; /* literal Length */ @@ -179,7 +179,7 @@ MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, size_t litLength, cons FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ -size_t ZSTD_insertBtAndGetAllMatches ( +U32 ZSTD_insertBtAndGetAllMatches ( ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, U32 nbCompares, const U32 mls, @@ -195,7 +195,7 @@ size_t ZSTD_insertBtAndGetAllMatches ( U32* const bt = zc->contentTable; const U32 btLog = zc->params.contentLog - 1; - const U32 btMask= (1 << btLog) - 1; + const U32 btMask= (1U << btLog) - 1; size_t commonLengthSmaller=0, commonLengthLarger=0; const BYTE* const dictBase = zc->dictBase; const U32 dictLimit = zc->dictLimit; @@ -207,7 +207,7 @@ size_t ZSTD_insertBtAndGetAllMatches ( U32* largerPtr = bt + 2*(current&btMask) + 1; U32 matchEndIdx = current+8; U32 dummy32; /* to be nullified at the end */ - size_t mnum = 0; + U32 mnum = 0; bestLength = 0; hashTable[h] = current; /* Update Hash Table */ @@ -235,7 +235,7 @@ size_t ZSTD_insertBtAndGetAllMatches ( if (matchLength >= MINMATCH) { bestLength = matchLength; matches[mnum].off = current - matchIndex; - matches[mnum].len = matchLength; + matches[mnum].len = (U32)matchLength; matches[mnum].back = 0; mnum++; } @@ -271,10 +271,10 @@ size_t ZSTD_insertBtAndGetAllMatches ( /** Tree updater, providing best match */ FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ -size_t ZSTD_BtGetAllMatches ( +U32 ZSTD_BtGetAllMatches ( ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iLimit, - const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, size_t minml) + const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, U32 minml) { if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */ ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls); @@ -282,10 +282,10 @@ size_t ZSTD_BtGetAllMatches ( } -FORCE_INLINE size_t ZSTD_BtGetAllMatches_selectMLS ( +FORCE_INLINE U32 ZSTD_BtGetAllMatches_selectMLS ( ZSTD_CCtx* zc, /* Index table will be updated */ const BYTE* ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, - const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, size_t minml) + const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, U32 minml) { if (iLowLimit) {}; // skip warnings @@ -300,13 +300,13 @@ FORCE_INLINE size_t ZSTD_BtGetAllMatches_selectMLS ( FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ -size_t ZSTD_HcGetAllMatches_generic ( +U32 ZSTD_HcGetAllMatches_generic ( ZSTD_CCtx* zc, /* Index table will be updated */ const BYTE* const ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, const U32 maxNbAttempts, const U32 mls, const U32 extDict, ZSTD_match_t* matches, size_t minml) { U32* const chainTable = zc->contentTable; - const U32 chainSize = (1 << zc->params.contentLog); + const U32 chainSize = (1U << zc->params.contentLog); const U32 chainMask = chainSize-1; const BYTE* const base = zc->base; const BYTE* const dictBase = zc->dictBase; @@ -317,9 +317,9 @@ size_t ZSTD_HcGetAllMatches_generic ( const U32 current = (U32)(ip-base); const U32 minChain = current > chainSize ? current - chainSize : 0; U32 matchIndex; + U32 mnum = 0; const BYTE* match; - int nbAttempts=maxNbAttempts; - size_t mnum = 0; + U32 nbAttempts=maxNbAttempts; minml=MINMATCH-1; /* HC4 match finder */ @@ -328,7 +328,7 @@ size_t ZSTD_HcGetAllMatches_generic ( while ((matchIndex>lowLimit) && (nbAttempts)) { size_t currentMl=0; - size_t back = 0; + U32 back = 0; nbAttempts--; if ((!extDict) || matchIndex >= dictLimit) { match = base + matchIndex; @@ -352,7 +352,7 @@ size_t ZSTD_HcGetAllMatches_generic ( if (currentMl > minml) { minml = currentMl; matches[mnum].off = current - matchIndex; - matches[mnum].len = currentMl; + matches[mnum].len = (U32)currentMl; matches[mnum].back = back; mnum++; if (currentMl > ZSTD_OPT_NUM) break; @@ -367,10 +367,10 @@ size_t ZSTD_HcGetAllMatches_generic ( } -FORCE_INLINE size_t ZSTD_HcGetAllMatches_selectMLS ( +FORCE_INLINE U32 ZSTD_HcGetAllMatches_selectMLS ( ZSTD_CCtx* zc, const BYTE* ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, - const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, size_t minml) + const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, U32 minml) { switch(matchLengthSearch) { @@ -382,27 +382,6 @@ FORCE_INLINE size_t ZSTD_HcGetAllMatches_selectMLS ( } -void print_hex_text(uint8_t* buf, int bufsize, int endline) -{ - int i, j; - for (i=0; i32?buf[i+j]:'.'); - printf("\n"); - } - if (endline) printf("\n"); -} - - - /* ******************************* * Optimal parser @@ -420,24 +399,22 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, const BYTE* const ilimit = iend - 8; const BYTE* const base = ctx->base + ctx->dictLimit; - size_t rep_2=REPCODE_STARTVALUE, rep_1=REPCODE_STARTVALUE; - const U32 maxSearches = 1 << ctx->params.searchLog; + U32 rep_2=REPCODE_STARTVALUE, rep_1=REPCODE_STARTVALUE; + const U32 maxSearches = 1U << ctx->params.searchLog; const U32 mls = ctx->params.searchLength; - typedef size_t (*getAllMatches_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLowLimit, const BYTE* iHighLimit, - U32 maxNbAttempts, U32 matchLengthSearch, ZSTD_match_t* matches, size_t minml); + typedef U32 (*getAllMatches_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLowLimit, const BYTE* iHighLimit, + U32 maxNbAttempts, U32 matchLengthSearch, ZSTD_match_t* matches, U32 minml); getAllMatches_f getAllMatches = searchMethod ? ZSTD_BtGetAllMatches_selectMLS : ZSTD_HcGetAllMatches_selectMLS; ZSTD_optimal_t opt[ZSTD_OPT_NUM+4]; ZSTD_match_t matches[ZSTD_OPT_NUM+1]; const uint8_t *inr; - int skip_num = 0, cur, cur2, last_pos, litlen, price, match_num; - - const int sufficient_len = ctx->params.sufficientLength; - const size_t faster_get_matches = (ctx->params.strategy == ZSTD_opt); + U32 skip_num, cur, cur2, match_num, last_pos, litlen, price; + const U32 sufficient_len = ctx->params.sufficientLength; + const U32 faster_get_matches = (ctx->params.strategy == ZSTD_opt); - // printf("orig_file="); print_hex_text(ip, srcSize, 0); /* init */ ZSTD_resetSeqStore(seqStorePtr); @@ -446,19 +423,19 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, /* Match Loop */ while (ip < ilimit) { - int mlen=0; - int best_mlen=0; - int best_off=0; + U32 mlen=0; + U32 best_mlen=0; + U32 best_off=0; memset(opt, 0, sizeof(ZSTD_optimal_t)); last_pos = 0; inr = ip; - opt[0].litlen = ip - anchor; + opt[0].litlen = (U32)(ip - anchor); /* check repCode */ if (MEM_read32(ip+1) == MEM_read32(ip+1 - rep_1)) { /* repcode : we take it */ - mlen = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-rep_1, iend) + MINMATCH; + mlen = (U32)ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-rep_1, iend) + MINMATCH; ZSTD_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)(ip-base), (int)rep_1, (int)mlen); if (depth==0 || mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) { @@ -502,7 +479,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } // set prices using matches at position = 0 - for (int i = 0; i < match_num; i++) + for (U32 i = 0; i < match_num; i++) { mlen = (i>0) ? matches[i-1].len+1 : best_mlen; best_mlen = (matches[i].len < ZSTD_OPT_NUM) ? matches[i].len : ZSTD_OPT_NUM; @@ -599,7 +576,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (MEM_read32(inr) == MEM_read32(inr - cur_rep)) // check rep { - mlen = ZSTD_count(inr+MINMATCH, inr+MINMATCH - cur_rep, iend) + MINMATCH; + mlen = (U32)ZSTD_count(inr+MINMATCH, inr+MINMATCH - cur_rep, iend) + MINMATCH; ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep, cur, opt[cur].off); if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) @@ -670,7 +647,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, // set prices using matches at position = cur - for (int i = 0; i < match_num; i++) + for (U32 i = 0; i < match_num; i++) { mlen = (i>0) ? matches[i-1].len+1 : best_mlen; cur2 = cur - matches[i].back; @@ -715,14 +692,14 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, /* store sequence */ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set - for (int i = 1; i <= last_pos; i++) + for (U32 i = 1; i <= last_pos; i++) ZSTD_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); ZSTD_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-base+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); opt[0].mlen = 1; - size_t offset; + U32 offset; - while (cur >= 0) + while (1) { mlen = opt[cur].mlen; ZSTD_LOG_PARSER("%d: cur=%d mlen=%d\n", (int)(ip-base), cur, mlen); @@ -731,10 +708,12 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set opt[cur].off = best_off; best_mlen = mlen; best_off = offset; + if (mlen > cur) + break; cur -= mlen; } - for (int i = 0; i <= last_pos;) + for (U32 i = 0; i <= last_pos;) { ZSTD_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); i += opt[i].mlen; @@ -751,7 +730,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set cur += mlen; - size_t litLength = ip - anchor; + U32 litLength = (U32)(ip - anchor); ZSTD_LOG_ENCODE("%d/%d: ENCODE1 literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); if (offset) @@ -770,9 +749,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set } ZSTD_LOG_ENCODE("%d/%d: ENCODE2 literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); - // printf("orig="); print_hex_text(ip, mlen, 0); - // printf("match="); print_hex_text(ip-offset, mlen, 0); - + #if ZSTD_OPT_DEBUG >= 5 int ml2; if (offset) @@ -803,7 +780,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set while ( (anchor <= ilimit) && (MEM_read32(anchor) == MEM_read32(anchor - rep_2)) ) { /* store sequence */ - best_mlen = ZSTD_count(anchor+MINMATCH, anchor+MINMATCH-rep_2, iend); + best_mlen = (U32)ZSTD_count(anchor+MINMATCH, anchor+MINMATCH-rep_2, iend); best_off = rep_2; rep_2 = rep_1; rep_1 = best_off; @@ -818,7 +795,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set /* Last Literals */ { - size_t lastLLSize = iend - anchor; + U32 lastLLSize = (U32)(iend - anchor); ZSTD_LOG_ENCODE("%d: lastLLSize literals=%d\n", (int)(ip-base), (int)(lastLLSize)); memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; From e75621f98d188c2354ab55d2757665b449cca4d3 Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 9 Feb 2016 21:12:23 +0100 Subject: [PATCH 063/113] dumpsEnd --- lib/zstd_compress.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index d5682811f..ac53662a0 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -240,7 +240,8 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, zc->seqStore.litLengthStart = zc->seqStore.litStart + blockSize; zc->seqStore.matchLengthStart = zc->seqStore.litLengthStart + (blockSize>>2); zc->seqStore.dumpsStart = zc->seqStore.matchLengthStart + (blockSize>>2); - zc->seqStore.litFreq = (U32*) (zc->seqStore.dumpsStart + (blockSize>>2)); + BYTE* dumpsEnd= zc->seqStore.dumpsStart + (blockSize>>2); + zc->seqStore.litFreq = (U32*)(dumpsEnd); zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (1<seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (1< Date: Tue, 9 Feb 2016 22:23:48 +0100 Subject: [PATCH 064/113] ZSTD_compressBlock_opt_extDict_generic --- lib/zstd_compress.c | 6 +- lib/zstd_opt.c | 492 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 492 insertions(+), 6 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index ac53662a0..407b3e8df 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -1927,12 +1927,12 @@ static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, static void ZSTD_compressBlock_opt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2); + ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0, 2); } static void ZSTD_compressBlock_opt_bt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2); + ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1, 2); } @@ -2106,10 +2106,12 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t case ZSTD_greedy: case ZSTD_lazy: case ZSTD_lazy2: + case ZSTD_opt: ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.searchLength); break; case ZSTD_btlazy2: + case ZSTD_opt_bt: ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength); break; diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 576ee133e..bd7abfc71 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -178,6 +178,9 @@ MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, U32 litLength, const B +/* ************************************* +* Binary Tree search +***************************************/ FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ U32 ZSTD_insertBtAndGetAllMatches ( ZSTD_CCtx* zc, @@ -298,7 +301,39 @@ FORCE_INLINE U32 ZSTD_BtGetAllMatches_selectMLS ( } } +/** Tree updater, providing best match */ +FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ +size_t ZSTD_BtGetAllMatches_extDict ( + ZSTD_CCtx* zc, + const BYTE* const ip, const BYTE* const iLimit, + const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, U32 minml) +{ + if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */ + ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls); + return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 1, matches, minml); +} + +FORCE_INLINE U32 ZSTD_BtGetAllMatches_selectMLS_extDict ( + ZSTD_CCtx* zc, /* Index table will be updated */ + const BYTE* ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, + const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, U32 minml) +{ + if (iLowLimit) {}; // skip warnings + + switch(matchLengthSearch) + { + default : + case 4 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minml); + case 5 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minml); + case 6 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minml); + } +} + + +/* *********************** +* Hash Chain +*************************/ FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ U32 ZSTD_HcGetAllMatches_generic ( ZSTD_CCtx* zc, /* Index table will be updated */ @@ -313,6 +348,7 @@ U32 ZSTD_HcGetAllMatches_generic ( const U32 dictLimit = zc->dictLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; + const BYTE* const dictStart = dictBase + zc->lowLimit; const U32 lowLimit = zc->lowLimit; const U32 current = (U32)(ip-base); const U32 minChain = current > chainSize ? current - chainSize : 0; @@ -343,7 +379,7 @@ U32 ZSTD_HcGetAllMatches_generic ( if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */ currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iHighLimit, dictEnd, prefixStart) + MINMATCH; if (currentMl > 0) { - while ((match-back > dictBase) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ + while ((match-back > dictStart) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ currentMl += back; } } @@ -381,6 +417,19 @@ FORCE_INLINE U32 ZSTD_HcGetAllMatches_selectMLS ( } } +FORCE_INLINE U32 ZSTD_HcGetAllMatches_selectMLS_extDict ( + ZSTD_CCtx* zc, + const BYTE* ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, + const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, U32 minml) +{ + switch(matchLengthSearch) + { + default : + case 4 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLowLimit, iHighLimit, maxNbAttempts, 4, 1, matches, minml); + case 5 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLowLimit, iHighLimit, maxNbAttempts, 5, 1, matches, minml); + case 6 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLowLimit, iHighLimit, maxNbAttempts, 6, 1, matches, minml); + } +} /* ******************************* @@ -465,9 +514,9 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); if (!last_pos && !match_num) { ip++; continue; } - opt[0].rep = rep_1; - opt[0].rep2 = rep_2; - opt[0].mlen = 1; + opt[0].rep = rep_1; + opt[0].rep2 = rep_2; + opt[0].mlen = 1; if (match_num && matches[match_num-1].len > sufficient_len) { @@ -804,3 +853,438 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set +FORCE_INLINE +void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, + const void* src, size_t srcSize, + const U32 searchMethod, const U32 depth) +{ + seqStore_t* seqStorePtr = &(ctx->seqStore); + const BYTE* const istart = (const BYTE*)src; + const BYTE* ip = istart; + const BYTE* anchor = istart; + const BYTE* const iend = istart + srcSize; + const BYTE* const ilimit = iend - 8; + const BYTE* const base = ctx->base; + const U32 dictLimit = ctx->dictLimit; + const BYTE* const prefixStart = base + dictLimit; + const BYTE* const dictBase = ctx->dictBase; + const BYTE* const dictEnd = dictBase + dictLimit; + + U32 rep_2=REPCODE_STARTVALUE, rep_1=REPCODE_STARTVALUE; + const U32 maxSearches = 1U << ctx->params.searchLog; + const U32 mls = ctx->params.searchLength; + + typedef U32 (*getAllMatches_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLowLimit, const BYTE* iHighLimit, + U32 maxNbAttempts, U32 matchLengthSearch, ZSTD_match_t* matches, U32 minml); + getAllMatches_f getAllMatches = searchMethod ? ZSTD_BtGetAllMatches_selectMLS_extDict : ZSTD_HcGetAllMatches_selectMLS_extDict; + + ZSTD_optimal_t opt[ZSTD_OPT_NUM+4]; + ZSTD_match_t matches[ZSTD_OPT_NUM+1]; + const uint8_t *inr; + U32 skip_num, cur, cur2, match_num, last_pos, litlen, price; + + const U32 sufficient_len = ctx->params.sufficientLength; + const U32 faster_get_matches = (ctx->params.strategy == ZSTD_opt); + + + /* init */ + ZSTD_resetSeqStore(seqStorePtr); + if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE; + + + /* Match Loop */ + while (ip < ilimit) { + U32 mlen=0; + U32 best_mlen=0; + U32 best_off=0; + U32 current = (U32)(ip-base); + memset(opt, 0, sizeof(ZSTD_optimal_t)); + last_pos = 0; + inr = ip; + opt[0].litlen = (U32)(ip - anchor); + + + /* check repCode */ + { + const U32 repIndex = (U32)(current+1 - rep_1); + const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; + const BYTE* const repMatch = repBase + repIndex; + if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ + if (MEM_read32(ip+1) == MEM_read32(repMatch)) { + /* repcode detected we should take it */ + const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; + mlen = (U32)ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; + + ZSTD_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)(ip-base), (int)rep_1, (int)mlen); + if (depth==0 || mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) { + ip+=1; best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; + goto _storeSequence; + } + + litlen = opt[0].litlen + 1; + do + { + price = ZSTD_getPrice(seqStorePtr, litlen, anchor, 0, mlen - MINMATCH); + if (mlen + 1 > last_pos || price < opt[mlen + 1].price) + SET_PRICE(mlen + 1, mlen, 0, litlen, price); + mlen--; + } + while (mlen >= MINMATCH); + } + } + + best_mlen = (last_pos) ? last_pos : MINMATCH; + + if (faster_get_matches && last_pos) + match_num = 0; + else + match_num = getAllMatches(ctx, ip, ip, iend, maxSearches, mls, matches, best_mlen); /* first search (depth 0) */ + + ZSTD_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); + if (!last_pos && !match_num) { ip++; continue; } + + opt[0].rep = rep_1; + opt[0].rep2 = rep_2; + opt[0].mlen = 1; + + if (match_num && matches[match_num-1].len > sufficient_len) + { + best_mlen = matches[match_num-1].len; + best_off = matches[match_num-1].off; + cur = 0; + last_pos = 1; + goto _storeSequence; + } + + // set prices using matches at position = 0 + for (U32 i = 0; i < match_num; i++) + { + mlen = (i>0) ? matches[i-1].len+1 : best_mlen; + best_mlen = (matches[i].len < ZSTD_OPT_NUM) ? matches[i].len : ZSTD_OPT_NUM; + ZSTD_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(ip-base), matches[i].len, matches[i].off, (int)best_mlen, (int)last_pos); + litlen = opt[0].litlen; + while (mlen <= best_mlen) + { + price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[i].off, mlen - MINMATCH); + if (mlen > last_pos || price < opt[mlen].price) + SET_PRICE(mlen, mlen, matches[i].off, litlen, price); + mlen++; + } + } + + if (last_pos < MINMATCH) { + // ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */ + ip++; continue; + } + + + // check further positions + for (skip_num = 0, cur = 1; cur <= last_pos; cur++) + { + inr = ip + cur; + + if (opt[cur-1].mlen == 1) + { + litlen = opt[cur-1].litlen + 1; + if (cur > litlen) + { + price = opt[cur - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-litlen); + ZSTD_LOG_TRY_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); + } + else + price = ZSTD_getLiteralPrice(seqStorePtr, litlen, anchor); + } + else + { + litlen = 1; + price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1); + ZSTD_LOG_TRY_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)(inr-base), price, cur, litlen, (int)ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1)); + } + + ZSTD_LOG_TRY_PRICE("%d: TRY4 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur, opt[cur].price); + + if (cur > last_pos || price <= opt[cur].price) // || ((price == opt[cur].price) && (opt[cur-1].mlen == 1) && (cur != litlen))) + SET_PRICE(cur, 1, 0, litlen, price); + + if (cur == last_pos) break; + + if (inr > ilimit) // last match must start at a minimum distance of 8 from oend + continue; + + mlen = opt[cur].mlen; + + if (opt[cur-mlen].off) + { + opt[cur].rep2 = opt[cur-mlen].rep; + opt[cur].rep = opt[cur-mlen].off; + ZSTD_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); + } + else + { + if (cur!=mlen && opt[cur-mlen].litlen == 0) + { + opt[cur].rep2 = opt[cur-mlen].rep; + opt[cur].rep = opt[cur-mlen].rep2; + ZSTD_LOG_PARSER("%d: COPYREP2 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); + } + else + { + opt[cur].rep2 = opt[cur-mlen].rep2; + opt[cur].rep = opt[cur-mlen].rep; + ZSTD_LOG_PARSER("%d: COPYREP3 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); + } + } + + ZSTD_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); + + + + size_t cur_rep; + best_mlen = 0; + + if (!opt[cur].off && opt[cur].mlen != 1) { + cur_rep = opt[cur].rep2; + ZSTD_LOG_PARSER("%d: try REP2 rep2=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); + } + else { + cur_rep = opt[cur].rep; + ZSTD_LOG_PARSER("%d: try REP1 rep=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); + } + + const U32 repIndex = (U32)(current+cur - cur_rep); + const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; + const BYTE* const repMatch = repBase + repIndex; + if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ + if (MEM_read32(inr) == MEM_read32(repMatch)) { + /* repcode detected */ + const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; + mlen = (U32)ZSTD_count_2segments(inr+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; + ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep, cur, opt[cur].off); + + if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) + { + best_mlen = mlen; + best_off = 0; + ZSTD_LOG_PARSER("%d: REP sufficient_len=%d best_mlen=%d best_off=%d last_pos=%d\n", (int)(inr-base), sufficient_len, best_mlen, best_off, last_pos); + last_pos = cur + 1; + goto _storeSequence; + } + + if (opt[cur].mlen == 1) + { + litlen = opt[cur].litlen; + + if (cur > litlen) + { + price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, inr-litlen, 0, mlen - MINMATCH); + ZSTD_LOG_TRY_PRICE("%d: TRY5 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); + } + else + price = ZSTD_getPrice(seqStorePtr, litlen, anchor, 0, mlen - MINMATCH); + } + else + { + litlen = 0; + price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, 0, mlen - MINMATCH); + ZSTD_LOG_TRY_PRICE("%d: TRY7 price=%d cur=%d litlen=0 getprice=%d\n", (int)(inr-base), price, cur, (int)ZSTD_getPrice(seqStorePtr, 0, NULL, 0, mlen - MINMATCH)); + } + + best_mlen = mlen; + if (faster_get_matches) + skip_num = best_mlen; + + ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), mlen, 0, price, litlen, cur - litlen, opt[cur - litlen].price); + + do + { + if (cur + mlen > last_pos || price <= opt[cur + mlen].price) // || ((price == opt[cur + mlen].price) && (opt[cur].mlen == 1) && (cur != litlen))) // at equal price prefer REP instead of MATCH + SET_PRICE(cur + mlen, mlen, 0, litlen, price); + mlen--; + } + while (mlen >= MINMATCH); + } + + + if (faster_get_matches && skip_num > 0) + { + skip_num--; + continue; + } + + + best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; + + match_num = getAllMatches(ctx, inr, ip, iend, maxSearches, mls, matches, best_mlen); + ZSTD_LOG_PARSER("%d: ZSTD_GetAllMatches match_num=%d\n", (int)(inr-base), match_num); + + + if (match_num > 0 && matches[match_num-1].len > sufficient_len) + { + cur -= matches[match_num-1].back; + best_mlen = matches[match_num-1].len; + best_off = matches[match_num-1].off; + last_pos = cur + 1; + goto _storeSequence; + } + + + // set prices using matches at position = cur + for (U32 i = 0; i < match_num; i++) + { + mlen = (i>0) ? matches[i-1].len+1 : best_mlen; + cur2 = cur - matches[i].back; + best_mlen = (cur2 + matches[i].len < ZSTD_OPT_NUM) ? matches[i].len : ZSTD_OPT_NUM - cur2; + + ZSTD_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(inr-base), cur, cur2, matches[i].len, matches[i].off, best_mlen, last_pos); + if (mlen < matches[i].back + 1) + mlen = matches[i].back + 1; + + while (mlen <= best_mlen) + { + if (opt[cur2].mlen == 1) + { + litlen = opt[cur2].litlen; + if (cur2 > litlen) + price = opt[cur2 - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, ip+cur2-litlen, matches[i].off, mlen - MINMATCH); + else + price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[i].off, mlen - MINMATCH); + } + else + { + litlen = 0; + price = opt[cur2].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[i].off, mlen - MINMATCH); + } + + ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); + ZSTD_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); + + if (cur2 + mlen > last_pos || (price < opt[cur2 + mlen].price)) + SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); + + mlen++; + } + } + } // for (skip_num = 0, cur = 1; cur <= last_pos; cur++) + + + best_mlen = opt[last_pos].mlen; + best_off = opt[last_pos].off; + cur = last_pos - best_mlen; + // printf("%d: start=%d best_mlen=%d best_off=%d cur=%d\n", (int)(ip - base), (int)(start - ip), (int)best_mlen, (int)best_off, cur); + + /* store sequence */ +_storeSequence: // cur, last_pos, best_mlen, best_off have to be set + for (U32 i = 1; i <= last_pos; i++) + ZSTD_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); + ZSTD_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-base+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); + + opt[0].mlen = 1; + U32 offset; + + while (1) + { + mlen = opt[cur].mlen; + ZSTD_LOG_PARSER("%d: cur=%d mlen=%d\n", (int)(ip-base), cur, mlen); + offset = opt[cur].off; + opt[cur].mlen = best_mlen; + opt[cur].off = best_off; + best_mlen = mlen; + best_off = offset; + if (mlen > cur) + break; + cur -= mlen; + } + + for (U32 i = 0; i <= last_pos;) + { + ZSTD_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); + i += opt[i].mlen; + } + + cur = 0; + + while (cur < last_pos) + { + ZSTD_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); + mlen = opt[cur].mlen; + if (mlen == 1) { ip++; cur++; continue; } + offset = opt[cur].off; + cur += mlen; + + + U32 litLength = (U32)(ip - anchor); + ZSTD_LOG_ENCODE("%d/%d: ENCODE1 literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); + + if (offset) + { + rep_2 = rep_1; + rep_1 = offset; + } + else + { + if (litLength == 0) + { + best_off = rep_2; + rep_2 = rep_1; + rep_1 = best_off; + } + } + + ZSTD_LOG_ENCODE("%d/%d: ENCODE2 literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); + +#if ZSTD_OPT_DEBUG >= 5 + int ml2; + if (offset) + ml2 = ZSTD_count(ip, ip-offset, iend); + else + ml2 = ZSTD_count(ip, ip-rep_1, iend); + if (ml2 < mlen && ml2 < MINMATCH) { + printf("%d: ERROR iend=%d mlen=%d offset=%d ml2=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset, (int)ml2); exit(0); } + if (ip < anchor) { + printf("%d: ERROR ip < anchor iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } + if (ip - offset < ctx->base) { + printf("%d: ERROR ip - offset < base iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } + if ((int)offset >= (1 << ctx->params.windowLog)) { + printf("%d: offset >= (1 << params.windowLog) iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } + if (mlen < MINMATCH) { + printf("%d: ERROR mlen < MINMATCH iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } + if (ip + mlen > iend) { + printf("%d: ERROR ip + mlen >= iend iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } +#endif + + ZSTD_updatePrice(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); + ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); + anchor = ip = ip + mlen; + } + + + // check immediate repcode + while (anchor <= ilimit) { + const U32 repIndex = (U32)((anchor-base) - rep_2); + const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; + const BYTE* const repMatch = repBase + repIndex; + if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ + if (MEM_read32(anchor) == MEM_read32(repMatch)) { + /* repcode detected we should take it */ + const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; + mlen = (U32)ZSTD_count_2segments(anchor+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; + offset = rep_2; rep_2 = rep_1; rep_1 = offset; /* swap offset history */ + ZSTD_LOG_ENCODE("%d/%d: ENCODE REP literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(anchor-base), (int)(iend-base), (int)(0), (int)best_mlen, (int)(0), (int)rep_1, (int)rep_2); + ZSTD_updatePrice(seqStorePtr, 0, anchor, 0, mlen-MINMATCH); + ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, mlen-MINMATCH); + anchor += mlen; + ip = anchor; + continue; /* faster when present ... (?) */ + } + break; + } + } + + /* Last Literals */ + { + U32 lastLLSize = (U32)(iend - anchor); + ZSTD_LOG_ENCODE("%d: lastLLSize literals=%d\n", (int)(ip-base), (int)(lastLLSize)); + memcpy(seqStorePtr->lit, anchor, lastLLSize); + seqStorePtr->lit += lastLLSize; + } +} From 2b714dfd2642d30e5b6ea84a61b148d8bc790a61 Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 9 Feb 2016 22:47:51 +0100 Subject: [PATCH 065/113] Revert "ZSTD_compressBlock_opt_extDict_generic" This reverts commit b498fc1c9971e64022607309213bcd7a3bf0d244. --- lib/zstd_compress.c | 6 +- lib/zstd_opt.c | 492 +------------------------------------------- 2 files changed, 6 insertions(+), 492 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 407b3e8df..ac53662a0 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -1927,12 +1927,12 @@ static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, static void ZSTD_compressBlock_opt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0, 2); + ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2); } static void ZSTD_compressBlock_opt_bt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1, 2); + ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2); } @@ -2106,12 +2106,10 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t case ZSTD_greedy: case ZSTD_lazy: case ZSTD_lazy2: - case ZSTD_opt: ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.searchLength); break; case ZSTD_btlazy2: - case ZSTD_opt_bt: ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength); break; diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index bd7abfc71..576ee133e 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -178,9 +178,6 @@ MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, U32 litLength, const B -/* ************************************* -* Binary Tree search -***************************************/ FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ U32 ZSTD_insertBtAndGetAllMatches ( ZSTD_CCtx* zc, @@ -301,39 +298,7 @@ FORCE_INLINE U32 ZSTD_BtGetAllMatches_selectMLS ( } } -/** Tree updater, providing best match */ -FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ -size_t ZSTD_BtGetAllMatches_extDict ( - ZSTD_CCtx* zc, - const BYTE* const ip, const BYTE* const iLimit, - const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, U32 minml) -{ - if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */ - ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls); - return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 1, matches, minml); -} - -FORCE_INLINE U32 ZSTD_BtGetAllMatches_selectMLS_extDict ( - ZSTD_CCtx* zc, /* Index table will be updated */ - const BYTE* ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, - const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, U32 minml) -{ - if (iLowLimit) {}; // skip warnings - - switch(matchLengthSearch) - { - default : - case 4 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minml); - case 5 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minml); - case 6 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minml); - } -} - - -/* *********************** -* Hash Chain -*************************/ FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ U32 ZSTD_HcGetAllMatches_generic ( ZSTD_CCtx* zc, /* Index table will be updated */ @@ -348,7 +313,6 @@ U32 ZSTD_HcGetAllMatches_generic ( const U32 dictLimit = zc->dictLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; - const BYTE* const dictStart = dictBase + zc->lowLimit; const U32 lowLimit = zc->lowLimit; const U32 current = (U32)(ip-base); const U32 minChain = current > chainSize ? current - chainSize : 0; @@ -379,7 +343,7 @@ U32 ZSTD_HcGetAllMatches_generic ( if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */ currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iHighLimit, dictEnd, prefixStart) + MINMATCH; if (currentMl > 0) { - while ((match-back > dictStart) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ + while ((match-back > dictBase) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ currentMl += back; } } @@ -417,19 +381,6 @@ FORCE_INLINE U32 ZSTD_HcGetAllMatches_selectMLS ( } } -FORCE_INLINE U32 ZSTD_HcGetAllMatches_selectMLS_extDict ( - ZSTD_CCtx* zc, - const BYTE* ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, - const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, U32 minml) -{ - switch(matchLengthSearch) - { - default : - case 4 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLowLimit, iHighLimit, maxNbAttempts, 4, 1, matches, minml); - case 5 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLowLimit, iHighLimit, maxNbAttempts, 5, 1, matches, minml); - case 6 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLowLimit, iHighLimit, maxNbAttempts, 6, 1, matches, minml); - } -} /* ******************************* @@ -514,9 +465,9 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); if (!last_pos && !match_num) { ip++; continue; } - opt[0].rep = rep_1; - opt[0].rep2 = rep_2; - opt[0].mlen = 1; + opt[0].rep = rep_1; + opt[0].rep2 = rep_2; + opt[0].mlen = 1; if (match_num && matches[match_num-1].len > sufficient_len) { @@ -853,438 +804,3 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set -FORCE_INLINE -void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, - const void* src, size_t srcSize, - const U32 searchMethod, const U32 depth) -{ - seqStore_t* seqStorePtr = &(ctx->seqStore); - const BYTE* const istart = (const BYTE*)src; - const BYTE* ip = istart; - const BYTE* anchor = istart; - const BYTE* const iend = istart + srcSize; - const BYTE* const ilimit = iend - 8; - const BYTE* const base = ctx->base; - const U32 dictLimit = ctx->dictLimit; - const BYTE* const prefixStart = base + dictLimit; - const BYTE* const dictBase = ctx->dictBase; - const BYTE* const dictEnd = dictBase + dictLimit; - - U32 rep_2=REPCODE_STARTVALUE, rep_1=REPCODE_STARTVALUE; - const U32 maxSearches = 1U << ctx->params.searchLog; - const U32 mls = ctx->params.searchLength; - - typedef U32 (*getAllMatches_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLowLimit, const BYTE* iHighLimit, - U32 maxNbAttempts, U32 matchLengthSearch, ZSTD_match_t* matches, U32 minml); - getAllMatches_f getAllMatches = searchMethod ? ZSTD_BtGetAllMatches_selectMLS_extDict : ZSTD_HcGetAllMatches_selectMLS_extDict; - - ZSTD_optimal_t opt[ZSTD_OPT_NUM+4]; - ZSTD_match_t matches[ZSTD_OPT_NUM+1]; - const uint8_t *inr; - U32 skip_num, cur, cur2, match_num, last_pos, litlen, price; - - const U32 sufficient_len = ctx->params.sufficientLength; - const U32 faster_get_matches = (ctx->params.strategy == ZSTD_opt); - - - /* init */ - ZSTD_resetSeqStore(seqStorePtr); - if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE; - - - /* Match Loop */ - while (ip < ilimit) { - U32 mlen=0; - U32 best_mlen=0; - U32 best_off=0; - U32 current = (U32)(ip-base); - memset(opt, 0, sizeof(ZSTD_optimal_t)); - last_pos = 0; - inr = ip; - opt[0].litlen = (U32)(ip - anchor); - - - /* check repCode */ - { - const U32 repIndex = (U32)(current+1 - rep_1); - const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; - const BYTE* const repMatch = repBase + repIndex; - if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ - if (MEM_read32(ip+1) == MEM_read32(repMatch)) { - /* repcode detected we should take it */ - const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; - mlen = (U32)ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; - - ZSTD_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)(ip-base), (int)rep_1, (int)mlen); - if (depth==0 || mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) { - ip+=1; best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; - goto _storeSequence; - } - - litlen = opt[0].litlen + 1; - do - { - price = ZSTD_getPrice(seqStorePtr, litlen, anchor, 0, mlen - MINMATCH); - if (mlen + 1 > last_pos || price < opt[mlen + 1].price) - SET_PRICE(mlen + 1, mlen, 0, litlen, price); - mlen--; - } - while (mlen >= MINMATCH); - } - } - - best_mlen = (last_pos) ? last_pos : MINMATCH; - - if (faster_get_matches && last_pos) - match_num = 0; - else - match_num = getAllMatches(ctx, ip, ip, iend, maxSearches, mls, matches, best_mlen); /* first search (depth 0) */ - - ZSTD_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); - if (!last_pos && !match_num) { ip++; continue; } - - opt[0].rep = rep_1; - opt[0].rep2 = rep_2; - opt[0].mlen = 1; - - if (match_num && matches[match_num-1].len > sufficient_len) - { - best_mlen = matches[match_num-1].len; - best_off = matches[match_num-1].off; - cur = 0; - last_pos = 1; - goto _storeSequence; - } - - // set prices using matches at position = 0 - for (U32 i = 0; i < match_num; i++) - { - mlen = (i>0) ? matches[i-1].len+1 : best_mlen; - best_mlen = (matches[i].len < ZSTD_OPT_NUM) ? matches[i].len : ZSTD_OPT_NUM; - ZSTD_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(ip-base), matches[i].len, matches[i].off, (int)best_mlen, (int)last_pos); - litlen = opt[0].litlen; - while (mlen <= best_mlen) - { - price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[i].off, mlen - MINMATCH); - if (mlen > last_pos || price < opt[mlen].price) - SET_PRICE(mlen, mlen, matches[i].off, litlen, price); - mlen++; - } - } - - if (last_pos < MINMATCH) { - // ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */ - ip++; continue; - } - - - // check further positions - for (skip_num = 0, cur = 1; cur <= last_pos; cur++) - { - inr = ip + cur; - - if (opt[cur-1].mlen == 1) - { - litlen = opt[cur-1].litlen + 1; - if (cur > litlen) - { - price = opt[cur - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-litlen); - ZSTD_LOG_TRY_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); - } - else - price = ZSTD_getLiteralPrice(seqStorePtr, litlen, anchor); - } - else - { - litlen = 1; - price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1); - ZSTD_LOG_TRY_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)(inr-base), price, cur, litlen, (int)ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1)); - } - - ZSTD_LOG_TRY_PRICE("%d: TRY4 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur, opt[cur].price); - - if (cur > last_pos || price <= opt[cur].price) // || ((price == opt[cur].price) && (opt[cur-1].mlen == 1) && (cur != litlen))) - SET_PRICE(cur, 1, 0, litlen, price); - - if (cur == last_pos) break; - - if (inr > ilimit) // last match must start at a minimum distance of 8 from oend - continue; - - mlen = opt[cur].mlen; - - if (opt[cur-mlen].off) - { - opt[cur].rep2 = opt[cur-mlen].rep; - opt[cur].rep = opt[cur-mlen].off; - ZSTD_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); - } - else - { - if (cur!=mlen && opt[cur-mlen].litlen == 0) - { - opt[cur].rep2 = opt[cur-mlen].rep; - opt[cur].rep = opt[cur-mlen].rep2; - ZSTD_LOG_PARSER("%d: COPYREP2 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); - } - else - { - opt[cur].rep2 = opt[cur-mlen].rep2; - opt[cur].rep = opt[cur-mlen].rep; - ZSTD_LOG_PARSER("%d: COPYREP3 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); - } - } - - ZSTD_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); - - - - size_t cur_rep; - best_mlen = 0; - - if (!opt[cur].off && opt[cur].mlen != 1) { - cur_rep = opt[cur].rep2; - ZSTD_LOG_PARSER("%d: try REP2 rep2=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); - } - else { - cur_rep = opt[cur].rep; - ZSTD_LOG_PARSER("%d: try REP1 rep=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); - } - - const U32 repIndex = (U32)(current+cur - cur_rep); - const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; - const BYTE* const repMatch = repBase + repIndex; - if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ - if (MEM_read32(inr) == MEM_read32(repMatch)) { - /* repcode detected */ - const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; - mlen = (U32)ZSTD_count_2segments(inr+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; - ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep, cur, opt[cur].off); - - if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) - { - best_mlen = mlen; - best_off = 0; - ZSTD_LOG_PARSER("%d: REP sufficient_len=%d best_mlen=%d best_off=%d last_pos=%d\n", (int)(inr-base), sufficient_len, best_mlen, best_off, last_pos); - last_pos = cur + 1; - goto _storeSequence; - } - - if (opt[cur].mlen == 1) - { - litlen = opt[cur].litlen; - - if (cur > litlen) - { - price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, inr-litlen, 0, mlen - MINMATCH); - ZSTD_LOG_TRY_PRICE("%d: TRY5 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); - } - else - price = ZSTD_getPrice(seqStorePtr, litlen, anchor, 0, mlen - MINMATCH); - } - else - { - litlen = 0; - price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, 0, mlen - MINMATCH); - ZSTD_LOG_TRY_PRICE("%d: TRY7 price=%d cur=%d litlen=0 getprice=%d\n", (int)(inr-base), price, cur, (int)ZSTD_getPrice(seqStorePtr, 0, NULL, 0, mlen - MINMATCH)); - } - - best_mlen = mlen; - if (faster_get_matches) - skip_num = best_mlen; - - ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), mlen, 0, price, litlen, cur - litlen, opt[cur - litlen].price); - - do - { - if (cur + mlen > last_pos || price <= opt[cur + mlen].price) // || ((price == opt[cur + mlen].price) && (opt[cur].mlen == 1) && (cur != litlen))) // at equal price prefer REP instead of MATCH - SET_PRICE(cur + mlen, mlen, 0, litlen, price); - mlen--; - } - while (mlen >= MINMATCH); - } - - - if (faster_get_matches && skip_num > 0) - { - skip_num--; - continue; - } - - - best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; - - match_num = getAllMatches(ctx, inr, ip, iend, maxSearches, mls, matches, best_mlen); - ZSTD_LOG_PARSER("%d: ZSTD_GetAllMatches match_num=%d\n", (int)(inr-base), match_num); - - - if (match_num > 0 && matches[match_num-1].len > sufficient_len) - { - cur -= matches[match_num-1].back; - best_mlen = matches[match_num-1].len; - best_off = matches[match_num-1].off; - last_pos = cur + 1; - goto _storeSequence; - } - - - // set prices using matches at position = cur - for (U32 i = 0; i < match_num; i++) - { - mlen = (i>0) ? matches[i-1].len+1 : best_mlen; - cur2 = cur - matches[i].back; - best_mlen = (cur2 + matches[i].len < ZSTD_OPT_NUM) ? matches[i].len : ZSTD_OPT_NUM - cur2; - - ZSTD_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(inr-base), cur, cur2, matches[i].len, matches[i].off, best_mlen, last_pos); - if (mlen < matches[i].back + 1) - mlen = matches[i].back + 1; - - while (mlen <= best_mlen) - { - if (opt[cur2].mlen == 1) - { - litlen = opt[cur2].litlen; - if (cur2 > litlen) - price = opt[cur2 - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, ip+cur2-litlen, matches[i].off, mlen - MINMATCH); - else - price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[i].off, mlen - MINMATCH); - } - else - { - litlen = 0; - price = opt[cur2].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[i].off, mlen - MINMATCH); - } - - ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); - ZSTD_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); - - if (cur2 + mlen > last_pos || (price < opt[cur2 + mlen].price)) - SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); - - mlen++; - } - } - } // for (skip_num = 0, cur = 1; cur <= last_pos; cur++) - - - best_mlen = opt[last_pos].mlen; - best_off = opt[last_pos].off; - cur = last_pos - best_mlen; - // printf("%d: start=%d best_mlen=%d best_off=%d cur=%d\n", (int)(ip - base), (int)(start - ip), (int)best_mlen, (int)best_off, cur); - - /* store sequence */ -_storeSequence: // cur, last_pos, best_mlen, best_off have to be set - for (U32 i = 1; i <= last_pos; i++) - ZSTD_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); - ZSTD_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-base+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); - - opt[0].mlen = 1; - U32 offset; - - while (1) - { - mlen = opt[cur].mlen; - ZSTD_LOG_PARSER("%d: cur=%d mlen=%d\n", (int)(ip-base), cur, mlen); - offset = opt[cur].off; - opt[cur].mlen = best_mlen; - opt[cur].off = best_off; - best_mlen = mlen; - best_off = offset; - if (mlen > cur) - break; - cur -= mlen; - } - - for (U32 i = 0; i <= last_pos;) - { - ZSTD_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); - i += opt[i].mlen; - } - - cur = 0; - - while (cur < last_pos) - { - ZSTD_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); - mlen = opt[cur].mlen; - if (mlen == 1) { ip++; cur++; continue; } - offset = opt[cur].off; - cur += mlen; - - - U32 litLength = (U32)(ip - anchor); - ZSTD_LOG_ENCODE("%d/%d: ENCODE1 literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); - - if (offset) - { - rep_2 = rep_1; - rep_1 = offset; - } - else - { - if (litLength == 0) - { - best_off = rep_2; - rep_2 = rep_1; - rep_1 = best_off; - } - } - - ZSTD_LOG_ENCODE("%d/%d: ENCODE2 literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); - -#if ZSTD_OPT_DEBUG >= 5 - int ml2; - if (offset) - ml2 = ZSTD_count(ip, ip-offset, iend); - else - ml2 = ZSTD_count(ip, ip-rep_1, iend); - if (ml2 < mlen && ml2 < MINMATCH) { - printf("%d: ERROR iend=%d mlen=%d offset=%d ml2=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset, (int)ml2); exit(0); } - if (ip < anchor) { - printf("%d: ERROR ip < anchor iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } - if (ip - offset < ctx->base) { - printf("%d: ERROR ip - offset < base iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } - if ((int)offset >= (1 << ctx->params.windowLog)) { - printf("%d: offset >= (1 << params.windowLog) iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } - if (mlen < MINMATCH) { - printf("%d: ERROR mlen < MINMATCH iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } - if (ip + mlen > iend) { - printf("%d: ERROR ip + mlen >= iend iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } -#endif - - ZSTD_updatePrice(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); - ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); - anchor = ip = ip + mlen; - } - - - // check immediate repcode - while (anchor <= ilimit) { - const U32 repIndex = (U32)((anchor-base) - rep_2); - const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; - const BYTE* const repMatch = repBase + repIndex; - if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ - if (MEM_read32(anchor) == MEM_read32(repMatch)) { - /* repcode detected we should take it */ - const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; - mlen = (U32)ZSTD_count_2segments(anchor+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; - offset = rep_2; rep_2 = rep_1; rep_1 = offset; /* swap offset history */ - ZSTD_LOG_ENCODE("%d/%d: ENCODE REP literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(anchor-base), (int)(iend-base), (int)(0), (int)best_mlen, (int)(0), (int)rep_1, (int)rep_2); - ZSTD_updatePrice(seqStorePtr, 0, anchor, 0, mlen-MINMATCH); - ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, mlen-MINMATCH); - anchor += mlen; - ip = anchor; - continue; /* faster when present ... (?) */ - } - break; - } - } - - /* Last Literals */ - { - U32 lastLLSize = (U32)(iend - anchor); - ZSTD_LOG_ENCODE("%d: lastLLSize literals=%d\n", (int)(ip-base), (int)(lastLLSize)); - memcpy(seqStorePtr->lit, anchor, lastLLSize); - seqStorePtr->lit += lastLLSize; - } -} From be77f3342dda9ee530ef27f84d6df81fedfadaac Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 9 Feb 2016 23:00:41 +0100 Subject: [PATCH 066/113] Revert "Revert "ZSTD_compressBlock_opt_extDict_generic"" This reverts commit 2b714dfd2642d30e5b6ea84a61b148d8bc790a61. --- lib/zstd_compress.c | 6 +- lib/zstd_opt.c | 492 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 492 insertions(+), 6 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index ac53662a0..407b3e8df 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -1927,12 +1927,12 @@ static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, static void ZSTD_compressBlock_opt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2); + ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0, 2); } static void ZSTD_compressBlock_opt_bt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2); + ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1, 2); } @@ -2106,10 +2106,12 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t case ZSTD_greedy: case ZSTD_lazy: case ZSTD_lazy2: + case ZSTD_opt: ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.searchLength); break; case ZSTD_btlazy2: + case ZSTD_opt_bt: ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength); break; diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 576ee133e..bd7abfc71 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -178,6 +178,9 @@ MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, U32 litLength, const B +/* ************************************* +* Binary Tree search +***************************************/ FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ U32 ZSTD_insertBtAndGetAllMatches ( ZSTD_CCtx* zc, @@ -298,7 +301,39 @@ FORCE_INLINE U32 ZSTD_BtGetAllMatches_selectMLS ( } } +/** Tree updater, providing best match */ +FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ +size_t ZSTD_BtGetAllMatches_extDict ( + ZSTD_CCtx* zc, + const BYTE* const ip, const BYTE* const iLimit, + const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, U32 minml) +{ + if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */ + ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls); + return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 1, matches, minml); +} + +FORCE_INLINE U32 ZSTD_BtGetAllMatches_selectMLS_extDict ( + ZSTD_CCtx* zc, /* Index table will be updated */ + const BYTE* ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, + const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, U32 minml) +{ + if (iLowLimit) {}; // skip warnings + + switch(matchLengthSearch) + { + default : + case 4 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 4, matches, minml); + case 5 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 5, matches, minml); + case 6 : return ZSTD_BtGetAllMatches_extDict(zc, ip, iHighLimit, maxNbAttempts, 6, matches, minml); + } +} + + +/* *********************** +* Hash Chain +*************************/ FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ U32 ZSTD_HcGetAllMatches_generic ( ZSTD_CCtx* zc, /* Index table will be updated */ @@ -313,6 +348,7 @@ U32 ZSTD_HcGetAllMatches_generic ( const U32 dictLimit = zc->dictLimit; const BYTE* const prefixStart = base + dictLimit; const BYTE* const dictEnd = dictBase + dictLimit; + const BYTE* const dictStart = dictBase + zc->lowLimit; const U32 lowLimit = zc->lowLimit; const U32 current = (U32)(ip-base); const U32 minChain = current > chainSize ? current - chainSize : 0; @@ -343,7 +379,7 @@ U32 ZSTD_HcGetAllMatches_generic ( if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */ currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iHighLimit, dictEnd, prefixStart) + MINMATCH; if (currentMl > 0) { - while ((match-back > dictBase) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ + while ((match-back > dictStart) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ currentMl += back; } } @@ -381,6 +417,19 @@ FORCE_INLINE U32 ZSTD_HcGetAllMatches_selectMLS ( } } +FORCE_INLINE U32 ZSTD_HcGetAllMatches_selectMLS_extDict ( + ZSTD_CCtx* zc, + const BYTE* ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, + const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, U32 minml) +{ + switch(matchLengthSearch) + { + default : + case 4 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLowLimit, iHighLimit, maxNbAttempts, 4, 1, matches, minml); + case 5 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLowLimit, iHighLimit, maxNbAttempts, 5, 1, matches, minml); + case 6 : return ZSTD_HcGetAllMatches_generic(zc, ip, iLowLimit, iHighLimit, maxNbAttempts, 6, 1, matches, minml); + } +} /* ******************************* @@ -465,9 +514,9 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); if (!last_pos && !match_num) { ip++; continue; } - opt[0].rep = rep_1; - opt[0].rep2 = rep_2; - opt[0].mlen = 1; + opt[0].rep = rep_1; + opt[0].rep2 = rep_2; + opt[0].mlen = 1; if (match_num && matches[match_num-1].len > sufficient_len) { @@ -804,3 +853,438 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set +FORCE_INLINE +void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, + const void* src, size_t srcSize, + const U32 searchMethod, const U32 depth) +{ + seqStore_t* seqStorePtr = &(ctx->seqStore); + const BYTE* const istart = (const BYTE*)src; + const BYTE* ip = istart; + const BYTE* anchor = istart; + const BYTE* const iend = istart + srcSize; + const BYTE* const ilimit = iend - 8; + const BYTE* const base = ctx->base; + const U32 dictLimit = ctx->dictLimit; + const BYTE* const prefixStart = base + dictLimit; + const BYTE* const dictBase = ctx->dictBase; + const BYTE* const dictEnd = dictBase + dictLimit; + + U32 rep_2=REPCODE_STARTVALUE, rep_1=REPCODE_STARTVALUE; + const U32 maxSearches = 1U << ctx->params.searchLog; + const U32 mls = ctx->params.searchLength; + + typedef U32 (*getAllMatches_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLowLimit, const BYTE* iHighLimit, + U32 maxNbAttempts, U32 matchLengthSearch, ZSTD_match_t* matches, U32 minml); + getAllMatches_f getAllMatches = searchMethod ? ZSTD_BtGetAllMatches_selectMLS_extDict : ZSTD_HcGetAllMatches_selectMLS_extDict; + + ZSTD_optimal_t opt[ZSTD_OPT_NUM+4]; + ZSTD_match_t matches[ZSTD_OPT_NUM+1]; + const uint8_t *inr; + U32 skip_num, cur, cur2, match_num, last_pos, litlen, price; + + const U32 sufficient_len = ctx->params.sufficientLength; + const U32 faster_get_matches = (ctx->params.strategy == ZSTD_opt); + + + /* init */ + ZSTD_resetSeqStore(seqStorePtr); + if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE; + + + /* Match Loop */ + while (ip < ilimit) { + U32 mlen=0; + U32 best_mlen=0; + U32 best_off=0; + U32 current = (U32)(ip-base); + memset(opt, 0, sizeof(ZSTD_optimal_t)); + last_pos = 0; + inr = ip; + opt[0].litlen = (U32)(ip - anchor); + + + /* check repCode */ + { + const U32 repIndex = (U32)(current+1 - rep_1); + const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; + const BYTE* const repMatch = repBase + repIndex; + if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ + if (MEM_read32(ip+1) == MEM_read32(repMatch)) { + /* repcode detected we should take it */ + const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; + mlen = (U32)ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; + + ZSTD_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)(ip-base), (int)rep_1, (int)mlen); + if (depth==0 || mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) { + ip+=1; best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; + goto _storeSequence; + } + + litlen = opt[0].litlen + 1; + do + { + price = ZSTD_getPrice(seqStorePtr, litlen, anchor, 0, mlen - MINMATCH); + if (mlen + 1 > last_pos || price < opt[mlen + 1].price) + SET_PRICE(mlen + 1, mlen, 0, litlen, price); + mlen--; + } + while (mlen >= MINMATCH); + } + } + + best_mlen = (last_pos) ? last_pos : MINMATCH; + + if (faster_get_matches && last_pos) + match_num = 0; + else + match_num = getAllMatches(ctx, ip, ip, iend, maxSearches, mls, matches, best_mlen); /* first search (depth 0) */ + + ZSTD_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); + if (!last_pos && !match_num) { ip++; continue; } + + opt[0].rep = rep_1; + opt[0].rep2 = rep_2; + opt[0].mlen = 1; + + if (match_num && matches[match_num-1].len > sufficient_len) + { + best_mlen = matches[match_num-1].len; + best_off = matches[match_num-1].off; + cur = 0; + last_pos = 1; + goto _storeSequence; + } + + // set prices using matches at position = 0 + for (U32 i = 0; i < match_num; i++) + { + mlen = (i>0) ? matches[i-1].len+1 : best_mlen; + best_mlen = (matches[i].len < ZSTD_OPT_NUM) ? matches[i].len : ZSTD_OPT_NUM; + ZSTD_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(ip-base), matches[i].len, matches[i].off, (int)best_mlen, (int)last_pos); + litlen = opt[0].litlen; + while (mlen <= best_mlen) + { + price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[i].off, mlen - MINMATCH); + if (mlen > last_pos || price < opt[mlen].price) + SET_PRICE(mlen, mlen, matches[i].off, litlen, price); + mlen++; + } + } + + if (last_pos < MINMATCH) { + // ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */ + ip++; continue; + } + + + // check further positions + for (skip_num = 0, cur = 1; cur <= last_pos; cur++) + { + inr = ip + cur; + + if (opt[cur-1].mlen == 1) + { + litlen = opt[cur-1].litlen + 1; + if (cur > litlen) + { + price = opt[cur - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-litlen); + ZSTD_LOG_TRY_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); + } + else + price = ZSTD_getLiteralPrice(seqStorePtr, litlen, anchor); + } + else + { + litlen = 1; + price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1); + ZSTD_LOG_TRY_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)(inr-base), price, cur, litlen, (int)ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1)); + } + + ZSTD_LOG_TRY_PRICE("%d: TRY4 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur, opt[cur].price); + + if (cur > last_pos || price <= opt[cur].price) // || ((price == opt[cur].price) && (opt[cur-1].mlen == 1) && (cur != litlen))) + SET_PRICE(cur, 1, 0, litlen, price); + + if (cur == last_pos) break; + + if (inr > ilimit) // last match must start at a minimum distance of 8 from oend + continue; + + mlen = opt[cur].mlen; + + if (opt[cur-mlen].off) + { + opt[cur].rep2 = opt[cur-mlen].rep; + opt[cur].rep = opt[cur-mlen].off; + ZSTD_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); + } + else + { + if (cur!=mlen && opt[cur-mlen].litlen == 0) + { + opt[cur].rep2 = opt[cur-mlen].rep; + opt[cur].rep = opt[cur-mlen].rep2; + ZSTD_LOG_PARSER("%d: COPYREP2 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); + } + else + { + opt[cur].rep2 = opt[cur-mlen].rep2; + opt[cur].rep = opt[cur-mlen].rep; + ZSTD_LOG_PARSER("%d: COPYREP3 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); + } + } + + ZSTD_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); + + + + size_t cur_rep; + best_mlen = 0; + + if (!opt[cur].off && opt[cur].mlen != 1) { + cur_rep = opt[cur].rep2; + ZSTD_LOG_PARSER("%d: try REP2 rep2=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); + } + else { + cur_rep = opt[cur].rep; + ZSTD_LOG_PARSER("%d: try REP1 rep=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); + } + + const U32 repIndex = (U32)(current+cur - cur_rep); + const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; + const BYTE* const repMatch = repBase + repIndex; + if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ + if (MEM_read32(inr) == MEM_read32(repMatch)) { + /* repcode detected */ + const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; + mlen = (U32)ZSTD_count_2segments(inr+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; + ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep, cur, opt[cur].off); + + if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) + { + best_mlen = mlen; + best_off = 0; + ZSTD_LOG_PARSER("%d: REP sufficient_len=%d best_mlen=%d best_off=%d last_pos=%d\n", (int)(inr-base), sufficient_len, best_mlen, best_off, last_pos); + last_pos = cur + 1; + goto _storeSequence; + } + + if (opt[cur].mlen == 1) + { + litlen = opt[cur].litlen; + + if (cur > litlen) + { + price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, inr-litlen, 0, mlen - MINMATCH); + ZSTD_LOG_TRY_PRICE("%d: TRY5 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); + } + else + price = ZSTD_getPrice(seqStorePtr, litlen, anchor, 0, mlen - MINMATCH); + } + else + { + litlen = 0; + price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, 0, mlen - MINMATCH); + ZSTD_LOG_TRY_PRICE("%d: TRY7 price=%d cur=%d litlen=0 getprice=%d\n", (int)(inr-base), price, cur, (int)ZSTD_getPrice(seqStorePtr, 0, NULL, 0, mlen - MINMATCH)); + } + + best_mlen = mlen; + if (faster_get_matches) + skip_num = best_mlen; + + ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), mlen, 0, price, litlen, cur - litlen, opt[cur - litlen].price); + + do + { + if (cur + mlen > last_pos || price <= opt[cur + mlen].price) // || ((price == opt[cur + mlen].price) && (opt[cur].mlen == 1) && (cur != litlen))) // at equal price prefer REP instead of MATCH + SET_PRICE(cur + mlen, mlen, 0, litlen, price); + mlen--; + } + while (mlen >= MINMATCH); + } + + + if (faster_get_matches && skip_num > 0) + { + skip_num--; + continue; + } + + + best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; + + match_num = getAllMatches(ctx, inr, ip, iend, maxSearches, mls, matches, best_mlen); + ZSTD_LOG_PARSER("%d: ZSTD_GetAllMatches match_num=%d\n", (int)(inr-base), match_num); + + + if (match_num > 0 && matches[match_num-1].len > sufficient_len) + { + cur -= matches[match_num-1].back; + best_mlen = matches[match_num-1].len; + best_off = matches[match_num-1].off; + last_pos = cur + 1; + goto _storeSequence; + } + + + // set prices using matches at position = cur + for (U32 i = 0; i < match_num; i++) + { + mlen = (i>0) ? matches[i-1].len+1 : best_mlen; + cur2 = cur - matches[i].back; + best_mlen = (cur2 + matches[i].len < ZSTD_OPT_NUM) ? matches[i].len : ZSTD_OPT_NUM - cur2; + + ZSTD_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(inr-base), cur, cur2, matches[i].len, matches[i].off, best_mlen, last_pos); + if (mlen < matches[i].back + 1) + mlen = matches[i].back + 1; + + while (mlen <= best_mlen) + { + if (opt[cur2].mlen == 1) + { + litlen = opt[cur2].litlen; + if (cur2 > litlen) + price = opt[cur2 - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, ip+cur2-litlen, matches[i].off, mlen - MINMATCH); + else + price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[i].off, mlen - MINMATCH); + } + else + { + litlen = 0; + price = opt[cur2].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[i].off, mlen - MINMATCH); + } + + ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); + ZSTD_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); + + if (cur2 + mlen > last_pos || (price < opt[cur2 + mlen].price)) + SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); + + mlen++; + } + } + } // for (skip_num = 0, cur = 1; cur <= last_pos; cur++) + + + best_mlen = opt[last_pos].mlen; + best_off = opt[last_pos].off; + cur = last_pos - best_mlen; + // printf("%d: start=%d best_mlen=%d best_off=%d cur=%d\n", (int)(ip - base), (int)(start - ip), (int)best_mlen, (int)best_off, cur); + + /* store sequence */ +_storeSequence: // cur, last_pos, best_mlen, best_off have to be set + for (U32 i = 1; i <= last_pos; i++) + ZSTD_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); + ZSTD_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-base+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); + + opt[0].mlen = 1; + U32 offset; + + while (1) + { + mlen = opt[cur].mlen; + ZSTD_LOG_PARSER("%d: cur=%d mlen=%d\n", (int)(ip-base), cur, mlen); + offset = opt[cur].off; + opt[cur].mlen = best_mlen; + opt[cur].off = best_off; + best_mlen = mlen; + best_off = offset; + if (mlen > cur) + break; + cur -= mlen; + } + + for (U32 i = 0; i <= last_pos;) + { + ZSTD_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); + i += opt[i].mlen; + } + + cur = 0; + + while (cur < last_pos) + { + ZSTD_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); + mlen = opt[cur].mlen; + if (mlen == 1) { ip++; cur++; continue; } + offset = opt[cur].off; + cur += mlen; + + + U32 litLength = (U32)(ip - anchor); + ZSTD_LOG_ENCODE("%d/%d: ENCODE1 literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); + + if (offset) + { + rep_2 = rep_1; + rep_1 = offset; + } + else + { + if (litLength == 0) + { + best_off = rep_2; + rep_2 = rep_1; + rep_1 = best_off; + } + } + + ZSTD_LOG_ENCODE("%d/%d: ENCODE2 literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); + +#if ZSTD_OPT_DEBUG >= 5 + int ml2; + if (offset) + ml2 = ZSTD_count(ip, ip-offset, iend); + else + ml2 = ZSTD_count(ip, ip-rep_1, iend); + if (ml2 < mlen && ml2 < MINMATCH) { + printf("%d: ERROR iend=%d mlen=%d offset=%d ml2=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset, (int)ml2); exit(0); } + if (ip < anchor) { + printf("%d: ERROR ip < anchor iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } + if (ip - offset < ctx->base) { + printf("%d: ERROR ip - offset < base iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } + if ((int)offset >= (1 << ctx->params.windowLog)) { + printf("%d: offset >= (1 << params.windowLog) iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } + if (mlen < MINMATCH) { + printf("%d: ERROR mlen < MINMATCH iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } + if (ip + mlen > iend) { + printf("%d: ERROR ip + mlen >= iend iend=%d mlen=%d offset=%d\n", (int)(ip - base), (int)(iend - ip), (int)mlen, (int)offset); exit(0); } +#endif + + ZSTD_updatePrice(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); + ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); + anchor = ip = ip + mlen; + } + + + // check immediate repcode + while (anchor <= ilimit) { + const U32 repIndex = (U32)((anchor-base) - rep_2); + const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; + const BYTE* const repMatch = repBase + repIndex; + if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ + if (MEM_read32(anchor) == MEM_read32(repMatch)) { + /* repcode detected we should take it */ + const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; + mlen = (U32)ZSTD_count_2segments(anchor+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; + offset = rep_2; rep_2 = rep_1; rep_1 = offset; /* swap offset history */ + ZSTD_LOG_ENCODE("%d/%d: ENCODE REP literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(anchor-base), (int)(iend-base), (int)(0), (int)best_mlen, (int)(0), (int)rep_1, (int)rep_2); + ZSTD_updatePrice(seqStorePtr, 0, anchor, 0, mlen-MINMATCH); + ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, mlen-MINMATCH); + anchor += mlen; + ip = anchor; + continue; /* faster when present ... (?) */ + } + break; + } + } + + /* Last Literals */ + { + U32 lastLLSize = (U32)(iend - anchor); + ZSTD_LOG_ENCODE("%d: lastLLSize literals=%d\n", (int)(ip-base), (int)(lastLLSize)); + memcpy(seqStorePtr->lit, anchor, lastLLSize); + seqStorePtr->lit += lastLLSize; + } +} From ce6730a7402e46444495208a88095f62ab7d7bc9 Mon Sep 17 00:00:00 2001 From: inikep Date: Tue, 9 Feb 2016 23:26:30 +0100 Subject: [PATCH 067/113] fix for ZSTD_HcGetAllMatches_generic --- lib/zstd_opt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index bd7abfc71..8a9b1e2b1 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -364,7 +364,7 @@ U32 ZSTD_HcGetAllMatches_generic ( while ((matchIndex>lowLimit) && (nbAttempts)) { size_t currentMl=0; - U32 back = 0; + int back = 0; nbAttempts--; if ((!extDict) || matchIndex >= dictLimit) { match = base + matchIndex; From 70e8c389f1099d4601c6b5d3c14abf79b76aa732 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 10 Feb 2016 13:37:52 +0100 Subject: [PATCH 068/113] Refactoring for portability --- lib/zstd_compress.c | 81 +++---- lib/zstd_opt.c | 511 +++++++++++++++++------------------------- lib/zstd_static.h | 9 +- programs/paramgrill.c | 240 ++++++++------------ 4 files changed, 345 insertions(+), 496 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 47f655946..7f8385b37 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -88,31 +88,33 @@ typedef struct { BYTE* matchLength; BYTE* dumpsStart; BYTE* dumps; + /* opt */ U32* matchLengthFreq; U32* litLengthFreq; U32* litFreq; U32* offCodeFreq; - U32 matchLengthSum; - U32 litLengthSum; - U32 litSum; - U32 offCodeSum; + U32 matchLengthSum; + U32 litLengthSum; + U32 litSum; + U32 offCodeSum; } seqStore_t; static void ZSTD_resetFreqs(seqStore_t* ssPtr) { - ssPtr->matchLengthSum = (1<litLengthSum = (1<matchLengthSum = 512; // (1<litLengthSum = 256; // (1<litSum = (1<offCodeSum = (1<litFreq[i] = 1; - for (int i=0; i<=MaxLL; i++) - ssPtr->litLengthFreq[i] = 1; - for (int i=0; i<=MaxML; i++) - ssPtr->matchLengthFreq[i] = 1; - for (int i=0; i<=MaxOff; i++) - ssPtr->offCodeFreq[i] = 1; + for (u=0; u<=MaxLit; u++) + ssPtr->litFreq[u] = 1; + for (u=0; u<=MaxLL; u++) + ssPtr->litLengthFreq[u] = 1; + for (u=0; u<=MaxML; u++) + ssPtr->matchLengthFreq[u] = 1; + for (u=0; u<=MaxOff; u++) + ssPtr->offCodeFreq[u] = 1; } static void ZSTD_resetSeqStore(seqStore_t* ssPtr) @@ -173,7 +175,9 @@ size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) static unsigned ZSTD_highbit(U32 val); -/** ZSTD_validateParams +#define CLAMP(val,min,max) { if (valmax) val=max; } + +/** ZSTD_validateParams() correct params value to remain within authorized range optimize for srcSize if srcSize > 0 */ void ZSTD_validateParams(ZSTD_parameters* params) @@ -182,25 +186,21 @@ void ZSTD_validateParams(ZSTD_parameters* params) /* validate params */ if (MEM_32bits()) if (params->windowLog > 25) params->windowLog = 25; /* 32 bits mode cannot flush > 24 bits */ - if (params->windowLog > ZSTD_WINDOWLOG_MAX) params->windowLog = ZSTD_WINDOWLOG_MAX; - if (params->windowLog < ZSTD_WINDOWLOG_MIN) params->windowLog = ZSTD_WINDOWLOG_MIN; + CLAMP(params->windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); + CLAMP(params->contentLog, ZSTD_CONTENTLOG_MIN, ZSTD_CONTENTLOG_MAX); + CLAMP(params->hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); + CLAMP(params->searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); + CLAMP(params->searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX); + CLAMP(params->sufficientLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX); + if ((U32)params->strategy>(U32)ZSTD_opt_bt) params->strategy = ZSTD_opt_bt; /* correct params, to use less memory */ if ((params->srcSize > 0) && (params->srcSize < (1<srcSize)-1) + 1; if (params->windowLog > srcLog) params->windowLog = srcLog; } - if (params->windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) params->windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */ if (params->contentLog > params->windowLog+btPlus) params->contentLog = params->windowLog+btPlus; /* <= ZSTD_CONTENTLOG_MAX */ - if (params->contentLog < ZSTD_CONTENTLOG_MIN) params->contentLog = ZSTD_CONTENTLOG_MIN; - if (params->hashLog > ZSTD_HASHLOG_MAX) params->hashLog = ZSTD_HASHLOG_MAX; - if (params->hashLog < ZSTD_HASHLOG_MIN) params->hashLog = ZSTD_HASHLOG_MIN; - if (params->searchLog > ZSTD_SEARCHLOG_MAX) params->searchLog = ZSTD_SEARCHLOG_MAX; - if (params->searchLog < ZSTD_SEARCHLOG_MIN) params->searchLog = ZSTD_SEARCHLOG_MIN; - if (params->searchLength> ZSTD_SEARCHLENGTH_MAX) params->searchLength = ZSTD_SEARCHLENGTH_MAX; - if (params->searchLength< ZSTD_SEARCHLENGTH_MIN) params->searchLength = ZSTD_SEARCHLENGTH_MIN; - if ((U32)params->strategy>(U32)ZSTD_opt_bt) params->strategy = ZSTD_opt_bt; } @@ -234,18 +234,19 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, zc->lowLimit = 0; zc->params = params; zc->blockSize = blockSize; - zc->seqStore.offsetStart = (U32*) (zc->seqStore.buffer); + + zc->seqStore.litFreq = (U32*) (zc->seqStore.buffer); + zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (1<seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (1<seqStore.offsetStart = zc->seqStore.offCodeFreq + (1<seqStore.offCodeStart = (BYTE*) (zc->seqStore.offsetStart + (blockSize>>2)); zc->seqStore.litStart = zc->seqStore.offCodeStart + (blockSize>>2); zc->seqStore.litLengthStart = zc->seqStore.litStart + blockSize; zc->seqStore.matchLengthStart = zc->seqStore.litLengthStart + (blockSize>>2); zc->seqStore.dumpsStart = zc->seqStore.matchLengthStart + (blockSize>>2); - BYTE* dumpsEnd= zc->seqStore.dumpsStart + (blockSize>>2); - zc->seqStore.litFreq = (U32*)(dumpsEnd); - zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (1<seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (1<seqStore.XXX = zc->seqStore.offCodeFreq + (1<seqStore.XXX = zc->seqStore.dumpsStart + (blockSize>>4); zc->hbSize = 0; zc->stage = 0; @@ -562,7 +563,6 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, const size_t maxCSize = srcSize - minGain; BYTE* seqHead; - /* Compress literals */ { size_t cSize; @@ -1194,8 +1194,8 @@ void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx, /* ************************************* * Binary Tree search ***************************************/ -/** ZSTD_insertBt1 : add one or multiple positions to tree -* @ip : assumed <= iend-8 +/** ZSTD_insertBt1() : add one or multiple positions to tree +* ip : assumed <= iend-8 * @return : nb of positions added */ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares, U32 extDict) @@ -1230,9 +1230,9 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co while (nbCompares-- && (matchIndex > windowLow)) { U32* nextPtr = bt + 2*(matchIndex & btMask); - const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */ size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ + const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */ if (matchIndex == predictedSmall) { /* no need to check length, result known */ *smallerPtr = matchIndex; @@ -1242,7 +1242,6 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co predictedSmall = predictPtr[1] + (predictPtr[1]>0); continue; } - if (matchIndex == predictedLarge) { *largerPtr = matchIndex; if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */ @@ -2314,8 +2313,9 @@ size_t ZSTD_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSi } -/*- Pre-defined compression levels -*/ +/*-===== Pre-defined compression levels =====-*/ +#define ZSTD_MAX_CLEVEL 25 unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { @@ -2345,7 +2345,8 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 0, 22, 20, 22, 4, 4, ZSTD_lazy2 }, /* level 21 = 11 + L=4 */ // 41902762 lazy1=42087013 norep1=42911693 { 0, 0, 23, 21, 22, 5, 4, ZSTD_btlazy2 }, /* level 22 = 16 + L=4 */ // 41233150 btlazy1=41560211 norep1=42322286 { 0, 32, 23, 21, 22, 5, 4, ZSTD_opt }, /* level 23 */ - { 0, 32, 23, 21, 22, 5, 4, ZSTD_opt_bt }, /* level 24 */ + { 0, 32, 23, 21, 22, 5, 4, ZSTD_opt_bt }, /* level 24 = 16 + btopt */ + { 0, 64, 26, 27, 25, 10, 4, ZSTD_opt_bt }, /* level 25 = 20 + btopt */ }, { /* for srcSize <= 256 KB */ /* SL, W, C, H, S, L, strat */ diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 8a9b1e2b1..43ae8b570 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -16,7 +16,7 @@ typedef struct U32 litlen; U32 rep; U32 rep2; -} ZSTD_optimal_t; +} ZSTD_optimal_t; #define ZSTD_OPT_DEBUG 0 // 1 = tableID=0; 5 = check encoded sequences @@ -24,11 +24,11 @@ typedef struct #if 1 #define ZSTD_LOG_PARSER(fmt, args...) ;// printf(fmt, ##args) #define ZSTD_LOG_PRICE(fmt, args...) ;//printf(fmt, ##args) - #define ZSTD_LOG_ENCODE(fmt, args...) ;//printf(fmt, ##args) + #define ZSTD_LOG_ENCODE(fmt, args...) ;//printf(fmt, ##args) #else #define ZSTD_LOG_PARSER(fmt, args...) printf(fmt, ##args) #define ZSTD_LOG_PRICE(fmt, args...) printf(fmt, ##args) - #define ZSTD_LOG_ENCODE(fmt, args...) printf(fmt, ##args) + #define ZSTD_LOG_ENCODE(fmt, args...) printf(fmt, ##args) #endif #define ZSTD_LOG_TRY_PRICE(fmt, args...) ;//printf(fmt, ##args) @@ -37,46 +37,23 @@ typedef struct #define ZSTD_FREQ_THRESHOLD (256) -// log2_32 is from http://stackoverflow.com/questions/11376288/fast-computing-of-log2-for-64-bit-integers -const U32 tab32[32] = { - 0, 9, 1, 10, 13, 21, 2, 29, - 11, 14, 16, 18, 22, 25, 3, 30, - 8, 12, 20, 28, 15, 17, 24, 7, - 19, 27, 23, 6, 26, 5, 4, 31}; - -U32 log2_32 (U32 value) -{ - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; - return tab32[(U32)(value*0x07C4ACDD) >> 27]; -} - FORCE_INLINE U32 ZSTD_getLiteralPriceReal(seqStore_t* seqStorePtr, U32 litLength, const BYTE* literals) { U32 price = 0; if (litLength > 0) { + U32 freq, u; /* literals */ - for (U32 i=0; i < litLength; i++) - price += log2_32(seqStorePtr->litSum) - log2_32(seqStorePtr->litFreq[literals[i]]); + for (u=0; u < litLength; u++) + price += ZSTD_highbit(seqStorePtr->litSum) - ZSTD_highbit(seqStorePtr->litFreq[literals[u]]); /* literal Length */ - U32 freq; - if (litLength >= MaxLL) { - freq = seqStorePtr->litLengthFreq[MaxLL]; - if (litLength<255 + MaxLL) { - price += 8; - } else { - price += 8; - if (litLength < (1<<15)) price += 16; else price += 24; - } } - else - freq = seqStorePtr->litLengthFreq[litLength]; - price += log2_32(seqStorePtr->litLengthSum) - log2_32(freq); + price += ((litLength >= MaxLL)*8) + ((litLength >= 255+MaxLL)*16) + ((litLength>=(1<<15))*8); + if (litLength >= MaxLL) litLength = MaxLL; + freq = seqStorePtr->litLengthFreq[litLength]; + price += ZSTD_highbit(seqStorePtr->litLengthSum) - ZSTD_highbit(freq); + /* note : seems that using matchLengthSum (litSum > ZSTD_FREQ_THRESHOLD) + if (seqStorePtr->litSum > ZSTD_FREQ_THRESHOLD) return ZSTD_getLiteralPriceReal(seqStorePtr, litLength, literals); - + /* backup eval */ return 1 + (litLength<<3); } @@ -96,25 +73,18 @@ FORCE_INLINE U32 ZSTD_getLiteralPrice(seqStore_t* seqStorePtr, U32 litLength, co FORCE_INLINE U32 ZSTD_getMatchPriceReal(seqStore_t* seqStorePtr, U32 offset, U32 matchLength) { - /* match offset */ - BYTE offCode = (BYTE)ZSTD_highbit(offset) + 1; - if (offset==0) - offCode = 0; - U32 price = log2_32(seqStorePtr->offCodeSum) - log2_32(seqStorePtr->offCodeFreq[offCode]); + U32 freq; + + /* offset */ + BYTE offCode = offset ? (BYTE)ZSTD_highbit(offset) + 1 : 0; + U32 price = ZSTD_highbit(seqStorePtr->offCodeSum) - ZSTD_highbit(seqStorePtr->offCodeFreq[offCode]); price += offCode; /* match Length */ - U32 freq; - if (matchLength >= MaxML) { - freq = seqStorePtr->matchLengthFreq[MaxML]; - if (matchLength < 255+MaxML) { - price += 8; - } else { - price += 8; - if (matchLength < (1<<15)) price += 16; else price += 24; - } } - else freq = seqStorePtr->matchLengthFreq[matchLength]; - price += log2_32(seqStorePtr->matchLengthSum) - log2_32(freq); + price += ((matchLength >= MaxML)*8) + ((matchLength >= 255+MaxML)*16) + ((matchLength>=(1<<15))*8); + if (matchLength >= MaxML) matchLength = MaxML; + freq = seqStorePtr->matchLengthFreq[matchLength]; + price += ZSTD_highbit(seqStorePtr->matchLengthSum) - ZSTD_highbit(freq); return price; } @@ -124,7 +94,7 @@ FORCE_INLINE U32 ZSTD_getPrice(seqStore_t* seqStorePtr, U32 litLength, const BYT { if (seqStorePtr->litSum > ZSTD_FREQ_THRESHOLD) return ZSTD_getLiteralPriceReal(seqStorePtr, litLength, literals) + ZSTD_getMatchPriceReal(seqStorePtr, offset, matchLength); - + return (litLength<<3) + ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); } @@ -132,6 +102,7 @@ FORCE_INLINE U32 ZSTD_getPrice(seqStore_t* seqStorePtr, U32 litLength, const BYT MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength) { + U32 u; #if 0 static const BYTE* g_start = NULL; if (g_start==NULL) g_start = literals; @@ -141,14 +112,14 @@ MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, U32 litLength, const B #endif /* literals */ seqStorePtr->litSum += litLength; - for (U32 i=0; i < litLength; i++) - seqStorePtr->litFreq[literals[i]]++; - + for (u=0; u < litLength; u++) + seqStorePtr->litFreq[literals[u]]++; + /* literal Length */ seqStorePtr->litLengthSum++; if (litLength >= MaxLL) seqStorePtr->litLengthFreq[MaxLL]++; - else + else seqStorePtr->litLengthFreq[litLength]++; /* match offset */ @@ -161,7 +132,7 @@ MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, U32 litLength, const B seqStorePtr->matchLengthSum++; if (matchLength >= MaxML) seqStorePtr->matchLengthFreq[MaxML]++; - else + else seqStorePtr->matchLengthFreq[matchLength]++; } @@ -211,8 +182,8 @@ U32 ZSTD_insertBtAndGetAllMatches ( U32 matchEndIdx = current+8; U32 dummy32; /* to be nullified at the end */ U32 mnum = 0; - - bestLength = 0; + + bestLength = MINMATCH-1; hashTable[h] = current; /* Update Hash Table */ while (nbCompares-- && (matchIndex > windowLow)) { @@ -232,18 +203,13 @@ U32 ZSTD_insertBtAndGetAllMatches ( } if (matchLength > bestLength) { - if (matchLength > matchEndIdx - matchIndex) - matchEndIdx = matchIndex + (U32)matchLength; - { - if (matchLength >= MINMATCH) { - bestLength = matchLength; - matches[mnum].off = current - matchIndex; - matches[mnum].len = (U32)matchLength; - matches[mnum].back = 0; - mnum++; - } - if (matchLength > ZSTD_OPT_NUM) break; - } + if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; + bestLength = matchLength; + matches[mnum].off = current - matchIndex; + matches[mnum].len = (U32)matchLength; + matches[mnum].back = 0; + mnum++; + if (matchLength > ZSTD_OPT_NUM) break; if (ip+matchLength == iend) /* equal : no way to know if inf or sup */ break; /* drop, to guarantee consistency (miss a little bit of compression) */ } @@ -262,8 +228,7 @@ U32 ZSTD_insertBtAndGetAllMatches ( if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */ largerPtr = nextPtr; matchIndex = nextPtr[0]; - } - } + } } *smallerPtr = *largerPtr = 0; @@ -290,8 +255,7 @@ FORCE_INLINE U32 ZSTD_BtGetAllMatches_selectMLS ( const BYTE* ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, U32 minml) { - if (iLowLimit) {}; // skip warnings - + (void)iLowLimit; /* unused */ switch(matchLengthSearch) { default : @@ -303,7 +267,7 @@ FORCE_INLINE U32 ZSTD_BtGetAllMatches_selectMLS ( /** Tree updater, providing best match */ FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ -size_t ZSTD_BtGetAllMatches_extDict ( +U32 ZSTD_BtGetAllMatches_extDict ( ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iLimit, const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, U32 minml) @@ -385,14 +349,14 @@ U32 ZSTD_HcGetAllMatches_generic ( } /* save best solution */ - if (currentMl > minml) { - minml = currentMl; + if (currentMl > minml) { + minml = currentMl; matches[mnum].off = current - matchIndex; matches[mnum].len = (U32)currentMl; matches[mnum].back = back; mnum++; if (currentMl > ZSTD_OPT_NUM) break; - if (ip+currentMl == iHighLimit) break; /* best possible, and avoid read overflow*/ + if (ip+currentMl == iHighLimit) break; /* best possible, and avoid read overflow*/ } if (matchIndex <= minChain) break; @@ -458,11 +422,11 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_optimal_t opt[ZSTD_OPT_NUM+4]; ZSTD_match_t matches[ZSTD_OPT_NUM+1]; - const uint8_t *inr; + const BYTE* inr; U32 skip_num, cur, cur2, match_num, last_pos, litlen, price; const U32 sufficient_len = ctx->params.sufficientLength; - const U32 faster_get_matches = (ctx->params.strategy == ZSTD_opt); + const U32 faster_get_matches = (ctx->params.strategy == ZSTD_opt); /* init */ @@ -472,6 +436,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, /* Match Loop */ while (ip < ilimit) { + U32 u; U32 mlen=0; U32 best_mlen=0; U32 best_off=0; @@ -485,7 +450,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (MEM_read32(ip+1) == MEM_read32(ip+1 - rep_1)) { /* repcode : we take it */ mlen = (U32)ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-rep_1, iend) + MINMATCH; - + ZSTD_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)(ip-base), (int)rep_1, (int)mlen); if (depth==0 || mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) { ip+=1; best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; @@ -505,7 +470,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, best_mlen = (last_pos) ? last_pos : MINMATCH; - + if (faster_get_matches && last_pos) match_num = 0; else @@ -518,8 +483,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, opt[0].rep2 = rep_2; opt[0].mlen = 1; - if (match_num && matches[match_num-1].len > sufficient_len) - { + if (match_num && matches[match_num-1].len > sufficient_len) { best_mlen = matches[match_num-1].len; best_off = matches[match_num-1].off; cur = 0; @@ -528,50 +492,45 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } // set prices using matches at position = 0 - for (U32 i = 0; i < match_num; i++) - { - mlen = (i>0) ? matches[i-1].len+1 : best_mlen; - best_mlen = (matches[i].len < ZSTD_OPT_NUM) ? matches[i].len : ZSTD_OPT_NUM; + for (u = 0; u < match_num; u++) { + mlen = (u>0) ? matches[u-1].len+1 : best_mlen; + best_mlen = (matches[u].len < ZSTD_OPT_NUM) ? matches[u].len : ZSTD_OPT_NUM; ZSTD_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(ip-base), matches[i].len, matches[i].off, (int)best_mlen, (int)last_pos); litlen = opt[0].litlen; while (mlen <= best_mlen) { - price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[i].off, mlen - MINMATCH); + price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off, mlen - MINMATCH); if (mlen > last_pos || price < opt[mlen].price) - SET_PRICE(mlen, mlen, matches[i].off, litlen, price); + SET_PRICE(mlen, mlen, matches[u].off, litlen, price); mlen++; } } - if (last_pos < MINMATCH) { + if (last_pos < MINMATCH) { // ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */ - ip++; continue; + ip++; continue; } // check further positions for (skip_num = 0, cur = 1; cur <= last_pos; cur++) - { + { + size_t cur_rep; inr = ip + cur; - if (opt[cur-1].mlen == 1) - { + if (opt[cur-1].mlen == 1) { litlen = opt[cur-1].litlen + 1; - if (cur > litlen) - { + if (cur > litlen) { price = opt[cur - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-litlen); ZSTD_LOG_TRY_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); - } - else + } else price = ZSTD_getLiteralPrice(seqStorePtr, litlen, anchor); - } - else - { + } else { litlen = 1; - price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1); + price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1); ZSTD_LOG_TRY_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)(inr-base), price, cur, litlen, (int)ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1)); } - + ZSTD_LOG_TRY_PRICE("%d: TRY4 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur, opt[cur].price); if (cur > last_pos || price <= opt[cur].price) // || ((price == opt[cur].price) && (opt[cur-1].mlen == 1) && (cur != litlen))) @@ -583,53 +542,40 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, continue; mlen = opt[cur].mlen; - - if (opt[cur-mlen].off) - { + + if (opt[cur-mlen].off) { opt[cur].rep2 = opt[cur-mlen].rep; opt[cur].rep = opt[cur-mlen].off; ZSTD_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); - } - else - { - if (cur!=mlen && opt[cur-mlen].litlen == 0) - { + } else { + if (cur!=mlen && opt[cur-mlen].litlen == 0) { opt[cur].rep2 = opt[cur-mlen].rep; opt[cur].rep = opt[cur-mlen].rep2; ZSTD_LOG_PARSER("%d: COPYREP2 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); - } - else - { + } else { opt[cur].rep2 = opt[cur-mlen].rep2; opt[cur].rep = opt[cur-mlen].rep; ZSTD_LOG_PARSER("%d: COPYREP3 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); - } - } + } } - ZSTD_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); + ZSTD_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); - - - size_t cur_rep; best_mlen = 0; if (!opt[cur].off && opt[cur].mlen != 1) { cur_rep = opt[cur].rep2; - ZSTD_LOG_PARSER("%d: try REP2 rep2=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); - } - else { + ZSTD_LOG_PARSER("%d: try REP2 rep2=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); + } else { cur_rep = opt[cur].rep; - ZSTD_LOG_PARSER("%d: try REP1 rep=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); + ZSTD_LOG_PARSER("%d: try REP1 rep=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); } - if (MEM_read32(inr) == MEM_read32(inr - cur_rep)) // check rep - { - mlen = (U32)ZSTD_count(inr+MINMATCH, inr+MINMATCH - cur_rep, iend) + MINMATCH; + if (MEM_read32(inr) == MEM_read32(inr - cur_rep)) { // check rep + mlen = (U32)ZSTD_count(inr+MINMATCH, inr+MINMATCH - cur_rep, iend) + MINMATCH; ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep, cur, opt[cur].off); - if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) - { + if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) { best_mlen = mlen; best_off = 0; ZSTD_LOG_PARSER("%d: REP sufficient_len=%d best_mlen=%d best_off=%d last_pos=%d\n", (int)(inr-base), sufficient_len, best_mlen, best_off, last_pos); @@ -637,20 +583,15 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, goto _storeSequence; } - if (opt[cur].mlen == 1) - { + if (opt[cur].mlen == 1) { litlen = opt[cur].litlen; - if (cur > litlen) - { + if (cur > litlen) { price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, inr-litlen, 0, mlen - MINMATCH); ZSTD_LOG_TRY_PRICE("%d: TRY5 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); - } - else + } else price = ZSTD_getPrice(seqStorePtr, litlen, anchor, 0, mlen - MINMATCH); - } - else - { + } else { litlen = 0; price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, 0, mlen - MINMATCH); ZSTD_LOG_TRY_PRICE("%d: TRY7 price=%d cur=%d litlen=0 getprice=%d\n", (int)(inr-base), price, cur, (int)ZSTD_getPrice(seqStorePtr, 0, NULL, 0, mlen - MINMATCH)); @@ -662,31 +603,23 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), mlen, 0, price, litlen, cur - litlen, opt[cur - litlen].price); - do - { + do { if (cur + mlen > last_pos || price <= opt[cur + mlen].price) // || ((price == opt[cur + mlen].price) && (opt[cur].mlen == 1) && (cur != litlen))) // at equal price prefer REP instead of MATCH SET_PRICE(cur + mlen, mlen, 0, litlen, price); mlen--; - } - while (mlen >= MINMATCH); + } while (mlen >= MINMATCH); } - - if (faster_get_matches && skip_num > 0) - { - skip_num--; - continue; - } + if (faster_get_matches && skip_num > 0) { skip_num--; continue; } - best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; + best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; - match_num = getAllMatches(ctx, inr, ip, iend, maxSearches, mls, matches, best_mlen); + match_num = getAllMatches(ctx, inr, ip, iend, maxSearches, mls, matches, best_mlen); ZSTD_LOG_PARSER("%d: ZSTD_GetAllMatches match_num=%d\n", (int)(inr-base), match_num); - if (match_num > 0 && matches[match_num-1].len > sufficient_len) - { + if (match_num > 0 && matches[match_num-1].len > sufficient_len) { cur -= matches[match_num-1].back; best_mlen = matches[match_num-1].len; best_off = matches[match_num-1].off; @@ -695,77 +628,69 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } - // set prices using matches at position = cur - for (U32 i = 0; i < match_num; i++) - { - mlen = (i>0) ? matches[i-1].len+1 : best_mlen; - cur2 = cur - matches[i].back; - best_mlen = (cur2 + matches[i].len < ZSTD_OPT_NUM) ? matches[i].len : ZSTD_OPT_NUM - cur2; + /* set prices using matches at position = cur */ + for (u = 0; u < match_num; u++) { + mlen = (u>0) ? matches[u-1].len+1 : best_mlen; + cur2 = cur - matches[u].back; + best_mlen = (cur2 + matches[u].len < ZSTD_OPT_NUM) ? matches[u].len : ZSTD_OPT_NUM - cur2; - ZSTD_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(inr-base), cur, cur2, matches[i].len, matches[i].off, best_mlen, last_pos); - if (mlen < matches[i].back + 1) - mlen = matches[i].back + 1; + ZSTD_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(inr-base), cur, cur2, matches[u].len, matches[i].off, best_mlen, last_pos); + if (mlen < matches[u].back + 1) + mlen = matches[u].back + 1; - while (mlen <= best_mlen) - { - if (opt[cur2].mlen == 1) - { + while (mlen <= best_mlen) { + if (opt[cur2].mlen == 1) { litlen = opt[cur2].litlen; if (cur2 > litlen) - price = opt[cur2 - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, ip+cur2-litlen, matches[i].off, mlen - MINMATCH); + price = opt[cur2 - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, ip+cur2-litlen, matches[u].off, mlen - MINMATCH); else - price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[i].off, mlen - MINMATCH); - } - else - { + price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off, mlen - MINMATCH); + } else { litlen = 0; - price = opt[cur2].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[i].off, mlen - MINMATCH); + price = opt[cur2].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[u].off, mlen - MINMATCH); } - ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); + ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[u].back, mlen, best_mlen, matches[u].off, price, litlen, cur - litlen, opt[cur - litlen].price); ZSTD_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); if (cur2 + mlen > last_pos || (price < opt[cur2 + mlen].price)) - SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); + SET_PRICE(cur2 + mlen, mlen, matches[u].off, litlen, price); mlen++; - } - } + } } } // for (skip_num = 0, cur = 1; cur <= last_pos; cur++) best_mlen = opt[last_pos].mlen; best_off = opt[last_pos].off; cur = last_pos - best_mlen; - // printf("%d: start=%d best_mlen=%d best_off=%d cur=%d\n", (int)(ip - base), (int)(start - ip), (int)best_mlen, (int)best_off, cur); + // printf("%d: start=%d best_mlen=%d best_off=%d cur=%d\n", (int)(ip - base), (int)(start - ip), (int)best_mlen, (int)best_off, cur); /* store sequence */ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set - for (U32 i = 1; i <= last_pos; i++) - ZSTD_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); - ZSTD_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-base+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); + for (u = 1; u <= last_pos; u++) + ZSTD_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+u), u, last_pos, opt[u].price, opt[u].off, opt[u].mlen, opt[u].litlen, opt[u].rep, opt[u].rep2); + ZSTD_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-base+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); opt[0].mlen = 1; U32 offset; - while (1) - { + while (1) { mlen = opt[cur].mlen; ZSTD_LOG_PARSER("%d: cur=%d mlen=%d\n", (int)(ip-base), cur, mlen); offset = opt[cur].off; - opt[cur].mlen = best_mlen; + opt[cur].mlen = best_mlen; opt[cur].off = best_off; best_mlen = mlen; - best_off = offset; + best_off = offset; if (mlen > cur) break; cur -= mlen; } - - for (U32 i = 0; i <= last_pos;) - { - ZSTD_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); - i += opt[i].mlen; + + for (u = 0; u <= last_pos;) { + ZSTD_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+u), u, last_pos, opt[u].price, opt[u].off, opt[u].mlen, opt[u].litlen, opt[u].rep, opt[u].rep2); + u += opt[u].mlen; } cur = 0; @@ -789,7 +714,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set } else { - if (litLength == 0) + if (litLength == 0) { best_off = rep_2; rep_2 = rep_1; @@ -798,7 +723,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set } ZSTD_LOG_ENCODE("%d/%d: ENCODE2 literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); - + #if ZSTD_OPT_DEBUG >= 5 int ml2; if (offset) @@ -839,7 +764,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set anchor += best_mlen+MINMATCH; ip = anchor; continue; // faster when present ... (?) - } + } } /* Last Literals */ @@ -880,11 +805,11 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, ZSTD_optimal_t opt[ZSTD_OPT_NUM+4]; ZSTD_match_t matches[ZSTD_OPT_NUM+1]; - const uint8_t *inr; + const BYTE* inr; U32 skip_num, cur, cur2, match_num, last_pos, litlen, price; const U32 sufficient_len = ctx->params.sufficientLength; - const U32 faster_get_matches = (ctx->params.strategy == ZSTD_opt); + const U32 faster_get_matches = (ctx->params.strategy == ZSTD_opt); /* init */ @@ -894,6 +819,8 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, /* Match Loop */ while (ip < ilimit) { + U32 u; + U32 offset; U32 mlen=0; U32 best_mlen=0; U32 best_off=0; @@ -914,7 +841,7 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, /* repcode detected we should take it */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; mlen = (U32)ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; - + ZSTD_LOG_PARSER("%d: start try REP rep=%d mlen=%d\n", (int)(ip-base), (int)rep_1, (int)mlen); if (depth==0 || mlen > sufficient_len || mlen >= ZSTD_OPT_NUM) { ip+=1; best_mlen = mlen; best_off = 0; cur = 0; last_pos = 1; @@ -922,19 +849,16 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, } litlen = opt[0].litlen + 1; - do - { + do { price = ZSTD_getPrice(seqStorePtr, litlen, anchor, 0, mlen - MINMATCH); if (mlen + 1 > last_pos || price < opt[mlen + 1].price) SET_PRICE(mlen + 1, mlen, 0, litlen, price); mlen--; - } - while (mlen >= MINMATCH); - } - } + } while (mlen >= MINMATCH); + } } best_mlen = (last_pos) ? last_pos : MINMATCH; - + if (faster_get_matches && last_pos) match_num = 0; else @@ -947,8 +871,7 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, opt[0].rep2 = rep_2; opt[0].mlen = 1; - if (match_num && matches[match_num-1].len > sufficient_len) - { + if (match_num && matches[match_num-1].len > sufficient_len) { best_mlen = matches[match_num-1].len; best_off = matches[match_num-1].off; cur = 0; @@ -957,50 +880,43 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, } // set prices using matches at position = 0 - for (U32 i = 0; i < match_num; i++) - { - mlen = (i>0) ? matches[i-1].len+1 : best_mlen; - best_mlen = (matches[i].len < ZSTD_OPT_NUM) ? matches[i].len : ZSTD_OPT_NUM; - ZSTD_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(ip-base), matches[i].len, matches[i].off, (int)best_mlen, (int)last_pos); + for (u = 0; u < match_num; u++) { + mlen = (u>0) ? matches[u-1].len+1 : best_mlen; + best_mlen = (matches[u].len < ZSTD_OPT_NUM) ? matches[u].len : ZSTD_OPT_NUM; + ZSTD_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(ip-base), matches[u].len, matches[u].off, (int)best_mlen, (int)last_pos); litlen = opt[0].litlen; - while (mlen <= best_mlen) - { - price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[i].off, mlen - MINMATCH); + while (mlen <= best_mlen) { + price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off, mlen - MINMATCH); if (mlen > last_pos || price < opt[mlen].price) - SET_PRICE(mlen, mlen, matches[i].off, litlen, price); + SET_PRICE(mlen, mlen, matches[u].off, litlen, price); mlen++; - } - } + } } - if (last_pos < MINMATCH) { - // ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */ - ip++; continue; + if (last_pos < MINMATCH) { + // ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */ + ip++; continue; } // check further positions for (skip_num = 0, cur = 1; cur <= last_pos; cur++) - { + { + size_t cur_rep; inr = ip + cur; - if (opt[cur-1].mlen == 1) - { + if (opt[cur-1].mlen == 1) { litlen = opt[cur-1].litlen + 1; - if (cur > litlen) - { + if (cur > litlen) { price = opt[cur - litlen].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-litlen); ZSTD_LOG_TRY_PRICE("%d: TRY1 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); - } - else + } else price = ZSTD_getLiteralPrice(seqStorePtr, litlen, anchor); - } - else - { + } else { litlen = 1; - price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1); + price = opt[cur - 1].price + ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1); ZSTD_LOG_TRY_PRICE("%d: TRY3 price=%d cur=%d litlen=%d litonly=%d\n", (int)(inr-base), price, cur, litlen, (int)ZSTD_getLiteralPrice(seqStorePtr, litlen, inr-1)); } - + ZSTD_LOG_TRY_PRICE("%d: TRY4 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur, opt[cur].price); if (cur > last_pos || price <= opt[cur].price) // || ((price == opt[cur].price) && (opt[cur-1].mlen == 1) && (cur != litlen))) @@ -1012,43 +928,35 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, continue; mlen = opt[cur].mlen; - - if (opt[cur-mlen].off) - { + + if (opt[cur-mlen].off) { opt[cur].rep2 = opt[cur-mlen].rep; opt[cur].rep = opt[cur-mlen].off; ZSTD_LOG_PARSER("%d: COPYREP1 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); - } - else - { - if (cur!=mlen && opt[cur-mlen].litlen == 0) - { + } else { + if (cur!=mlen && opt[cur-mlen].litlen == 0) { opt[cur].rep2 = opt[cur-mlen].rep; opt[cur].rep = opt[cur-mlen].rep2; ZSTD_LOG_PARSER("%d: COPYREP2 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); - } - else - { + } else { opt[cur].rep2 = opt[cur-mlen].rep2; opt[cur].rep = opt[cur-mlen].rep; ZSTD_LOG_PARSER("%d: COPYREP3 cur=%d mlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, mlen, opt[cur].rep, opt[cur].rep2); - } - } + } } - ZSTD_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); + ZSTD_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); - size_t cur_rep; best_mlen = 0; if (!opt[cur].off && opt[cur].mlen != 1) { cur_rep = opt[cur].rep2; - ZSTD_LOG_PARSER("%d: try REP2 rep2=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); + ZSTD_LOG_PARSER("%d: try REP2 rep2=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); } else { cur_rep = opt[cur].rep; - ZSTD_LOG_PARSER("%d: try REP1 rep=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); + ZSTD_LOG_PARSER("%d: try REP1 rep=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); } const U32 repIndex = (U32)(current+cur - cur_rep); @@ -1107,19 +1015,18 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, if (faster_get_matches && skip_num > 0) { - skip_num--; + skip_num--; continue; } - best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; + best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; - match_num = getAllMatches(ctx, inr, ip, iend, maxSearches, mls, matches, best_mlen); + match_num = getAllMatches(ctx, inr, ip, iend, maxSearches, mls, matches, best_mlen); ZSTD_LOG_PARSER("%d: ZSTD_GetAllMatches match_num=%d\n", (int)(inr-base), match_num); - if (match_num > 0 && matches[match_num-1].len > sufficient_len) - { + if (match_num > 0 && matches[match_num-1].len > sufficient_len) { cur -= matches[match_num-1].back; best_mlen = matches[match_num-1].len; best_off = matches[match_num-1].off; @@ -1129,109 +1036,94 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, // set prices using matches at position = cur - for (U32 i = 0; i < match_num; i++) - { - mlen = (i>0) ? matches[i-1].len+1 : best_mlen; - cur2 = cur - matches[i].back; - best_mlen = (cur2 + matches[i].len < ZSTD_OPT_NUM) ? matches[i].len : ZSTD_OPT_NUM - cur2; + for (u = 0; u < match_num; u++) { + mlen = (u>0) ? matches[u-1].len+1 : best_mlen; + cur2 = cur - matches[u].back; + best_mlen = (cur2 + matches[u].len < ZSTD_OPT_NUM) ? matches[u].len : ZSTD_OPT_NUM - cur2; - ZSTD_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(inr-base), cur, cur2, matches[i].len, matches[i].off, best_mlen, last_pos); - if (mlen < matches[i].back + 1) - mlen = matches[i].back + 1; + ZSTD_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(inr-base), cur, cur2, matches[u].len, matches[u].off, best_mlen, last_pos); + if (mlen < matches[u].back + 1) + mlen = matches[u].back + 1; - while (mlen <= best_mlen) - { - if (opt[cur2].mlen == 1) - { + while (mlen <= best_mlen) { + if (opt[cur2].mlen == 1) { litlen = opt[cur2].litlen; if (cur2 > litlen) - price = opt[cur2 - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, ip+cur2-litlen, matches[i].off, mlen - MINMATCH); + price = opt[cur2 - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, ip+cur2-litlen, matches[u].off, mlen - MINMATCH); else - price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[i].off, mlen - MINMATCH); - } - else - { + price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off, mlen - MINMATCH); + } else { litlen = 0; - price = opt[cur2].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[i].off, mlen - MINMATCH); + price = opt[cur2].price + ZSTD_getPrice(seqStorePtr, 0, NULL, matches[u].off, mlen - MINMATCH); } - ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[i].back, mlen, best_mlen, matches[i].off, price, litlen, cur - litlen, opt[cur - litlen].price); + ZSTD_LOG_PARSER("%d: Found2 pred=%d mlen=%d best_mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), matches[u].back, mlen, best_mlen, matches[u].off, price, litlen, cur - litlen, opt[cur - litlen].price); ZSTD_LOG_TRY_PRICE("%d: TRY8 price=%d opt[%d].price=%d\n", (int)(inr-base), price, cur2 + mlen, opt[cur2 + mlen].price); if (cur2 + mlen > last_pos || (price < opt[cur2 + mlen].price)) - SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price); + SET_PRICE(cur2 + mlen, mlen, matches[u].off, litlen, price); mlen++; - } - } + } } } // for (skip_num = 0, cur = 1; cur <= last_pos; cur++) best_mlen = opt[last_pos].mlen; best_off = opt[last_pos].off; cur = last_pos - best_mlen; - // printf("%d: start=%d best_mlen=%d best_off=%d cur=%d\n", (int)(ip - base), (int)(start - ip), (int)best_mlen, (int)best_off, cur); + // printf("%d: start=%d best_mlen=%d best_off=%d cur=%d\n", (int)(ip - base), (int)(start - ip), (int)best_mlen, (int)best_off, cur); /* store sequence */ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set - for (U32 i = 1; i <= last_pos; i++) - ZSTD_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); - ZSTD_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-base+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); + for (u = 1; u <= last_pos; u++) + ZSTD_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+u), u, last_pos, opt[u].price, opt[u].off, opt[u].mlen, opt[u]litlen, opt[u].rep, opt[u].rep2); + ZSTD_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-base+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); opt[0].mlen = 1; - U32 offset; - while (1) - { + while (1) { mlen = opt[cur].mlen; ZSTD_LOG_PARSER("%d: cur=%d mlen=%d\n", (int)(ip-base), cur, mlen); offset = opt[cur].off; - opt[cur].mlen = best_mlen; + opt[cur].mlen = best_mlen; opt[cur].off = best_off; best_mlen = mlen; - best_off = offset; + best_off = offset; if (mlen > cur) break; cur -= mlen; } - - for (U32 i = 0; i <= last_pos;) - { - ZSTD_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+i), i, last_pos, opt[i].price, opt[i].off, opt[i].mlen, opt[i].litlen, opt[i].rep, opt[i].rep2); - i += opt[i].mlen; + + for (u = 0; u <= last_pos;) { + ZSTD_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+u), u, last_pos, opt[u].price, opt[u].off, opt[u].mlen, opt[u].litlen, opt[u].rep, opt[u].rep2); + u += opt[u].mlen; } cur = 0; - while (cur < last_pos) - { + while (cur < last_pos) { + U32 litLength; ZSTD_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); mlen = opt[cur].mlen; if (mlen == 1) { ip++; cur++; continue; } offset = opt[cur].off; cur += mlen; - - U32 litLength = (U32)(ip - anchor); + litLength = (U32)(ip - anchor); ZSTD_LOG_ENCODE("%d/%d: ENCODE1 literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); - if (offset) - { + if (offset) { rep_2 = rep_1; rep_1 = offset; - } - else - { - if (litLength == 0) - { + } else { + if (litLength == 0) { best_off = rep_2; rep_2 = rep_1; rep_1 = best_off; - } - } + } } ZSTD_LOG_ENCODE("%d/%d: ENCODE2 literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); - + #if ZSTD_OPT_DEBUG >= 5 int ml2; if (offset) @@ -1258,14 +1150,14 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set } - // check immediate repcode + /* check immediate repcode */ while (anchor <= ilimit) { const U32 repIndex = (U32)((anchor-base) - rep_2); const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; - if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ - if (MEM_read32(anchor) == MEM_read32(repMatch)) { - /* repcode detected we should take it */ + if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ + && (MEM_read32(anchor) == MEM_read32(repMatch)) ) { + /* repcode detected, let's take it */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; mlen = (U32)ZSTD_count_2segments(anchor+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; offset = rep_2; rep_2 = rep_1; rep_1 = offset; /* swap offset history */ @@ -1277,8 +1169,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set continue; /* faster when present ... (?) */ } break; - } - } + } } /* Last Literals */ { diff --git a/lib/zstd_static.h b/lib/zstd_static.h index da2335bd3..8b7d63b23 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -54,6 +54,8 @@ extern "C" { #define ZSTD_WINDOWLOG_MAX 26 #define ZSTD_WINDOWLOG_MIN 18 #define ZSTD_WINDOWLOG_ABSOLUTEMIN 11 +#define ZSTD_TARGETLENGTH_MIN 4 +#define ZSTD_TARGETLENGTH_MAX 999 #define ZSTD_CONTENTLOG_MAX (ZSTD_WINDOWLOG_MAX+1) #define ZSTD_CONTENTLOG_MIN 4 #define ZSTD_HASHLOG_MAX 28 @@ -63,16 +65,16 @@ extern "C" { #define ZSTD_SEARCHLENGTH_MAX 7 #define ZSTD_SEARCHLENGTH_MIN 4 -/** from faster to stronger */ +/* from faster to stronger */ typedef enum { ZSTD_fast, ZSTD_greedy, ZSTD_lazy, ZSTD_lazy2, ZSTD_btlazy2, ZSTD_opt, ZSTD_opt_bt } ZSTD_strategy; typedef struct { U64 srcSize; /* optional : tells how much bytes are present in the frame. Use 0 if not known. */ - U32 sufficientLength; /* size of matches which is acceptable (used only by the optimal parser): larger == more compression, slower */ + U32 sufficientLength; /* size of matches which is acceptable (used only by the optimal parser): larger == more compression, slower */ U32 windowLog; /* largest match distance : larger == more compression, more memory needed during decompression */ U32 contentLog; /* full search segment : larger == more compression, slower, more memory (useless for fast) */ - U32 hashLog; /* dispatch table : larger == more memory, faster */ + U32 hashLog; /* dispatch table : larger == faster, more memory */ U32 searchLog; /* nb of searches : larger == more compression, slower */ U32 searchLength; /* size of matches : larger == faster decompression, sometimes less compression */ ZSTD_strategy strategy; @@ -82,7 +84,6 @@ typedef struct /* ************************************* * Advanced functions ***************************************/ -#define ZSTD_MAX_CLEVEL 24 ZSTDLIB_API unsigned ZSTD_maxCLevel (void); /*! ZSTD_getParams() : diff --git a/programs/paramgrill.c b/programs/paramgrill.c index a34da88ce..fd75aa327 100644 --- a/programs/paramgrill.c +++ b/programs/paramgrill.c @@ -1,6 +1,6 @@ /* - paramgrill.c - parameter tester for zstd_hc - Copyright (C) Yann Collet 2015 + paramgrill.c - parameter tester for zstd + Copyright (C) Yann Collet 2015-2016 GPL v2 License @@ -19,11 +19,10 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. You can contact the author at : - - zstd source repository : https://github.com/Cyan4973/zstd - - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c + - zstd homepage : http://www.zstd.net/ */ -/************************************** +/*-************************************ * Compiler Options **************************************/ /* Disable some Visual warning messages */ @@ -48,8 +47,8 @@ #endif -/************************************** -* Includes +/*-************************************ +* Dependencies **************************************/ #include /* malloc */ #include /* fprintf, fopen, ftello64 */ @@ -71,7 +70,7 @@ #include "xxhash.h" -/************************************** +/*-************************************ * Compiler Options **************************************/ /* S_ISREG & gettimeofday() are not supported by MSVC */ @@ -80,7 +79,7 @@ #endif -/************************************** +/*-************************************ * Constants **************************************/ #define PROGRAM_DESCRIPTION "ZSTD_HC parameters tester" @@ -98,6 +97,8 @@ #define NBLOOPS 2 #define TIMELOOP 2000 +#define NB_LEVELS_TRACKED 30 + static const size_t maxMemory = (sizeof(size_t)==4) ? (2 GB - 64 MB) : (size_t)(1ULL << ((sizeof(size_t)*8)-31)); #define DEFAULT_CHUNKSIZE (4<<20) @@ -110,13 +111,13 @@ static const int g_maxVariationTime = 60000; /* 60 sec */ static const int g_maxNbVariations = 64; -/************************************** +/*-************************************ * Macros **************************************/ #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) -/************************************** +/*-************************************ * Benchmark Parameters **************************************/ static U32 g_nbIterations = NBLOOPS; @@ -126,7 +127,7 @@ static U32 g_rand = 1; static U32 g_singleRun = 0; static U32 g_target = 0; static U32 g_noSeed = 0; -static ZSTD_parameters g_params = { 0, 0, 0, 0, 0, 0, ZSTD_greedy }; +static ZSTD_parameters g_params = { 0, 0, 0, 0, 0, 0, 0, ZSTD_greedy }; void BMK_SetNbIterations(int nbLoops) { @@ -135,7 +136,7 @@ void BMK_SetNbIterations(int nbLoops) } -/********************************************************* +/*-******************************************************* * Private functions *********************************************************/ @@ -187,8 +188,7 @@ static size_t BMK_findMaxMem(U64 requiredMem) if (requiredMem > maxMemory) requiredMem = maxMemory; requiredMem += 2*step; - while (!testmem) - { + while (!testmem) { requiredMem -= step; testmem = (BYTE*) malloc ((size_t)requiredMem); } @@ -226,7 +226,7 @@ U32 FUZ_rand(U32* src) } -/********************************************************* +/*-******************************************************* * Bench functions *********************************************************/ typedef struct { @@ -265,14 +265,14 @@ static size_t BMK_benchParam(BMK_result_t* resultPtr, U32 Hlog = params.hashLog; U32 Slog = params.searchLog; U32 Slength = params.searchLength; + U32 Tlength = params.sufficientLength; ZSTD_strategy strat = params.strategy; char name[30] = { 0 }; U64 crcOrig; /* Memory allocation & restrictions */ - snprintf(name, 30, "Sw%02uc%02uh%02us%02ul%1ut%1u", Wlog, Clog, Hlog, Slog, Slength, strat); - if (!compressedBuffer || !resultBuffer || !blockTable) - { + snprintf(name, 30, "Sw%02uc%02uh%02us%02ul%1ut%03uS%1u", Wlog, Clog, Hlog, Slog, Slength, Tlength, strat); + if (!compressedBuffer || !resultBuffer || !blockTable) { DISPLAY("\nError: not enough memory!\n"); free(compressedBuffer); free(resultBuffer); @@ -290,8 +290,7 @@ static size_t BMK_benchParam(BMK_result_t* resultPtr, const char* srcPtr = (const char*)srcBuffer; char* cPtr = (char*)compressedBuffer; char* resPtr = (char*)resultBuffer; - for (i=0; i O_ratio) DISPLAY ("Decompression Memory : %5.3f @ %4.1f MB vs %5.3f @ %4.1f MB : not enough for level %i\n", @@ -518,8 +504,7 @@ static int BMK_seed(winnerInfo_t* winners, const ZSTD_parameters params, O_ratio, (double)(O_DMemUsed) / 1024 / 1024, cLevel); continue; } - if (W_CMemUsed_note < O_CMemUsed_note) - { + if (W_CMemUsed_note < O_CMemUsed_note) { /* uses too much memory for compression for too little benefit */ if (W_ratio > O_ratio) DISPLAY ("Compression Memory : %5.3f @ %4.1f MB vs %5.3f @ %4.1f MB : not enough for level %i\n", @@ -527,8 +512,7 @@ static int BMK_seed(winnerInfo_t* winners, const ZSTD_parameters params, O_ratio, (double)(O_CMemUsed) / 1024 / 1024, cLevel); continue; } - if (W_CSpeed_note < O_CSpeed_note ) - { + if (W_CSpeed_note < O_CSpeed_note ) { /* too large compression speed difference for the compression benefit */ if (W_ratio > O_ratio) DISPLAY ("Compression Speed : %5.3f @ %4.1f MB/s vs %5.3f @ %4.1f MB/s : not enough for level %i\n", @@ -536,8 +520,7 @@ static int BMK_seed(winnerInfo_t* winners, const ZSTD_parameters params, O_ratio, (double)(winners[cLevel].result.cSpeed) / 1000., cLevel); continue; } - if (W_DSpeed_note < O_DSpeed_note ) - { + if (W_DSpeed_note < O_DSpeed_note ) { /* too large decompression speed difference for the compression benefit */ if (W_ratio > O_ratio) DISPLAY ("Decompression Speed : %5.3f @ %4.1f MB/s vs %5.3f @ %4.1f MB/s : not enough for level %i\n", @@ -554,9 +537,7 @@ static int BMK_seed(winnerInfo_t* winners, const ZSTD_parameters params, BMK_printWinner(stdout, cLevel, testResult, params, srcSize); better = 1; - } - - } + } } return better; } @@ -567,10 +548,9 @@ static ZSTD_parameters* sanitizeParams(ZSTD_parameters params) { g_params = params; if (params.strategy == ZSTD_fast) - { - g_params.contentLog = 0; - g_params.searchLog = 0; - } + g_params.contentLog = 0, g_params.searchLog = 0; + if ((params.strategy != ZSTD_opt) && (params.strategy != ZSTD_opt_bt)) + g_params.sufficientLength = 0; return &g_params; } @@ -578,8 +558,7 @@ static ZSTD_parameters* sanitizeParams(ZSTD_parameters params) static void paramVariation(ZSTD_parameters* p) { U32 nbChanges = (FUZ_rand(&g_rand) & 3) + 1; - for (; nbChanges; nbChanges--) - { + for (; nbChanges; nbChanges--) { const U32 changeID = FUZ_rand(&g_rand) % 12; switch(changeID) { @@ -607,6 +586,10 @@ static void paramVariation(ZSTD_parameters* p) p->strategy = (ZSTD_strategy)(((U32)p->strategy)+1); break; case 11: p->strategy = (ZSTD_strategy)(((U32)p->strategy)-1); break; + case 12: + p->sufficientLength *= 1 + ((double)(FUZ_rand(&g_rand)&255)) / 256.; break; + case 13: + p->sufficientLength /= 1 + ((double)(FUZ_rand(&g_rand)&255)) / 256.; break; } } ZSTD_validateParams(p); @@ -632,8 +615,7 @@ static void playAround(FILE* f, winnerInfo_t* winners, int nbVariations = 0; const int startTime = BMK_GetMilliStart(); - while (BMK_GetMilliSpan(startTime) < g_maxVariationTime) - { + while (BMK_GetMilliSpan(startTime) < g_maxVariationTime) { ZSTD_parameters p = params; if (nbVariations++ > g_maxNbVariations) break; @@ -658,15 +640,15 @@ static void playAround(FILE* f, winnerInfo_t* winners, static void potentialRandomParams(ZSTD_parameters* p, U32 inverseChance) { U32 chance = (FUZ_rand(&g_rand) % (inverseChance+1)); - if (!chance) - { + if (!chance) { /* totally random entry */ p->contentLog = FUZ_rand(&g_rand) % (ZSTD_CONTENTLOG_MAX+1 - ZSTD_CONTENTLOG_MIN) + ZSTD_CONTENTLOG_MIN; p->hashLog = FUZ_rand(&g_rand) % (ZSTD_HASHLOG_MAX+1 - ZSTD_HASHLOG_MIN) + ZSTD_HASHLOG_MIN; p->searchLog = FUZ_rand(&g_rand) % (ZSTD_SEARCHLOG_MAX+1 - ZSTD_SEARCHLOG_MIN) + ZSTD_SEARCHLOG_MIN; p->windowLog = FUZ_rand(&g_rand) % (ZSTD_WINDOWLOG_MAX+1 - ZSTD_WINDOWLOG_MIN) + ZSTD_WINDOWLOG_MIN; p->searchLength=FUZ_rand(&g_rand) % (ZSTD_SEARCHLENGTH_MAX+1 - ZSTD_SEARCHLENGTH_MIN) + ZSTD_SEARCHLENGTH_MIN; - p->strategy = (ZSTD_strategy) (FUZ_rand(&g_rand) % (ZSTD_btlazy2+1)); + p->sufficientLength=FUZ_rand(&g_rand) % (ZSTD_TARGETLENGTH_MAX+1 - ZSTD_TARGETLENGTH_MIN) + ZSTD_TARGETLENGTH_MIN; + p->strategy = (ZSTD_strategy) (FUZ_rand(&g_rand) % (ZSTD_opt_bt+1)); ZSTD_validateParams(p); } } @@ -676,9 +658,8 @@ static void BMK_selectRandomStart( const void* srcBuffer, size_t srcSize, ZSTD_CCtx* ctx) { - U32 id = (FUZ_rand(&g_rand) % (ZSTD_MAX_CLEVEL+1)); - if ((id==0) || (winners[id].params.windowLog==0)) - { + U32 id = (FUZ_rand(&g_rand) % (ZSTD_maxCLevel()+1)); + if ((id==0) || (winners[id].params.windowLog==0)) { /* totally random entry */ ZSTD_parameters p; potentialRandomParams(&p, 1); @@ -695,14 +676,14 @@ static void BMK_benchMem(void* srcBuffer, size_t srcSize) { ZSTD_CCtx* ctx = ZSTD_createCCtx(); ZSTD_parameters params; - winnerInfo_t winners[ZSTD_MAX_CLEVEL+1]; + winnerInfo_t winners[NB_LEVELS_TRACKED]; int i; + unsigned u; const char* rfName = "grillResults.txt"; FILE* f; const size_t blockSize = g_blockSize ? g_blockSize : srcSize; - if (g_singleRun) - { + if (g_singleRun) { BMK_result_t testResult; g_params.srcSize = blockSize; ZSTD_validateParams(&g_params); @@ -718,8 +699,7 @@ static void BMK_benchMem(void* srcBuffer, size_t srcSize) if (g_target) g_cSpeedTarget[1] = g_target * 1000; - else - { + else { /* baseline config for level 1 */ BMK_result_t testResult; params = ZSTD_getParams(1, blockSize); @@ -728,14 +708,13 @@ static void BMK_benchMem(void* srcBuffer, size_t srcSize) } /* establish speed objectives (relative to level 1) */ - for (i=2; i<=ZSTD_MAX_CLEVEL; i++) - g_cSpeedTarget[i] = (g_cSpeedTarget[i-1] * 25) >> 5; + for (u=2; u<=ZSTD_maxCLevel(); u++) + g_cSpeedTarget[u] = (g_cSpeedTarget[u-1] * 25) >> 5; /* populate initial solution */ { - const int maxSeeds = g_noSeed ? 1 : ZSTD_MAX_CLEVEL; - for (i=1; i<=maxSeeds; i++) - { + const int maxSeeds = g_noSeed ? 1 : ZSTD_maxCLevel(); + for (i=1; i<=maxSeeds; i++) { params = ZSTD_getParams(i, blockSize); ZSTD_validateParams(¶ms); BMK_seed(winners, params, srcBuffer, srcSize, ctx); @@ -746,8 +725,7 @@ static void BMK_benchMem(void* srcBuffer, size_t srcSize) /* start tests */ { const int milliStart = BMK_GetMilliStart(); - do - { + do { BMK_selectRandomStart(f, winners, srcBuffer, srcSize, ctx); } while (BMK_GetMilliSpan(milliStart) < g_grillDuration); } @@ -764,17 +742,13 @@ static void BMK_benchMem(void* srcBuffer, size_t srcSize) static int benchSample(void) { - char* origBuff; + void* origBuff; size_t benchedSize = sampleSize; const char* name = "Sample 10MiB"; /* Allocation */ - origBuff = (char*) malloc((size_t)benchedSize); - if(!origBuff) - { - DISPLAY("\nError: not enough memory!\n"); - return 12; - } + origBuff = malloc(benchedSize); + if (!origBuff) { DISPLAY("\nError: not enough memory!\n"); return 12; } /* Fill buffer */ RDG_genBuffer(origBuff, benchedSize, g_compressibility, 0.0, 0); @@ -794,8 +768,7 @@ int benchFiles(char** fileNamesTable, int nbFiles) int fileIdx=0; /* Loop for each file */ - while (fileIdx inFileSize) benchedSize = (size_t)inFileSize; if (benchedSize < inFileSize) - { DISPLAY("Not enough memory for '%s' full size; testing %i MB only...\n", inFileName, (int)(benchedSize>>20)); - } /* Alloc */ origBuff = (char*) malloc((size_t)benchedSize); - if(!origBuff) - { + if(!origBuff) { DISPLAY("\nError: not enough memory!\n"); fclose(inFile); return 12; @@ -835,8 +804,7 @@ int benchFiles(char** fileNamesTable, int nbFiles) readSize = fread(origBuff, 1, benchedSize, inFile); fclose(inFile); - if(readSize != benchedSize) - { + if(readSize != benchedSize) { DISPLAY("\nError: problem reading file '%s' !! \n", inFileName); free(origBuff); return 13; @@ -862,8 +830,7 @@ int optimizeForSize(char* inFileName) /* Check file existence */ inFile = fopen( inFileName, "rb" ); - if (inFile==NULL) - { + if (inFile==NULL) { DISPLAY( "Pb opening %s\n", inFileName); return 11; } @@ -873,14 +840,11 @@ int optimizeForSize(char* inFileName) benchedSize = (size_t) BMK_findMaxMem(inFileSize*3) / 3; if ((U64)benchedSize > inFileSize) benchedSize = (size_t)inFileSize; if (benchedSize < inFileSize) - { DISPLAY("Not enough memory for '%s' full size; testing %i MB only...\n", inFileName, (int)(benchedSize>>20)); - } /* Alloc */ origBuff = (char*) malloc((size_t)benchedSize); - if(!origBuff) - { + if(!origBuff) { DISPLAY("\nError: not enough memory!\n"); fclose(inFile); return 12; @@ -891,8 +855,7 @@ int optimizeForSize(char* inFileName) readSize = fread(origBuff, 1, benchedSize, inFile); fclose(inFile); - if(readSize != benchedSize) - { + if(readSize != benchedSize) { DISPLAY("\nError: problem reading file '%s' !! \n", inFileName); free(origBuff); return 13; @@ -916,9 +879,8 @@ int optimizeForSize(char* inFileName) /* find best solution from default params */ { - const int maxSeeds = g_noSeed ? 1 : ZSTD_MAX_CLEVEL; - for (i=1; i<=maxSeeds; i++) - { + const int maxSeeds = g_noSeed ? 1 : ZSTD_maxCLevel(); + for (i=1; i<=maxSeeds; i++) { params = ZSTD_getParams(i, blockSize); BMK_benchParam(&candidate, origBuff, benchedSize, ctx, params); if ( (candidate.cSize < winner.result.cSize) @@ -927,16 +889,14 @@ int optimizeForSize(char* inFileName) winner.params = params; winner.result = candidate; BMK_printWinner(stdout, i, winner.result, winner.params, benchedSize); - } - } + } } } BMK_printWinner(stdout, 99, winner.result, winner.params, benchedSize); /* start tests */ { const int milliStart = BMK_GetMilliStart(); - do - { + do { params = winner.params; paramVariation(¶ms); potentialRandomParams(¶ms, 16); @@ -950,13 +910,11 @@ int optimizeForSize(char* inFileName) /* improvement found => new winner */ if ( (candidate.cSize < winner.result.cSize) - ||((candidate.cSize == winner.result.cSize) && (candidate.cSpeed > winner.result.cSpeed)) ) - { + ||((candidate.cSize == winner.result.cSize) && (candidate.cSpeed > winner.result.cSpeed)) ) { winner.params = params; winner.result = candidate; BMK_printWinner(stdout, 99, winner.result, winner.params, benchedSize); } - } while (BMK_GetMilliSpan(milliStart) < g_grillDuration); } @@ -1008,6 +966,12 @@ int main(int argc, char** argv) U32 optimizer = 0; U32 main_pause = 0; + /* checks */ + if (NB_LEVELS_TRACKED <= ZSTD_maxCLevel()) { + DISPLAY("Error : NB_LEVELS_TRACKED <= ZSTD_maxCLevel() \n"); + exit(1); + } + /* Welcome message */ DISPLAY(WELCOME_MESSAGE); @@ -1022,12 +986,10 @@ int main(int argc, char** argv) if(!strcmp(argument,"--no-seed")) { g_noSeed = 1; continue; } /* Decode command (note : aggregated commands are allowed) */ - if (argument[0]=='-') - { + if (argument[0]=='-') { argument++; - while (argument[0]!=0) - { + while (argument[0]!=0) { switch(argument[0]) { @@ -1050,8 +1012,7 @@ int main(int argc, char** argv) argument++; { U32 proba32 = 0; - while ((argument[0]>= '0') && (argument[0]<= '9')) - { + while ((argument[0]>= '0') && (argument[0]<= '9')) { proba32 *= 10; proba32 += argument[0] - '0'; argument++; @@ -1070,8 +1031,7 @@ int main(int argc, char** argv) g_singleRun = 1; argument++; g_params = ZSTD_getParams(2, g_blockSize); - for ( ; ; ) - { + for ( ; ; ) { switch(*argument) { case 'w': @@ -1107,8 +1067,7 @@ int main(int argc, char** argv) case 't': /* strategy */ g_params.strategy = (ZSTD_strategy)0; argument++; - while ((*argument>= '0') && (*argument<='9')) - { + while ((*argument>= '0') && (*argument<='9')) { g_params.strategy = (ZSTD_strategy)((U32)g_params.strategy *10); g_params.strategy = (ZSTD_strategy)((U32)g_params.strategy + *argument++ - '0'); } @@ -1132,8 +1091,7 @@ int main(int argc, char** argv) case 'T': argument++; g_target = 0; - while ((*argument >= '0') && (*argument <= '9')) - { + while ((*argument >= '0') && (*argument <= '9')) { g_target *= 10; g_target += *argument - '0'; argument++; @@ -1167,8 +1125,7 @@ int main(int argc, char** argv) if (filenamesStart==0) result = benchSample(); - else - { + else { if (optimizer) result = optimizeForSize(input_filename); else @@ -1179,4 +1136,3 @@ int main(int argc, char** argv) return result; } - From 768c6bc7057a7e285db91a6946d3feb38abd0c19 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 10 Feb 2016 14:01:49 +0100 Subject: [PATCH 069/113] fix : inlining difficulties with gcc 4.6 (travis) --- lib/zstd_compress.c | 7 +++---- lib/zstd_opt.c | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 7f8385b37..6ca31895e 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -1370,8 +1370,7 @@ size_t ZSTD_insertBtAndFindBestMatch ( if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */ largerPtr = nextPtr; matchIndex = nextPtr[0]; - } - } + } } *smallerPtr = *largerPtr = 0; @@ -1394,7 +1393,7 @@ size_t ZSTD_BtFindBestMatch ( } -FORCE_INLINE size_t ZSTD_BtFindBestMatch_selectMLS ( +static size_t ZSTD_BtFindBestMatch_selectMLS ( ZSTD_CCtx* zc, /* Index table will be updated */ const BYTE* ip, const BYTE* const iLimit, size_t* offsetPtr, @@ -1661,7 +1660,7 @@ void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx, break; /* nothing found : store previous solution */ } - /* catch up */ + /* catch up */ if (offset) { while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) /* only search for offset within prefix */ { start--; matchLength++; } diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 43ae8b570..3c1fbbe16 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -94,7 +94,7 @@ FORCE_INLINE U32 ZSTD_getPrice(seqStore_t* seqStorePtr, U32 litLength, const BYT { if (seqStorePtr->litSum > ZSTD_FREQ_THRESHOLD) return ZSTD_getLiteralPriceReal(seqStorePtr, litLength, literals) + ZSTD_getMatchPriceReal(seqStorePtr, offset, matchLength); - + /* backup eval */ return (litLength<<3) + ZSTD_highbit((U32)matchLength+1) + Offbits + ZSTD_highbit((U32)offset+1); } From 2f94d2f166f1224a3e853ef927b2d31bacec59e2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 10 Feb 2016 14:26:30 +0100 Subject: [PATCH 070/113] minor refactor --- lib/zstd_opt.c | 168 +++++++++++++++++++++++++------------------------ 1 file changed, 87 insertions(+), 81 deletions(-) diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index 3c1fbbe16..e7ec6dd7c 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -1,15 +1,51 @@ -#include -#include // log +/* + ZSTD Optimal mode + Copyright (C) 2016, Przemyslaw Skibinski, Yann Collet. -typedef struct -{ + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - Zstd source repository : https://www.zstd.net +*/ + +/* Note : this file is intended to be included within zstd_compress.c */ + +/*- Dependencies -*/ +#include +#include /* log */ + + +/*- Local types -*/ +typedef struct { U32 off; U32 len; U32 back; } ZSTD_match_t; -typedef struct -{ +typedef struct { U32 price; U32 off; U32 mlen; @@ -18,7 +54,11 @@ typedef struct U32 rep2; } ZSTD_optimal_t; +/*- Constants -*/ +#define ZSTD_OPT_NUM (1<<12) +#define ZSTD_FREQ_THRESHOLD (256) +/*- Debug -*/ #define ZSTD_OPT_DEBUG 0 // 1 = tableID=0; 5 = check encoded sequences #if 1 @@ -33,30 +73,25 @@ typedef struct #define ZSTD_LOG_TRY_PRICE(fmt, args...) ;//printf(fmt, ##args) -#define ZSTD_OPT_NUM (1<<12) -#define ZSTD_FREQ_THRESHOLD (256) - FORCE_INLINE U32 ZSTD_getLiteralPriceReal(seqStore_t* seqStorePtr, U32 litLength, const BYTE* literals) { - U32 price = 0; + U32 price, freq, u; - if (litLength > 0) { - U32 freq, u; - /* literals */ - for (u=0; u < litLength; u++) - price += ZSTD_highbit(seqStorePtr->litSum) - ZSTD_highbit(seqStorePtr->litFreq[literals[u]]); + if (!litLength) return 1; /* special case */ - /* literal Length */ - price += ((litLength >= MaxLL)*8) + ((litLength >= 255+MaxLL)*16) + ((litLength>=(1<<15))*8); - if (litLength >= MaxLL) litLength = MaxLL; - freq = seqStorePtr->litLengthFreq[litLength]; - price += ZSTD_highbit(seqStorePtr->litLengthSum) - ZSTD_highbit(freq); - /* note : seems that using matchLengthSum (litSum) - ZSTD_highbit(seqStorePtr->litFreq[literals[u]]); - return price + (price == 0); + /* literal Length */ + price += ((litLength >= MaxLL)*8) + ((litLength >= 255+MaxLL)*16) + ((litLength>=(1<<15))*8); + if (litLength >= MaxLL) litLength = MaxLL; + freq = seqStorePtr->litLengthFreq[litLength]; + price += ZSTD_highbit(seqStorePtr->litLengthSum) - ZSTD_highbit(freq); + + return price; } @@ -73,8 +108,6 @@ FORCE_INLINE U32 ZSTD_getLiteralPrice(seqStore_t* seqStorePtr, U32 litLength, co FORCE_INLINE U32 ZSTD_getMatchPriceReal(seqStore_t* seqStorePtr, U32 offset, U32 matchLength) { - U32 freq; - /* offset */ BYTE offCode = offset ? (BYTE)ZSTD_highbit(offset) + 1 : 0; U32 price = ZSTD_highbit(seqStorePtr->offCodeSum) - ZSTD_highbit(seqStorePtr->offCodeFreq[offCode]); @@ -83,8 +116,7 @@ FORCE_INLINE U32 ZSTD_getMatchPriceReal(seqStore_t* seqStorePtr, U32 offset, U32 /* match Length */ price += ((matchLength >= MaxML)*8) + ((matchLength >= 255+MaxML)*16) + ((matchLength>=(1<<15))*8); if (matchLength >= MaxML) matchLength = MaxML; - freq = seqStorePtr->matchLengthFreq[matchLength]; - price += ZSTD_highbit(seqStorePtr->matchLengthSum) - ZSTD_highbit(freq); + price += ZSTD_highbit(seqStorePtr->matchLengthSum) - ZSTD_highbit(seqStorePtr->matchLengthFreq[matchLength]); return price; } @@ -103,13 +135,7 @@ FORCE_INLINE U32 ZSTD_getPrice(seqStore_t* seqStorePtr, U32 litLength, const BYT MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength) { U32 u; -#if 0 - static const BYTE* g_start = NULL; - if (g_start==NULL) g_start = literals; - //if (literals - g_start == 8695) - printf("pos %6u : %3u literals & match %3u bytes at distance %6u \n", - (U32)(literals - g_start), (U32)litLength, (U32)matchLength+4, (U32)offset); -#endif + /* literals */ seqStorePtr->litSum += litLength; for (u=0; u < litLength; u++) @@ -149,7 +175,7 @@ MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, U32 litLength, const B -/* ************************************* +/*-************************************* * Binary Tree search ***************************************/ FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ @@ -165,8 +191,6 @@ U32 ZSTD_insertBtAndGetAllMatches ( const size_t h = ZSTD_hashPtr(ip, hashLog, mls); U32* const hashTable = zc->hashTable; U32 matchIndex = hashTable[h]; - if (matchIndex >= current) return 0; - U32* const bt = zc->contentTable; const U32 btLog = zc->params.contentLog - 1; const U32 btMask= (1U << btLog) - 1; @@ -183,6 +207,7 @@ U32 ZSTD_insertBtAndGetAllMatches ( U32 dummy32; /* to be nullified at the end */ U32 mnum = 0; + if (matchIndex >= current) return 0; bestLength = MINMATCH-1; hashTable[h] = current; /* Update Hash Table */ @@ -334,18 +359,14 @@ U32 ZSTD_HcGetAllMatches_generic ( match = base + matchIndex; if (match[minml] == ip[minml]) /* potentially better */ currentMl = ZSTD_count(ip, match, iHighLimit); - if (currentMl > 0) { - while ((match-back > base) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ - currentMl += back; - } + while ((match-back > base) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ + currentMl += back; } else { match = dictBase + matchIndex; if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */ currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iHighLimit, dictEnd, prefixStart) + MINMATCH; - if (currentMl > 0) { - while ((match-back > dictStart) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ - currentMl += back; - } + while ((match-back > dictStart) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ + currentMl += back; } /* save best solution */ @@ -396,7 +417,7 @@ FORCE_INLINE U32 ZSTD_HcGetAllMatches_selectMLS_extDict ( } -/* ******************************* +/*-******************************* * Optimal parser *********************************/ FORCE_INLINE @@ -836,8 +857,8 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, const U32 repIndex = (U32)(current+1 - rep_1); const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; - if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ - if (MEM_read32(ip+1) == MEM_read32(repMatch)) { + if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ + && (MEM_read32(ip+1) == MEM_read32(repMatch)) ) { /* repcode detected we should take it */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; mlen = (U32)ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; @@ -879,18 +900,18 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, goto _storeSequence; } - // set prices using matches at position = 0 - for (u = 0; u < match_num; u++) { - mlen = (u>0) ? matches[u-1].len+1 : best_mlen; - best_mlen = (matches[u].len < ZSTD_OPT_NUM) ? matches[u].len : ZSTD_OPT_NUM; - ZSTD_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(ip-base), matches[u].len, matches[u].off, (int)best_mlen, (int)last_pos); - litlen = opt[0].litlen; - while (mlen <= best_mlen) { + // set prices using matches at position = 0 + for (u = 0; u < match_num; u++) { + mlen = (u>0) ? matches[u-1].len+1 : best_mlen; + best_mlen = (matches[u].len < ZSTD_OPT_NUM) ? matches[u].len : ZSTD_OPT_NUM; + ZSTD_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(ip-base), matches[u].len, matches[u].off, (int)best_mlen, (int)last_pos); + litlen = opt[0].litlen; + while (mlen <= best_mlen) { price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off, mlen - MINMATCH); if (mlen > last_pos || price < opt[mlen].price) SET_PRICE(mlen, mlen, matches[u].off, litlen, price); mlen++; - } } + } } if (last_pos < MINMATCH) { // ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */ @@ -899,8 +920,7 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, // check further positions - for (skip_num = 0, cur = 1; cur <= last_pos; cur++) - { + for (skip_num = 0, cur = 1; cur <= last_pos; cur++) { size_t cur_rep; inr = ip + cur; @@ -953,8 +973,7 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, if (!opt[cur].off && opt[cur].mlen != 1) { cur_rep = opt[cur].rep2; ZSTD_LOG_PARSER("%d: try REP2 rep2=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); - } - else { + } else { cur_rep = opt[cur].rep; ZSTD_LOG_PARSER("%d: try REP1 rep=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); } @@ -969,8 +988,7 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, mlen = (U32)ZSTD_count_2segments(inr+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep, cur, opt[cur].off); - if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) - { + if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) { best_mlen = mlen; best_off = 0; ZSTD_LOG_PARSER("%d: REP sufficient_len=%d best_mlen=%d best_off=%d last_pos=%d\n", (int)(inr-base), sufficient_len, best_mlen, best_off, last_pos); @@ -978,20 +996,15 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, goto _storeSequence; } - if (opt[cur].mlen == 1) - { + if (opt[cur].mlen == 1) { litlen = opt[cur].litlen; - if (cur > litlen) - { + if (cur > litlen) { price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, inr-litlen, 0, mlen - MINMATCH); ZSTD_LOG_TRY_PRICE("%d: TRY5 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); - } - else + } else price = ZSTD_getPrice(seqStorePtr, litlen, anchor, 0, mlen - MINMATCH); - } - else - { + } else { litlen = 0; price = opt[cur].price + ZSTD_getPrice(seqStorePtr, 0, NULL, 0, mlen - MINMATCH); ZSTD_LOG_TRY_PRICE("%d: TRY7 price=%d cur=%d litlen=0 getprice=%d\n", (int)(inr-base), price, cur, (int)ZSTD_getPrice(seqStorePtr, 0, NULL, 0, mlen - MINMATCH)); @@ -1003,22 +1016,15 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), mlen, 0, price, litlen, cur - litlen, opt[cur - litlen].price); - do - { + do { if (cur + mlen > last_pos || price <= opt[cur + mlen].price) // || ((price == opt[cur + mlen].price) && (opt[cur].mlen == 1) && (cur != litlen))) // at equal price prefer REP instead of MATCH SET_PRICE(cur + mlen, mlen, 0, litlen, price); mlen--; - } - while (mlen >= MINMATCH); + } while (mlen >= MINMATCH); } - if (faster_get_matches && skip_num > 0) - { - skip_num--; - continue; - } - + if (faster_get_matches && skip_num > 0) { skip_num--; continue; } best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; From 0db4115f35cc5c0183a5da91f9444542c90e7e25 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 10 Feb 2016 14:50:22 +0100 Subject: [PATCH 071/113] fixed debug print macros on Windows --- Makefile | 2 +- NEWS | 3 +++ lib/zstd_opt.c | 33 +++++++++++++++------------------ 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index e8b797da1..c80b20f39 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ # ################################################################ # force a version number : uncomment below export (otherwise, default to the one declared into zstd.h) -#export VERSION := 0.4.6 +#export VERSION := 0.5.1 PRGDIR = programs ZSTDDIR = lib diff --git a/NEWS b/NEWS index 46b170a10..170f0c824 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,6 @@ +v0.5.1 +New : Optimal parsing => Very high compression modes, thanks to Przemyslaw Skibinski + v0.5.0 New : dictionary builder utility Changed : streaming & dictionary API diff --git a/lib/zstd_opt.c b/lib/zstd_opt.c index e7ec6dd7c..1d2315689 100644 --- a/lib/zstd_opt.c +++ b/lib/zstd_opt.c @@ -54,6 +54,7 @@ typedef struct { U32 rep2; } ZSTD_optimal_t; + /*- Constants -*/ #define ZSTD_OPT_NUM (1<<12) #define ZSTD_FREQ_THRESHOLD (256) @@ -61,19 +62,16 @@ typedef struct { /*- Debug -*/ #define ZSTD_OPT_DEBUG 0 // 1 = tableID=0; 5 = check encoded sequences -#if 1 - #define ZSTD_LOG_PARSER(fmt, args...) ;// printf(fmt, ##args) - #define ZSTD_LOG_PRICE(fmt, args...) ;//printf(fmt, ##args) - #define ZSTD_LOG_ENCODE(fmt, args...) ;//printf(fmt, ##args) +#if defined(ZSTD_OPT_DEBUG) && ZSTD_OPT_DEBUG>=1 + #define ZSTD_LOG_PARSER(...) printf(__VA_ARGS__) + #define ZSTD_LOG_ENCODE(...) printf(__VA_ARGS__) + #define ZSTD_LOG_TRY_PRICE(...) printf(__VA_ARGS__) #else - #define ZSTD_LOG_PARSER(fmt, args...) printf(fmt, ##args) - #define ZSTD_LOG_PRICE(fmt, args...) printf(fmt, ##args) - #define ZSTD_LOG_ENCODE(fmt, args...) printf(fmt, ##args) + #define ZSTD_LOG_PARSER(...) + #define ZSTD_LOG_ENCODE(...) + #define ZSTD_LOG_TRY_PRICE(...) #endif -#define ZSTD_LOG_TRY_PRICE(fmt, args...) ;//printf(fmt, ##args) - - FORCE_INLINE U32 ZSTD_getLiteralPriceReal(seqStore_t* seqStorePtr, U32 litLength, const BYTE* literals) { @@ -131,7 +129,6 @@ FORCE_INLINE U32 ZSTD_getPrice(seqStore_t* seqStorePtr, U32 litLength, const BYT } - MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, U32 litLength, const BYTE* literals, U32 offset, U32 matchLength) { U32 u; @@ -516,7 +513,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, for (u = 0; u < match_num; u++) { mlen = (u>0) ? matches[u-1].len+1 : best_mlen; best_mlen = (matches[u].len < ZSTD_OPT_NUM) ? matches[u].len : ZSTD_OPT_NUM; - ZSTD_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(ip-base), matches[i].len, matches[i].off, (int)best_mlen, (int)last_pos); + ZSTD_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(ip-base), matches[u].len, matches[u].off, (int)best_mlen, (int)last_pos); litlen = opt[0].litlen; while (mlen <= best_mlen) { @@ -585,10 +582,10 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (!opt[cur].off && opt[cur].mlen != 1) { cur_rep = opt[cur].rep2; - ZSTD_LOG_PARSER("%d: try REP2 rep2=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); + ZSTD_LOG_PARSER("%d: try REP2 rep2=%u mlen=%u\n", (int)(inr-base), (U32)cur_rep, mlen); } else { cur_rep = opt[cur].rep; - ZSTD_LOG_PARSER("%d: try REP1 rep=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); + ZSTD_LOG_PARSER("%d: try REP1 rep=%u mlen=%u\n", (int)(inr-base), (U32)cur_rep, mlen); } @@ -655,7 +652,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, cur2 = cur - matches[u].back; best_mlen = (cur2 + matches[u].len < ZSTD_OPT_NUM) ? matches[u].len : ZSTD_OPT_NUM - cur2; - ZSTD_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(inr-base), cur, cur2, matches[u].len, matches[i].off, best_mlen, last_pos); + ZSTD_LOG_PARSER("%d: Found1 cur=%d cur2=%d mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(inr-base), cur, cur2, matches[u].len, matches[u].off, best_mlen, last_pos); if (mlen < matches[u].back + 1) mlen = matches[u].back + 1; @@ -972,10 +969,10 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, if (!opt[cur].off && opt[cur].mlen != 1) { cur_rep = opt[cur].rep2; - ZSTD_LOG_PARSER("%d: try REP2 rep2=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); + ZSTD_LOG_PARSER("%d: try REP2 rep2=%u mlen=%u\n", (int)(inr-base), (U32)cur_rep, mlen); } else { cur_rep = opt[cur].rep; - ZSTD_LOG_PARSER("%d: try REP1 rep=%d mlen=%d\n", (int)(inr-base), cur_rep, mlen); + ZSTD_LOG_PARSER("%d: try REP1 rep=%u mlen=%u\n", (int)(inr-base), (U32)cur_rep, mlen); } const U32 repIndex = (U32)(current+cur - cur_rep); @@ -1082,7 +1079,7 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, /* store sequence */ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set for (u = 1; u <= last_pos; u++) - ZSTD_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+u), u, last_pos, opt[u].price, opt[u].off, opt[u].mlen, opt[u]litlen, opt[u].rep, opt[u].rep2); + ZSTD_LOG_PARSER("%d: price[%u/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+u), u, last_pos, opt[u].price, opt[u].off, opt[u].mlen, opt[u].litlen, opt[u].rep, opt[u].rep2); ZSTD_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-base+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); opt[0].mlen = 1; From 3b63f7fbb0daf3a4e32a2b7a5bed462b67604ca4 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 10 Feb 2016 15:05:12 +0100 Subject: [PATCH 072/113] change zstd_opt.c into zstd_opt.h, since it's included --- lib/zstd_compress.c | 2 +- lib/{zstd_opt.c => zstd_opt.h} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename lib/{zstd_opt.c => zstd_opt.h} (100%) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 6ca31895e..db774ccd8 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -1697,7 +1697,7 @@ _storeSequence: } } -#include "zstd_opt.c" +#include "zstd_opt.h" static void ZSTD_compressBlock_opt_bt(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { diff --git a/lib/zstd_opt.c b/lib/zstd_opt.h similarity index 100% rename from lib/zstd_opt.c rename to lib/zstd_opt.h From 62ae262771c2ad1e0a8f993f9d4d44d19e64c463 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 10 Feb 2016 15:44:07 +0100 Subject: [PATCH 073/113] restored currentMl>0 condition, as suggested by @inikep --- lib/zstd_opt.h | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/lib/zstd_opt.h b/lib/zstd_opt.h index 1d2315689..951bc7322 100644 --- a/lib/zstd_opt.h +++ b/lib/zstd_opt.h @@ -34,8 +34,7 @@ /* Note : this file is intended to be included within zstd_compress.c */ /*- Dependencies -*/ -#include -#include /* log */ +#include /* for debug */ /*- Local types -*/ @@ -356,14 +355,17 @@ U32 ZSTD_HcGetAllMatches_generic ( match = base + matchIndex; if (match[minml] == ip[minml]) /* potentially better */ currentMl = ZSTD_count(ip, match, iHighLimit); - while ((match-back > base) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ - currentMl += back; + if (currentMl>0) { + while ((match-back > base) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ + currentMl += back; + } } else { match = dictBase + matchIndex; - if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */ + if (MEM_read32(match) == MEM_read32(ip)) { /* assumption : matchIndex <= dictLimit-4 (by table construction) */ currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iHighLimit, dictEnd, prefixStart) + MINMATCH; - while ((match-back > dictStart) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ - currentMl += back; + while ((match-back > dictStart) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ + currentMl += back; + } } /* save best solution */ @@ -463,7 +465,6 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, inr = ip; opt[0].litlen = (U32)(ip - anchor); - /* check repCode */ if (MEM_read32(ip+1) == MEM_read32(ip+1 - rep_1)) { /* repcode : we take it */ @@ -476,14 +477,12 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } litlen = opt[0].litlen + 1; - do - { + do { price = ZSTD_getPrice(seqStorePtr, litlen, anchor, 0, mlen - MINMATCH); if (mlen + 1 > last_pos || price < opt[mlen + 1].price) - SET_PRICE(mlen + 1, mlen, 0, litlen, price); + SET_PRICE(mlen + 1, mlen, 0, litlen, price); /* note : macro modifies last_pos */ mlen--; - } - while (mlen >= MINMATCH); + } while (mlen >= MINMATCH); } @@ -515,17 +514,15 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, best_mlen = (matches[u].len < ZSTD_OPT_NUM) ? matches[u].len : ZSTD_OPT_NUM; ZSTD_LOG_PARSER("%d: start Found mlen=%d off=%d best_mlen=%d last_pos=%d\n", (int)(ip-base), matches[u].len, matches[u].off, (int)best_mlen, (int)last_pos); litlen = opt[0].litlen; - while (mlen <= best_mlen) - { + while (mlen <= best_mlen) { price = ZSTD_getPrice(seqStorePtr, litlen, anchor, matches[u].off, mlen - MINMATCH); if (mlen > last_pos || price < opt[mlen].price) SET_PRICE(mlen, mlen, matches[u].off, litlen, price); mlen++; - } - } + } } if (last_pos < MINMATCH) { - // ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */ + // ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */ ip++; continue; } From b79a0b34f394acb8a8182bcbe5894c2d3ec64880 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 10 Feb 2016 17:07:37 +0100 Subject: [PATCH 074/113] paramgrill supports sufficientLength stronger variation for ZSTD_opt --- lib/zstd_compress.c | 4 ++-- lib/zstd_opt.h | 15 +++++---------- programs/paramgrill.c | 4 ++-- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index db774ccd8..d59ff12ae 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -2341,8 +2341,8 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 0, 25, 24, 23, 5, 5, ZSTD_btlazy2 }, /* level 18 */ { 0, 0, 25, 26, 23, 5, 5, ZSTD_btlazy2 }, /* level 19 */ { 0, 0, 26, 27, 25, 9, 5, ZSTD_btlazy2 }, /* level 20 */ - { 0, 0, 22, 20, 22, 4, 4, ZSTD_lazy2 }, /* level 21 = 11 + L=4 */ // 41902762 lazy1=42087013 norep1=42911693 - { 0, 0, 23, 21, 22, 5, 4, ZSTD_btlazy2 }, /* level 22 = 16 + L=4 */ // 41233150 btlazy1=41560211 norep1=42322286 + { 0, 0, 23, 21, 22, 5, 4, ZSTD_btlazy2 }, /* level 21 = 16 + L=4 */ // 41233150 btlazy1=41560211 norep1=42322286 + { 0, 12, 23, 21, 22, 5, 4, ZSTD_opt }, /* level 22 */ { 0, 32, 23, 21, 22, 5, 4, ZSTD_opt }, /* level 23 */ { 0, 32, 23, 21, 22, 5, 4, ZSTD_opt_bt }, /* level 24 = 16 + btopt */ { 0, 64, 26, 27, 25, 10, 4, ZSTD_opt_bt }, /* level 25 = 20 + btopt */ diff --git a/lib/zstd_opt.h b/lib/zstd_opt.h index 951bc7322..579558b11 100644 --- a/lib/zstd_opt.h +++ b/lib/zstd_opt.h @@ -92,7 +92,6 @@ FORCE_INLINE U32 ZSTD_getLiteralPriceReal(seqStore_t* seqStorePtr, U32 litLength } - FORCE_INLINE U32 ZSTD_getLiteralPrice(seqStore_t* seqStorePtr, U32 litLength, const BYTE* literals) { if (seqStorePtr->litSum > ZSTD_FREQ_THRESHOLD) @@ -102,7 +101,6 @@ FORCE_INLINE U32 ZSTD_getLiteralPrice(seqStore_t* seqStorePtr, U32 litLength, co } - FORCE_INLINE U32 ZSTD_getMatchPriceReal(seqStore_t* seqStorePtr, U32 offset, U32 matchLength) { /* offset */ @@ -304,8 +302,7 @@ FORCE_INLINE U32 ZSTD_BtGetAllMatches_selectMLS_extDict ( const BYTE* ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, U32 minml) { - if (iLowLimit) {}; // skip warnings - + (void)iLowLimit; switch(matchLengthSearch) { default : @@ -353,10 +350,9 @@ U32 ZSTD_HcGetAllMatches_generic ( nbAttempts--; if ((!extDict) || matchIndex >= dictLimit) { match = base + matchIndex; - if (match[minml] == ip[minml]) /* potentially better */ - currentMl = ZSTD_count(ip, match, iHighLimit); - if (currentMl>0) { - while ((match-back > base) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ + //if (match[minml] == ip[minml]) currentMl = ZSTD_count(ip, match, iHighLimit); if (currentMl>0) { // faster + if (MEM_read32(match) == MEM_read32(ip)) { currentMl = ZSTD_count(ip+MINMATCH, match+MINMATCH, iHighLimit)+MINMATCH; // stronger + while ((match-back > base) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; currentMl += back; } } else { @@ -365,8 +361,7 @@ U32 ZSTD_HcGetAllMatches_generic ( currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iHighLimit, dictEnd, prefixStart) + MINMATCH; while ((match-back > dictStart) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; /* backward match extension */ currentMl += back; - } - } + } } /* save best solution */ if (currentMl > minml) { diff --git a/programs/paramgrill.c b/programs/paramgrill.c index fd75aa327..e3f421277 100644 --- a/programs/paramgrill.c +++ b/programs/paramgrill.c @@ -421,7 +421,7 @@ static void BMK_printWinner(FILE* f, U32 cLevel, BMK_result_t result, ZSTD_param } -static U32 g_cSpeedTarget[NB_LEVELS_TRACKED] = { 0 }; /* NB_LEVELS_TRACKED : to check */ +static U32 g_cSpeedTarget[NB_LEVELS_TRACKED] = { 0 }; /* NB_LEVELS_TRACKED : checked at main() */ typedef struct { BMK_result_t result; @@ -559,7 +559,7 @@ static void paramVariation(ZSTD_parameters* p) { U32 nbChanges = (FUZ_rand(&g_rand) & 3) + 1; for (; nbChanges; nbChanges--) { - const U32 changeID = FUZ_rand(&g_rand) % 12; + const U32 changeID = FUZ_rand(&g_rand) % 14; switch(changeID) { case 0: From 490aa68b1809ad10807a92a833e9b21ca2171cf4 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 10 Feb 2016 17:18:24 +0100 Subject: [PATCH 075/113] restored fast zstd_opt variant --- lib/zstd_opt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/zstd_opt.h b/lib/zstd_opt.h index 579558b11..6fb94e21a 100644 --- a/lib/zstd_opt.h +++ b/lib/zstd_opt.h @@ -350,8 +350,8 @@ U32 ZSTD_HcGetAllMatches_generic ( nbAttempts--; if ((!extDict) || matchIndex >= dictLimit) { match = base + matchIndex; - //if (match[minml] == ip[minml]) currentMl = ZSTD_count(ip, match, iHighLimit); if (currentMl>0) { // faster - if (MEM_read32(match) == MEM_read32(ip)) { currentMl = ZSTD_count(ip+MINMATCH, match+MINMATCH, iHighLimit)+MINMATCH; // stronger + if (match[minml] == ip[minml]) currentMl = ZSTD_count(ip, match, iHighLimit); if (currentMl>0) { // faster + //if (MEM_read32(match) == MEM_read32(ip)) { currentMl = ZSTD_count(ip+MINMATCH, match+MINMATCH, iHighLimit)+MINMATCH; // stronger while ((match-back > base) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; currentMl += back; } From 448866167857a1efd812e026fbbcd998cd856568 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 11 Feb 2016 04:17:50 +0100 Subject: [PATCH 076/113] minor cosmetics --- lib/legacy/zstd_v04.c | 23 +++----- lib/mem.h | 4 +- lib/zstd_compress.c | 3 +- lib/zstd_opt.h | 124 +++++++++++++++--------------------------- programs/fileio.c | 20 +++---- programs/xxhash.c | 2 +- programs/zstdcli.c | 68 ++++++++--------------- 7 files changed, 87 insertions(+), 157 deletions(-) diff --git a/lib/legacy/zstd_v04.c b/lib/legacy/zstd_v04.c index 4a1399ec9..57d724c27 100644 --- a/lib/legacy/zstd_v04.c +++ b/lib/legacy/zstd_v04.c @@ -1465,7 +1465,7 @@ MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr) /* ************************************************************** -* Includes +* Dependencies ****************************************************************/ #include /* malloc, free, qsort */ #include /* memcpy, memset */ @@ -1499,7 +1499,7 @@ MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr) typedef U32 DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)]; -/* ************************************************************** +/*-************************************************************** * Templates ****************************************************************/ /* @@ -4249,39 +4249,32 @@ static size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDs ip += headerSize; headerSize = ZSTD_getFrameParams(&(zbc->params), zbc->headerBuffer, zbc->hPos); if (ZSTD_isError(headerSize)) return headerSize; - if (headerSize) - { + if (headerSize) { /* not enough input to decode header : tell how many bytes would be necessary */ *maxDstSizePtr = 0; return headerSize - zbc->hPos; - } - // zbc->stage = ZBUFFds_decodeHeader; break; /* useless : stage follows */ - } + } } case ZBUFFds_decodeHeader: /* apply header to create / resize buffers */ { size_t neededOutSize = (size_t)1 << zbc->params.windowLog; size_t neededInSize = BLOCKSIZE; /* a block is never > BLOCKSIZE */ - if (zbc->inBuffSize < neededInSize) - { + if (zbc->inBuffSize < neededInSize) { free(zbc->inBuff); zbc->inBuffSize = neededInSize; zbc->inBuff = (char*)malloc(neededInSize); if (zbc->inBuff == NULL) return ERROR(memory_allocation); } - if (zbc->outBuffSize < neededOutSize) - { + if (zbc->outBuffSize < neededOutSize) { free(zbc->outBuff); zbc->outBuffSize = neededOutSize; zbc->outBuff = (char*)malloc(neededOutSize); if (zbc->outBuff == NULL) return ERROR(memory_allocation); - } - } + } } if (zbc->dictSize) ZSTD_decompress_insertDictionary(zbc->zc, zbc->dict, zbc->dictSize); - if (zbc->hPos) - { + if (zbc->hPos) { /* some data already loaded into headerBuffer : transfer into inBuff */ memcpy(zbc->inBuff, zbc->headerBuffer, zbc->hPos); zbc->inPos = zbc->hPos; diff --git a/lib/mem.h b/lib/mem.h index 36ba06f06..a6606e51d 100644 --- a/lib/mem.h +++ b/lib/mem.h @@ -86,7 +86,7 @@ extern "C" { /*-************************************************************** * Memory I/O *****************************************************************/ -/*!MEM_FORCE_MEMORY_ACCESS +/* MEM_FORCE_MEMORY_ACCESS : * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable. * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal. * The below switch allow to select different access method for improved performance. @@ -178,7 +178,7 @@ MEM_STATIC void MEM_write64(void* memPtr, U64 value) memcpy(memPtr, &value, sizeof(value)); } -#endif // MEM_FORCE_MEMORY_ACCESS +#endif /* MEM_FORCE_MEMORY_ACCESS */ MEM_STATIC U16 MEM_readLE16(const void* memPtr) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index d59ff12ae..137058b5b 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -1043,8 +1043,7 @@ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc, continue; /* faster when present ... (?) */ } } } - /* Last Literals */ - { + { /* Last Literals */ size_t lastLLSize = iend - anchor; memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; diff --git a/lib/zstd_opt.h b/lib/zstd_opt.h index 6fb94e21a..8d9598db3 100644 --- a/lib/zstd_opt.h +++ b/lib/zstd_opt.h @@ -481,27 +481,27 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } - best_mlen = (last_pos) ? last_pos : MINMATCH; + best_mlen = (last_pos) ? last_pos : MINMATCH; - if (faster_get_matches && last_pos) + if (faster_get_matches && last_pos) match_num = 0; - else + else match_num = getAllMatches(ctx, ip, ip, iend, maxSearches, mls, matches, best_mlen); /* first search (depth 0) */ - ZSTD_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); - if (!last_pos && !match_num) { ip++; continue; } + ZSTD_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); + if (!last_pos && !match_num) { ip++; continue; } - opt[0].rep = rep_1; - opt[0].rep2 = rep_2; - opt[0].mlen = 1; + opt[0].rep = rep_1; + opt[0].rep2 = rep_2; + opt[0].mlen = 1; - if (match_num && matches[match_num-1].len > sufficient_len) { + if (match_num && matches[match_num-1].len > sufficient_len) { best_mlen = matches[match_num-1].len; best_off = matches[match_num-1].off; cur = 0; last_pos = 1; goto _storeSequence; - } + } // set prices using matches at position = 0 for (u = 0; u < match_num; u++) { @@ -523,8 +523,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, // check further positions - for (skip_num = 0, cur = 1; cur <= last_pos; cur++) - { + for (skip_num = 0, cur = 1; cur <= last_pos; cur++) { size_t cur_rep; inr = ip + cur; @@ -548,7 +547,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (cur == last_pos) break; - if (inr > ilimit) // last match must start at a minimum distance of 8 from oend + if (inr > ilimit) /* last match must start at a minimum distance of 8 from oend */ continue; mlen = opt[cur].mlen; @@ -582,15 +581,15 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (MEM_read32(inr) == MEM_read32(inr - cur_rep)) { // check rep - mlen = (U32)ZSTD_count(inr+MINMATCH, inr+MINMATCH - cur_rep, iend) + MINMATCH; - ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep, cur, opt[cur].off); + mlen = (U32)ZSTD_count(inr+MINMATCH, inr+MINMATCH - cur_rep, iend) + MINMATCH; + ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep, cur, opt[cur].off); - if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) { - best_mlen = mlen; - best_off = 0; - ZSTD_LOG_PARSER("%d: REP sufficient_len=%d best_mlen=%d best_off=%d last_pos=%d\n", (int)(inr-base), sufficient_len, best_mlen, best_off, last_pos); - last_pos = cur + 1; - goto _storeSequence; + if (mlen > sufficient_len || cur + mlen >= ZSTD_OPT_NUM) { + best_mlen = mlen; + best_off = 0; + ZSTD_LOG_PARSER("%d: REP sufficient_len=%d best_mlen=%d best_off=%d last_pos=%d\n", (int)(inr-base), sufficient_len, best_mlen, best_off, last_pos); + last_pos = cur + 1; + goto _storeSequence; } if (opt[cur].mlen == 1) { @@ -622,13 +621,11 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (faster_get_matches && skip_num > 0) { skip_num--; continue; } - best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; match_num = getAllMatches(ctx, inr, ip, iend, maxSearches, mls, matches, best_mlen); ZSTD_LOG_PARSER("%d: ZSTD_GetAllMatches match_num=%d\n", (int)(inr-base), match_num); - if (match_num > 0 && matches[match_num-1].len > sufficient_len) { cur -= matches[match_num-1].back; best_mlen = matches[match_num-1].len; @@ -637,7 +634,6 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, goto _storeSequence; } - /* set prices using matches at position = cur */ for (u = 0; u < match_num; u++) { mlen = (u>0) ? matches[u-1].len+1 : best_mlen; @@ -667,9 +663,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, SET_PRICE(cur2 + mlen, mlen, matches[u].off, litlen, price); mlen++; - } } - } // for (skip_num = 0, cur = 1; cur <= last_pos; cur++) - + } } } // for (skip_num = 0, cur = 1; cur <= last_pos; cur++) best_mlen = opt[last_pos].mlen; best_off = opt[last_pos].off; @@ -703,34 +697,25 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set u += opt[u].mlen; } - cur = 0; - - while (cur < last_pos) - { + for (cur=0; cur < last_pos; ) { ZSTD_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); mlen = opt[cur].mlen; if (mlen == 1) { ip++; cur++; continue; } offset = opt[cur].off; cur += mlen; - U32 litLength = (U32)(ip - anchor); ZSTD_LOG_ENCODE("%d/%d: ENCODE1 literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); - if (offset) - { + if (offset) { rep_2 = rep_1; rep_1 = offset; - } - else - { - if (litLength == 0) - { + } else { + if (litLength == 0) { best_off = rep_2; rep_2 = rep_1; rep_1 = best_off; - } - } + } } ZSTD_LOG_ENCODE("%d/%d: ENCODE2 literals=%d mlen=%d off=%d rep1=%d rep2=%d\n", (int)(ip-base), (int)(iend-base), (int)(litLength), (int)mlen, (int)(offset), (int)rep_1, (int)rep_2); @@ -759,8 +744,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set anchor = ip = ip + mlen; } - - // check immediate repcode + /* check immediate repcode */ while ( (anchor <= ilimit) && (MEM_read32(anchor) == MEM_read32(anchor - rep_2)) ) { /* store sequence */ @@ -774,13 +758,11 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set anchor += best_mlen+MINMATCH; ip = anchor; continue; // faster when present ... (?) - } - } + } } - /* Last Literals */ - { - U32 lastLLSize = (U32)(iend - anchor); - ZSTD_LOG_ENCODE("%d: lastLLSize literals=%d\n", (int)(ip-base), (int)(lastLLSize)); + { /* Last Literals */ + size_t lastLLSize = iend - anchor; + ZSTD_LOG_ENCODE("%d: lastLLSize literals=%u\n", (int)(ip-base), (U32)lastLLSize); memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } @@ -826,21 +808,16 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, ZSTD_resetSeqStore(seqStorePtr); if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE; - /* Match Loop */ while (ip < ilimit) { - U32 u; - U32 offset; - U32 mlen=0; - U32 best_mlen=0; - U32 best_off=0; + U32 u, offset, best_off=0; + U32 mlen=0, best_mlen=0; U32 current = (U32)(ip-base); memset(opt, 0, sizeof(ZSTD_optimal_t)); last_pos = 0; inr = ip; opt[0].litlen = (U32)(ip - anchor); - /* check repCode */ { const U32 repIndex = (U32)(current+1 - rep_1); @@ -872,7 +849,7 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, if (faster_get_matches && last_pos) match_num = 0; else - match_num = getAllMatches(ctx, ip, ip, iend, maxSearches, mls, matches, best_mlen); /* first search (depth 0) */ + match_num = getAllMatches(ctx, ip, ip, iend, maxSearches, mls, matches, best_mlen); /* first search (depth 0) */ ZSTD_LOG_PARSER("%d: match_num=%d last_pos=%d\n", (int)(ip-base), match_num, last_pos); if (!last_pos && !match_num) { ip++; continue; } @@ -907,8 +884,7 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, ip++; continue; } - - // check further positions + /* check further positions */ for (skip_num = 0, cur = 1; cur <= last_pos; cur++) { size_t cur_rep; inr = ip + cur; @@ -955,8 +931,6 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, ZSTD_LOG_PARSER("%d: CURRENT price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(inr-base), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); - - best_mlen = 0; if (!opt[cur].off && opt[cur].mlen != 1) { @@ -970,8 +944,8 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, const U32 repIndex = (U32)(current+cur - cur_rep); const BYTE* const repBase = repIndex < dictLimit ? dictBase : base; const BYTE* const repMatch = repBase + repIndex; - if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ - if (MEM_read32(inr) == MEM_read32(repMatch)) { + if ( ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */ + &&(MEM_read32(inr) == MEM_read32(repMatch)) ) { /* repcode detected */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; mlen = (U32)ZSTD_count_2segments(inr+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; @@ -983,11 +957,10 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, ZSTD_LOG_PARSER("%d: REP sufficient_len=%d best_mlen=%d best_off=%d last_pos=%d\n", (int)(inr-base), sufficient_len, best_mlen, best_off, last_pos); last_pos = cur + 1; goto _storeSequence; - } + } if (opt[cur].mlen == 1) { litlen = opt[cur].litlen; - if (cur > litlen) { price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, inr-litlen, 0, mlen - MINMATCH); ZSTD_LOG_TRY_PRICE("%d: TRY5 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); @@ -1000,8 +973,7 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, } best_mlen = mlen; - if (faster_get_matches) - skip_num = best_mlen; + if (faster_get_matches) skip_num = best_mlen; ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), mlen, 0, price, litlen, cur - litlen, opt[cur - litlen].price); @@ -1012,7 +984,6 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, } while (mlen >= MINMATCH); } - if (faster_get_matches && skip_num > 0) { skip_num--; continue; } best_mlen = (best_mlen > MINMATCH) ? best_mlen : MINMATCH; @@ -1020,7 +991,6 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, match_num = getAllMatches(ctx, inr, ip, iend, maxSearches, mls, matches, best_mlen); ZSTD_LOG_PARSER("%d: ZSTD_GetAllMatches match_num=%d\n", (int)(inr-base), match_num); - if (match_num > 0 && matches[match_num-1].len > sufficient_len) { cur -= matches[match_num-1].back; best_mlen = matches[match_num-1].len; @@ -1029,7 +999,6 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, goto _storeSequence; } - // set prices using matches at position = cur for (u = 0; u < match_num; u++) { mlen = (u>0) ? matches[u-1].len+1 : best_mlen; @@ -1059,9 +1028,7 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, SET_PRICE(cur2 + mlen, mlen, matches[u].off, litlen, price); mlen++; - } } - } // for (skip_num = 0, cur = 1; cur <= last_pos; cur++) - + } } } // for (skip_num = 0, cur = 1; cur <= last_pos; cur++) best_mlen = opt[last_pos].mlen; best_off = opt[last_pos].off; @@ -1084,8 +1051,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set opt[cur].off = best_off; best_mlen = mlen; best_off = offset; - if (mlen > cur) - break; + if (mlen > cur) break; cur -= mlen; } @@ -1144,7 +1110,6 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set anchor = ip = ip + mlen; } - /* check immediate repcode */ while (anchor <= ilimit) { const U32 repIndex = (U32)((anchor-base) - rep_2); @@ -1166,10 +1131,9 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set break; } } - /* Last Literals */ - { - U32 lastLLSize = (U32)(iend - anchor); - ZSTD_LOG_ENCODE("%d: lastLLSize literals=%d\n", (int)(ip-base), (int)(lastLLSize)); + { /* Last Literals */ + size_t lastLLSize = iend - anchor; + ZSTD_LOG_ENCODE("%d: lastLLSize literals=%u\n", (int)(ip-base), (U32)(lastLLSize)); memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } diff --git a/programs/fileio.c b/programs/fileio.c index ed2a06181..a5739ab4d 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -1,6 +1,6 @@ /* - fileio.c - File i/o handler - Copyright (C) Yann Collet 2013-2015 + fileio.c - File i/o handler for zstd + Copyright (C) Yann Collet 2013-2016 GPL v2 License @@ -19,8 +19,7 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. You can contact the author at : - - zstd source repository : https://github.com/Cyan4973/zstd - - Public forum : https://groups.google.com/forum/#!forum/lz4c + - zstd homepage : http://www.zstd.net */ /* Note : this is stand-alone program. @@ -33,7 +32,7 @@ * Tuning options ***************************************/ #ifndef ZSTD_LEGACY_SUPPORT -/**LEGACY_SUPPORT : +/* LEGACY_SUPPORT : * decompressor can decode older formats (starting from Zstd 0.1+) */ # define ZSTD_LEGACY_SUPPORT 1 #endif @@ -80,9 +79,6 @@ #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) # include /* _O_BINARY */ # include /* _setmode, _isatty */ -# ifdef __MINGW32__ - // int _fileno(FILE *stream); /* seems no longer useful /* MINGW somehow forgets to include this windows declaration into */ -# endif # define SET_BINARY_MODE(file) { int unused = _setmode(_fileno(file), _O_BINARY); (void)unused; } # define IS_CONSOLE(stdStream) _isatty(_fileno(stdStream)) #else @@ -317,10 +313,10 @@ static void FIO_freeCResources(cRess_t ress) } -/* - * FIO_compressFilename_extRess() - * result : 0 : compression completed correctly - * 1 : missing or pb opening srcFileName +/*! + * FIO_compressFilename_extRess() : + * @result : 0 : compression completed correctly, + * 1 : missing or pb opening srcFileName */ static int FIO_compressFilename_extRess(cRess_t ress, const char* dstFileName, const char* srcFileName, diff --git a/programs/xxhash.c b/programs/xxhash.c index d33113fe2..352d1e540 100644 --- a/programs/xxhash.c +++ b/programs/xxhash.c @@ -175,7 +175,7 @@ static U64 XXH_read64(const void* memPtr) return val; } -#endif // XXH_FORCE_DIRECT_MEMORY_ACCESS +#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ /* **************************************** diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 89027afd8..3f3c5cd51 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -1,6 +1,6 @@ /* zstdcli - Command Line Interface (cli) for zstd - Copyright (C) Yann Collet 2014-2015 + Copyright (C) Yann Collet 2014-2016 GPL v2 License @@ -19,8 +19,7 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. You can contact the author at : - - zstd source repository : https://github.com/Cyan4973/zstd - - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c + - zstd homepage : http://www.zstd.net/ */ /* Note : this is user program. @@ -30,14 +29,14 @@ */ -/************************************** +/*-************************************ * Compiler Options **************************************/ #define _CRT_SECURE_NO_WARNINGS /* Visual : removes warning from strcpy */ #define _POSIX_SOURCE 1 /* triggers fileno() within on unix */ -/************************************** +/*-************************************ * Includes **************************************/ #include /* fprintf, getchar */ @@ -50,7 +49,7 @@ #include "zstd.h" /* ZSTD version numbers */ -/************************************** +/*-************************************ * OS-specific Includes **************************************/ #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) @@ -68,7 +67,7 @@ #endif -/************************************** +/*-************************************ * Constants **************************************/ #define COMPRESSOR_NAME "zstd command line interface" @@ -88,16 +87,16 @@ #define GB *(1U<<30) -/************************************** +/*-************************************ * Display Macros **************************************/ #define DISPLAY(...) fprintf(displayOut, __VA_ARGS__) #define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); } static FILE* displayOut; -static unsigned displayLevel = 2; // 0 : no display // 1: errors // 2 : + result + interaction + warnings ; // 3 : + progression; // 4 : + information +static unsigned displayLevel = 2; /* 0 : no display, 1: errors, 2 : + result + interaction + warnings, 3 : + progression, 4 : + information */ -/************************************** +/*-************************************ * Exceptions **************************************/ #define DEBUG 0 @@ -112,7 +111,7 @@ static unsigned displayLevel = 2; // 0 : no display // 1: errors // 2 : + re } -/************************************** +/*-************************************ * Command Line **************************************/ static int usage(const char* programName) @@ -126,7 +125,6 @@ static int usage(const char* programName) DISPLAY( " -# : # compression level (1-19, default:1) \n"); DISPLAY( " -d : decompression \n"); DISPLAY( " -D file: use `file` as Dictionary \n"); - //DISPLAY( " -z : force compression\n"); DISPLAY( " -f : overwrite output without prompting \n"); DISPLAY( " -h/-H : display help/long help and exit\n"); return 0; @@ -203,10 +201,8 @@ int main(int argCount, const char** argv) if (!strcmp(programName, ZSTD_CAT)) { decode=1; forceStdout=1; displayLevel=1; outFileName=stdoutmark; } /* command switches */ - for(i=1; i try to select one automatically (when possible) */ if (filenameIdx>=2) outFileName = filenameTable[1]; - while (!outFileName) /* while : just to allow break statement */ - { + while (!outFileName) { /* while : just to allow break statement */ if (!IS_CONSOLE(stdout)) { outFileName=stdoutmark; break; } /* Default to stdout whenever possible (i.e. not a console) */ - if (!decode) /* compression to file */ - { + if (!decode) { /* compression to file */ size_t l = strlen(filenameTable[0]); dynNameSpace = (char*)calloc(1,l+5); if (dynNameSpace==NULL) { DISPLAY("not enough memory\n"); exit(1); } @@ -375,8 +359,7 @@ int main(int argCount, const char** argv) /* decompression to file (automatic name will work only if input filename has correct format extension) */ { size_t filenameSize = strlen(filenameTable[0]); - if (strcmp(filenameTable[0] + (filenameSize-4), extension)) - { + if (strcmp(filenameTable[0] + (filenameSize-4), extension)) { DISPLAYLEVEL(1, "unknown suffix - cannot determine destination filename\n"); return badusage(programName); } @@ -386,8 +369,7 @@ int main(int argCount, const char** argv) strcpy(dynNameSpace, filenameTable[0]); dynNameSpace[filenameSize-4]=0; DISPLAYLEVEL(2, "Decoding file %s \n", outFileName); - } - } + } } /* Check if output is defined as console; trigger an error in this case */ if (!strcmp(outFileName,stdoutmark) && IS_CONSOLE(stdout) && !forceStdout) return badusage(programName); @@ -396,23 +378,19 @@ int main(int argCount, const char** argv) if (!strcmp(filenameTable[0], stdinmark) && !strcmp(outFileName,stdoutmark) && (displayLevel==2)) displayLevel=1; if (multiple && (displayLevel==2)) displayLevel=1; - if ((!multiple) && (filenameIdx>2)) - { + if ((!multiple) && (filenameIdx>2)) { DISPLAY("Too many files on the command line (%u > 2). Do you mean -m ? \n", filenameIdx); return filenameIdx; } /* IO Stream/File */ FIO_setNotificationLevel(displayLevel); - if (decode) - { + if (decode) { if (multiple) operationResult = FIO_decompressMultipleFilenames(filenameTable, filenameIdx, ZSTD_EXTENSION, dictFileName); else operationResult = FIO_decompressFilename(outFileName, filenameTable[0], dictFileName); - } - else - { + } else { /* compression */ if (multiple) operationResult = FIO_compressMultipleFilenames(filenameTable, filenameIdx, ZSTD_EXTENSION, dictFileName, cLevel); else From bd828d9cd129d9c4c6c28a1f6f6e0c8d078e6440 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 11 Feb 2016 04:38:55 +0100 Subject: [PATCH 077/113] changed : sufficientLength => targetLength --- lib/zstd_compress.c | 2 +- lib/zstd_opt.h | 4 ++-- lib/zstd_static.h | 4 ++-- programs/paramgrill.c | 12 ++++++------ 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 137058b5b..dda6683e6 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -191,7 +191,7 @@ void ZSTD_validateParams(ZSTD_parameters* params) CLAMP(params->hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); CLAMP(params->searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); CLAMP(params->searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX); - CLAMP(params->sufficientLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX); + CLAMP(params->targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX); if ((U32)params->strategy>(U32)ZSTD_opt_bt) params->strategy = ZSTD_opt_bt; /* correct params, to use less memory */ diff --git a/lib/zstd_opt.h b/lib/zstd_opt.h index 8d9598db3..a936d3131 100644 --- a/lib/zstd_opt.h +++ b/lib/zstd_opt.h @@ -440,7 +440,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, const BYTE* inr; U32 skip_num, cur, cur2, match_num, last_pos, litlen, price; - const U32 sufficient_len = ctx->params.sufficientLength; + const U32 sufficient_len = ctx->params.targetLength; const U32 faster_get_matches = (ctx->params.strategy == ZSTD_opt); @@ -800,7 +800,7 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, const BYTE* inr; U32 skip_num, cur, cur2, match_num, last_pos, litlen, price; - const U32 sufficient_len = ctx->params.sufficientLength; + const U32 sufficient_len = ctx->params.targetLength; const U32 faster_get_matches = (ctx->params.strategy == ZSTD_opt); diff --git a/lib/zstd_static.h b/lib/zstd_static.h index 8b7d63b23..f31e63a28 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -27,7 +27,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - zstd source repository : https://github.com/Cyan4973/zstd + - zstd homepage : http://www.zstd.net */ #ifndef ZSTD_STATIC_H #define ZSTD_STATIC_H @@ -71,7 +71,7 @@ typedef enum { ZSTD_fast, ZSTD_greedy, ZSTD_lazy, ZSTD_lazy2, ZSTD_btlazy2, ZSTD typedef struct { U64 srcSize; /* optional : tells how much bytes are present in the frame. Use 0 if not known. */ - U32 sufficientLength; /* size of matches which is acceptable (used only by the optimal parser): larger == more compression, slower */ + U32 targetLength; /* acceptable match size for optimal parser (only) : larger == more compression, slower */ U32 windowLog; /* largest match distance : larger == more compression, more memory needed during decompression */ U32 contentLog; /* full search segment : larger == more compression, slower, more memory (useless for fast) */ U32 hashLog; /* dispatch table : larger == faster, more memory */ diff --git a/programs/paramgrill.c b/programs/paramgrill.c index e3f421277..b77f7a38c 100644 --- a/programs/paramgrill.c +++ b/programs/paramgrill.c @@ -265,7 +265,7 @@ static size_t BMK_benchParam(BMK_result_t* resultPtr, U32 Hlog = params.hashLog; U32 Slog = params.searchLog; U32 Slength = params.searchLength; - U32 Tlength = params.sufficientLength; + U32 Tlength = params.targetLength; ZSTD_strategy strat = params.strategy; char name[30] = { 0 }; U64 crcOrig; @@ -414,7 +414,7 @@ static void BMK_printWinner(FILE* f, U32 cLevel, BMK_result_t result, ZSTD_param DISPLAY("\r%79s\r", ""); fprintf(f," {%3u,%3u,%3u,%3u,%3u,%3u,%3u, %s }, ", 0, params.windowLog, params.contentLog, params.hashLog, params.searchLog, params.searchLength, - params.sufficientLength, g_stratName[(U32)(params.strategy)]); + params.targetLength, g_stratName[(U32)(params.strategy)]); fprintf(f, "/* level %2u */ /* R:%5.3f at %5.1f MB/s - %5.1f MB/s */\n", cLevel, (double)srcSize / result.cSize, (double)result.cSpeed / 1000., (double)result.dSpeed / 1000.); @@ -550,7 +550,7 @@ static ZSTD_parameters* sanitizeParams(ZSTD_parameters params) if (params.strategy == ZSTD_fast) g_params.contentLog = 0, g_params.searchLog = 0; if ((params.strategy != ZSTD_opt) && (params.strategy != ZSTD_opt_bt)) - g_params.sufficientLength = 0; + g_params.targetLength = 0; return &g_params; } @@ -587,9 +587,9 @@ static void paramVariation(ZSTD_parameters* p) case 11: p->strategy = (ZSTD_strategy)(((U32)p->strategy)-1); break; case 12: - p->sufficientLength *= 1 + ((double)(FUZ_rand(&g_rand)&255)) / 256.; break; + p->targetLength *= 1 + ((double)(FUZ_rand(&g_rand)&255)) / 256.; break; case 13: - p->sufficientLength /= 1 + ((double)(FUZ_rand(&g_rand)&255)) / 256.; break; + p->targetLength /= 1 + ((double)(FUZ_rand(&g_rand)&255)) / 256.; break; } } ZSTD_validateParams(p); @@ -647,7 +647,7 @@ static void potentialRandomParams(ZSTD_parameters* p, U32 inverseChance) p->searchLog = FUZ_rand(&g_rand) % (ZSTD_SEARCHLOG_MAX+1 - ZSTD_SEARCHLOG_MIN) + ZSTD_SEARCHLOG_MIN; p->windowLog = FUZ_rand(&g_rand) % (ZSTD_WINDOWLOG_MAX+1 - ZSTD_WINDOWLOG_MIN) + ZSTD_WINDOWLOG_MIN; p->searchLength=FUZ_rand(&g_rand) % (ZSTD_SEARCHLENGTH_MAX+1 - ZSTD_SEARCHLENGTH_MIN) + ZSTD_SEARCHLENGTH_MIN; - p->sufficientLength=FUZ_rand(&g_rand) % (ZSTD_TARGETLENGTH_MAX+1 - ZSTD_TARGETLENGTH_MIN) + ZSTD_TARGETLENGTH_MIN; + p->targetLength=FUZ_rand(&g_rand) % (ZSTD_TARGETLENGTH_MAX+1 - ZSTD_TARGETLENGTH_MIN) + ZSTD_TARGETLENGTH_MIN; p->strategy = (ZSTD_strategy) (FUZ_rand(&g_rand) % (ZSTD_opt_bt+1)); ZSTD_validateParams(p); } From 04b12d8bcb009b522d9ce58bc1e96f11a386a5f3 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 11 Feb 2016 06:23:24 +0100 Subject: [PATCH 078/113] paramgrill can select manually targetLength new compression levels --- lib/zstd_compress.c | 26 +++++++++++++------------- lib/zstd_opt.h | 16 ++++++---------- programs/paramgrill.c | 22 +++++++++++++--------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index dda6683e6..3ffacc81e 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -903,7 +903,7 @@ static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLim return (size_t)(pIn - pStart); } -/** ZSTD_count_2segments +/** ZSTD_count_2segments() : * can count match length with ip & match in potentially 2 different segments. * convention : on reaching mEnd, match count continue starting from iStart */ @@ -1190,11 +1190,11 @@ void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx, } -/* ************************************* +/*-************************************* * Binary Tree search ***************************************/ -/** ZSTD_insertBt1() : add one or multiple positions to tree -* ip : assumed <= iend-8 +/** ZSTD_insertBt1() : add one or multiple positions to tree. +* ip : assumed <= iend-8 . * @return : nb of positions added */ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares, U32 extDict) @@ -1230,7 +1230,7 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co while (nbCompares-- && (matchIndex > windowLow)) { U32* nextPtr = bt + 2*(matchIndex & btMask); size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */ - +#if 1 /* note : can create issues when hlog small <= 11 */ const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */ if (matchIndex == predictedSmall) { /* no need to check length, result known */ @@ -1249,7 +1249,7 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co predictedLarge = predictPtr[0] + (predictPtr[0]>0); continue; } - +#endif if ((!extDict) || (matchIndex+matchLength >= dictLimit)) { match = base + matchIndex; if (match[matchLength] == ip[matchLength]) @@ -1284,7 +1284,7 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co } } *smallerPtr = *largerPtr = 0; - return (matchEndIdx > current + 8) ? matchEndIdx - current - 8 : 1; + return (matchEndIdx > current + 8) ? (matchEndIdx - current) - 8 : 1; } @@ -2339,12 +2339,12 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 0, 23, 24, 23, 4, 5, ZSTD_btlazy2 }, /* level 17 */ { 0, 0, 25, 24, 23, 5, 5, ZSTD_btlazy2 }, /* level 18 */ { 0, 0, 25, 26, 23, 5, 5, ZSTD_btlazy2 }, /* level 19 */ - { 0, 0, 26, 27, 25, 9, 5, ZSTD_btlazy2 }, /* level 20 */ - { 0, 0, 23, 21, 22, 5, 4, ZSTD_btlazy2 }, /* level 21 = 16 + L=4 */ // 41233150 btlazy1=41560211 norep1=42322286 - { 0, 12, 23, 21, 22, 5, 4, ZSTD_opt }, /* level 22 */ - { 0, 32, 23, 21, 22, 5, 4, ZSTD_opt }, /* level 23 */ - { 0, 32, 23, 21, 22, 5, 4, ZSTD_opt_bt }, /* level 24 = 16 + btopt */ - { 0, 64, 26, 27, 25, 10, 4, ZSTD_opt_bt }, /* level 25 = 20 + btopt */ + { 0, 12, 22, 20, 21, 3, 5, ZSTD_opt }, /* level 20 */ + { 0, 16, 23, 21, 22, 4, 4, ZSTD_opt }, /* level 21 */ + { 0, 32, 25, 25, 24, 5, 4, ZSTD_opt_bt }, /* level 22 */ + { 0, 64, 25, 26, 24, 6, 4, ZSTD_opt_bt }, /* level 23 */ + { 0,128, 26, 26, 25, 8, 4, ZSTD_opt_bt }, /* level 24 */ + { 0,256, 26, 27, 25, 10, 4, ZSTD_opt_bt }, /* level 25 */ }, { /* for srcSize <= 256 KB */ /* SL, W, C, H, S, L, strat */ diff --git a/lib/zstd_opt.h b/lib/zstd_opt.h index a936d3131..b968bdb0a 100644 --- a/lib/zstd_opt.h +++ b/lib/zstd_opt.h @@ -269,7 +269,7 @@ U32 ZSTD_BtGetAllMatches ( } -FORCE_INLINE U32 ZSTD_BtGetAllMatches_selectMLS ( +static U32 ZSTD_BtGetAllMatches_selectMLS ( ZSTD_CCtx* zc, /* Index table will be updated */ const BYTE* ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, U32 minml) @@ -297,7 +297,7 @@ U32 ZSTD_BtGetAllMatches_extDict ( } -FORCE_INLINE U32 ZSTD_BtGetAllMatches_selectMLS_extDict ( +static U32 ZSTD_BtGetAllMatches_selectMLS_extDict ( ZSTD_CCtx* zc, /* Index table will be updated */ const BYTE* ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, U32 minml) @@ -382,7 +382,7 @@ U32 ZSTD_HcGetAllMatches_generic ( } -FORCE_INLINE U32 ZSTD_HcGetAllMatches_selectMLS ( +static U32 ZSTD_HcGetAllMatches_selectMLS ( ZSTD_CCtx* zc, const BYTE* ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, U32 minml) @@ -396,7 +396,7 @@ FORCE_INLINE U32 ZSTD_HcGetAllMatches_selectMLS ( } } -FORCE_INLINE U32 ZSTD_HcGetAllMatches_selectMLS_extDict ( +static U32 ZSTD_HcGetAllMatches_selectMLS_extDict ( ZSTD_CCtx* zc, const BYTE* ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, const U32 maxNbAttempts, const U32 matchLengthSearch, ZSTD_match_t* matches, U32 minml) @@ -769,7 +769,6 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set } - FORCE_INLINE void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, const void* src, size_t srcSize, @@ -803,7 +802,6 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, const U32 sufficient_len = ctx->params.targetLength; const U32 faster_get_matches = (ctx->params.strategy == ZSTD_opt); - /* init */ ZSTD_resetSeqStore(seqStorePtr); if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE; @@ -1055,14 +1053,12 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set cur -= mlen; } - for (u = 0; u <= last_pos;) { + for (u = 0; u <= last_pos; ) { ZSTD_LOG_PARSER("%d: price2[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+u), u, last_pos, opt[u].price, opt[u].off, opt[u].mlen, opt[u].litlen, opt[u].rep, opt[u].rep2); u += opt[u].mlen; } - cur = 0; - - while (cur < last_pos) { + for (cur=0; cur < last_pos; ) { U32 litLength; ZSTD_LOG_PARSER("%d: price3[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+cur), cur, last_pos, opt[cur].price, opt[cur].off, opt[cur].mlen, opt[cur].litlen, opt[cur].rep, opt[cur].rep2); mlen = opt[cur].mlen; diff --git a/programs/paramgrill.c b/programs/paramgrill.c index b77f7a38c..5ba3afab2 100644 --- a/programs/paramgrill.c +++ b/programs/paramgrill.c @@ -930,7 +930,7 @@ int optimizeForSize(char* inFileName) } -int usage(char* exename) +static int usage(char* exename) { DISPLAY( "Usage :\n"); DISPLAY( " %s [arg] file\n", exename); @@ -940,16 +940,17 @@ int usage(char* exename) return 0; } -int usage_advanced(void) +static int usage_advanced(void) { DISPLAY( "\nAdvanced options :\n"); DISPLAY( " -i# : iteration loops [1-9](default : %i)\n", NBLOOPS); DISPLAY( " -B# : cut input into blocks of size # (default : single block)\n"); DISPLAY( " -P# : generated sample compressibility (default : %.1f%%)\n", COMPRESSIBILITY_DEFAULT * 100); + DISPLAY( " -S : Single run\n"); return 0; } -int badusage(char* exename) +static int badusage(char* exename) { DISPLAY("Wrong parameters\n"); usage(exename); @@ -1064,13 +1065,16 @@ int main(int argc, char** argv) while ((*argument>= '0') && (*argument<='9')) g_params.searchLength *= 10, g_params.searchLength += *argument++ - '0'; continue; - case 't': /* strategy */ - g_params.strategy = (ZSTD_strategy)0; + case 't': /* target length */ + g_params.targetLength = 0; argument++; - while ((*argument>= '0') && (*argument<='9')) { - g_params.strategy = (ZSTD_strategy)((U32)g_params.strategy *10); - g_params.strategy = (ZSTD_strategy)((U32)g_params.strategy + *argument++ - '0'); - } + while ((*argument>= '0') && (*argument<='9')) + g_params.targetLength *= 10, g_params.targetLength += *argument++ - '0'; + continue; + case 'S': /* strategy */ + argument++; + while ((*argument>= '0') && (*argument<='9')) + g_params.strategy = (ZSTD_strategy)(*argument++ - '0'); continue; case 'L': { From 82260ddd8afd092fd174577f42de1c7612fde1a3 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 11 Feb 2016 07:14:25 +0100 Subject: [PATCH 079/113] fixed asan read error in ZSTD_HcGetAllMatches --- lib/zstd_compress.c | 40 +++++++++++++++++----------------------- lib/zstd_opt.h | 10 ++-------- 2 files changed, 19 insertions(+), 31 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 3ffacc81e..39e996c2d 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -1051,7 +1051,7 @@ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc, } -void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx, +static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { const U32 mls = ctx->params.searchLength; @@ -1070,8 +1070,7 @@ void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx, } -//FORCE_INLINE -void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, +static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, const void* src, size_t srcSize, const U32 mls) { @@ -1171,7 +1170,7 @@ void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, } -void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx, +static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { const U32 mls = ctx->params.searchLength; @@ -1288,18 +1287,7 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co } -static void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls) -{ - const BYTE* const base = zc->base; - const U32 target = (U32)(ip - base); - U32 idx = zc->nextToUpdate; - - for( ; idx < target ; ) - idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0); -} - -FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ -size_t ZSTD_insertBtAndFindBestMatch ( +static size_t ZSTD_insertBtAndFindBestMatch ( ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, size_t* offsetPtr, @@ -1378,9 +1366,17 @@ size_t ZSTD_insertBtAndFindBestMatch ( } +static void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls) +{ + const BYTE* const base = zc->base; + const U32 target = (U32)(ip - base); + U32 idx = zc->nextToUpdate; + + while(idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0); +} + /** Tree updater, providing best match */ -FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ -size_t ZSTD_BtFindBestMatch ( +static size_t ZSTD_BtFindBestMatch ( ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iLimit, size_t* offsetPtr, @@ -1414,14 +1410,12 @@ static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const B const U32 target = (U32)(ip - base); U32 idx = zc->nextToUpdate; - for( ; idx < target ; ) - idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1); + while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1); } /** Tree updater, providing best match */ -FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ -size_t ZSTD_BtFindBestMatch_extDict ( +static size_t ZSTD_BtFindBestMatch_extDict ( ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iLimit, size_t* offsetPtr, @@ -1433,7 +1427,7 @@ size_t ZSTD_BtFindBestMatch_extDict ( } -FORCE_INLINE size_t ZSTD_BtFindBestMatch_selectMLS_extDict ( +static size_t ZSTD_BtFindBestMatch_selectMLS_extDict ( ZSTD_CCtx* zc, /* Index table will be updated */ const BYTE* ip, const BYTE* const iLimit, size_t* offsetPtr, diff --git a/lib/zstd_opt.h b/lib/zstd_opt.h index b968bdb0a..1ea88f103 100644 --- a/lib/zstd_opt.h +++ b/lib/zstd_opt.h @@ -352,7 +352,7 @@ U32 ZSTD_HcGetAllMatches_generic ( match = base + matchIndex; if (match[minml] == ip[minml]) currentMl = ZSTD_count(ip, match, iHighLimit); if (currentMl>0) { // faster //if (MEM_read32(match) == MEM_read32(ip)) { currentMl = ZSTD_count(ip+MINMATCH, match+MINMATCH, iHighLimit)+MINMATCH; // stronger - while ((match-back > base) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; + while ((match-back > prefixStart) && (ip-back > iLowLimit) && (ip[-back-1] == match[-back-1])) back++; currentMl += back; } } else { @@ -448,7 +448,6 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_resetSeqStore(seqStorePtr); if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE; - /* Match Loop */ while (ip < ilimit) { U32 u; @@ -480,7 +479,6 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } while (mlen >= MINMATCH); } - best_mlen = (last_pos) ? last_pos : MINMATCH; if (faster_get_matches && last_pos) @@ -579,7 +577,6 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_LOG_PARSER("%d: try REP1 rep=%u mlen=%u\n", (int)(inr-base), (U32)cur_rep, mlen); } - if (MEM_read32(inr) == MEM_read32(inr - cur_rep)) { // check rep mlen = (U32)ZSTD_count(inr+MINMATCH, inr+MINMATCH - cur_rep, iend) + MINMATCH; ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d rep=%d opt[%d].off=%d\n", (int)(inr-base), mlen, 0, opt[cur].rep, cur, opt[cur].off); @@ -594,7 +591,6 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, if (opt[cur].mlen == 1) { litlen = opt[cur].litlen; - if (cur > litlen) { price = opt[cur - litlen].price + ZSTD_getPrice(seqStorePtr, litlen, inr-litlen, 0, mlen - MINMATCH); ZSTD_LOG_TRY_PRICE("%d: TRY5 opt[%d].price=%d price=%d cur=%d litlen=%d\n", (int)(inr-base), cur - litlen, opt[cur - litlen].price, price, cur, litlen); @@ -607,9 +603,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, } best_mlen = mlen; - if (faster_get_matches) - skip_num = best_mlen; - + if (faster_get_matches) skip_num = best_mlen; ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), mlen, 0, price, litlen, cur - litlen, opt[cur - litlen].price); do { From 7d3602807891e54673867524821a2fa4a9709cc3 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 12 Feb 2016 00:07:30 +0100 Subject: [PATCH 080/113] Integrate dictBuilder into libzstd --- dictBuilder/Makefile | 7 +- dictBuilder/dibcli.c | 8 +- dictBuilder/dibio.c | 281 ++++ dictBuilder/dibio.h | 64 + dictBuilder/dictBuilder.h | 94 -- dictBuilder/dictionary | Bin 0 -> 112640 bytes dictBuilder/divsufsort.c | 404 ----- dictBuilder/divsufsort.h | 180 -- dictBuilder/divsufsort_private.h | 212 --- dictBuilder/lfs.h | 56 - dictBuilder/sssort.c | 844 ---------- dictBuilder/trsort.c | 615 ------- dictBuilder/utils.c | 381 ----- lib/Makefile | 6 +- {dictBuilder => lib}/dictBuilder.c | 348 ++-- lib/dictBuilder.h | 67 + lib/dictBuilder_static.h | 104 ++ lib/divsufsort.c | 1905 ++++++++++++++++++++++ dictBuilder/config.h => lib/divsufsort.h | 72 +- lib/mem.h | 11 +- lib/zstd.h | 2 +- lib/zstd_compress.c | 78 +- lib/zstd_internal.h | 65 +- lib/zstd_static.h | 7 +- 24 files changed, 2658 insertions(+), 3153 deletions(-) create mode 100644 dictBuilder/dibio.c create mode 100644 dictBuilder/dibio.h delete mode 100644 dictBuilder/dictBuilder.h create mode 100644 dictBuilder/dictionary delete mode 100644 dictBuilder/divsufsort.c delete mode 100644 dictBuilder/divsufsort.h delete mode 100644 dictBuilder/divsufsort_private.h delete mode 100644 dictBuilder/lfs.h delete mode 100644 dictBuilder/sssort.c delete mode 100644 dictBuilder/trsort.c delete mode 100644 dictBuilder/utils.c rename {dictBuilder => lib}/dictBuilder.c (72%) create mode 100644 lib/dictBuilder.h create mode 100644 lib/dictBuilder_static.h create mode 100644 lib/divsufsort.c rename dictBuilder/config.h => lib/divsufsort.h (52%) diff --git a/dictBuilder/Makefile b/dictBuilder/Makefile index e5a4f1aa7..949995253 100644 --- a/dictBuilder/Makefile +++ b/dictBuilder/Makefile @@ -1,6 +1,6 @@ # ########################################################################## # Dict Builder - Makefile -# Copyright (C) Yann Collet 2015 +# Copyright (C) Yann Collet 2016 # # GPL v2 License # @@ -19,8 +19,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # # You can contact the author at : -# - ZSTD source repository : http://code.google.com/p/zstd/ -# - Public forum : https://groups.google.com/forum/#!forum/lz4c +# - ZSTD homepage : http://www.zstd.net/ # ########################################################################## CPPFLAGS= -I../lib @@ -47,7 +46,7 @@ default: dictBuilder all: dictBuilder -dictBuilder: dictBuilder.c dibcli.c divsufsort.c sssort.c trsort.c $(ZSTDDIR)/huff0.c $(ZSTDDIR)/fse.c $(ZSTDDIR)/zstd_decompress.c +dictBuilder: dibio.c dibcli.c $(ZSTDDIR)/dictBuilder.c $(ZSTDDIR)/huff0.c $(ZSTDDIR)/fse.c $(ZSTDDIR)/zstd_decompress.c $(ZSTDDIR)/zstd_compress.c $(ZSTDDIR)/divsufsort.c $(CC) $(FLAGS) $^ -o $@$(EXT) clean: diff --git a/dictBuilder/dibcli.c b/dictBuilder/dibcli.c index 8566c6245..a8009ae63 100644 --- a/dictBuilder/dibcli.c +++ b/dictBuilder/dibcli.c @@ -37,8 +37,8 @@ #include /* exit, calloc, free */ #include /* strcmp, strlen */ #include /* fprintf, getchar */ - -#include "dictBuilder.h" +#include "dibio.h" +#include "zstd.h" /* version numbers */ /*-************************************ @@ -48,7 +48,7 @@ #ifndef PROGRAM_VERSION # define QUOTE(str) #str # define EXP_Q(str) QUOTE(str) -# define PROGRAM_VERSION "v" EXP_Q(DiB_VERSION_MAJOR) "." EXP_Q(DiB_VERSION_MINOR) "." EXP_Q(DiB_VERSION_RELEASE) +# define PROGRAM_VERSION "v" EXP_Q(ZSTD_VERSION_MAJOR) "." EXP_Q(ZSTD_VERSION_MINOR) "." EXP_Q(ZSTD_VERSION_RELEASE) #endif #define AUTHOR "Yann Collet" #define WELCOME_MESSAGE "*** %s %s %i-bits, by %s ***\n", PROGRAM_DESCRIPTION, PROGRAM_VERSION, (int)(sizeof(void*)*8), AUTHOR @@ -248,7 +248,7 @@ int main(int argCount, const char** argv) /* building ... */ { - DiB_params_t param; + ZDICT_params_t param; param.selectivityLevel = selectionLevel; param.compressionLevel = cLevel; DiB_setNotificationLevel(g_displayLevel); diff --git a/dictBuilder/dibio.c b/dictBuilder/dibio.c new file mode 100644 index 000000000..679b6504c --- /dev/null +++ b/dictBuilder/dibio.c @@ -0,0 +1,281 @@ +/* + dibio - I/O API for dictionary builder + Copyright (C) Yann Collet 2016 + + GPL v2 License + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + You can contact the author at : + - zstd homepage : http://www.zstd.net/ +*/ + +/*-************************************** +* Compiler Options +****************************************/ +/* Disable some Visual warning messages */ +#ifdef _MSC_VER +# define _CRT_SECURE_NO_WARNINGS /* fopen */ +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +#endif + +/* Unix Large Files support (>4GB) */ +#define _FILE_OFFSET_BITS 64 +#if (defined(__sun__) && (!defined(__LP64__))) /* Sun Solaris 32-bits requires specific definitions */ +# define _LARGEFILE_SOURCE +#elif ! defined(__LP64__) /* No point defining Large file for 64 bit */ +# define _LARGEFILE64_SOURCE +#endif + + +/*-************************************* +* Includes +***************************************/ +#include /* malloc, free */ +#include /* memset */ +#include /* fprintf, fopen, ftello64 */ +#include /* stat64 */ +#include /* stat64 */ +#include /* clock */ + +#include "mem.h" /* read */ +#include "error_private.h" +#include "dictBuilder_static.h" + +/*-************************************* +* Compiler specifics +***************************************/ +#if !defined(S_ISREG) +# define S_ISREG(x) (((x) & S_IFMT) == S_IFREG) +#endif + + +/*-************************************* +* Constants +***************************************/ +#define KB *(1 <<10) +#define MB *(1 <<20) +#define GB *(1U<<30) + +#define DICTLISTSIZE 10000 +#define MEMMULT 11 +static const size_t maxMemory = (sizeof(size_t) == 4) ? (2 GB - 64 MB) : ((size_t)(512 MB) << sizeof(size_t)); + +#define NOISELENGTH 32 +#define PRIME1 2654435761U +#define PRIME2 2246822519U + +#define MINRATIO 4 +static const U32 g_compressionLevel_default = 5; +static const U32 g_selectivity_default = 9; +static const size_t g_provision_entropySize = 200; +static const size_t g_min_fast_dictContent = 192; + + +/*-************************************* +* Console display +***************************************/ +#define DISPLAY(...) fprintf(stderr, __VA_ARGS__) +#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } +static unsigned g_displayLevel = 0; /* 0 : no display; 1: errors; 2: default; 4: full information */ +void DiB_setNotificationLevel(unsigned l) { g_displayLevel=l; ZDICT_setNotificationLevel(l); } + +void DiB_printHex(U32 dlevel, const void* ptr, size_t length) +{ + const BYTE* const b = (const BYTE*)ptr; + size_t u; + for (u=0; u126) c = '.'; /* non-printable char */ + DISPLAYLEVEL(dlevel, "%c", c); + } +} + + +/*-************************************* +* Exceptions +***************************************/ +#ifndef DEBUG +# define DEBUG 0 +#endif +#define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__); +#define EXM_THROW(error, ...) \ +{ \ + DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \ + DISPLAYLEVEL(1, "Error %i : ", error); \ + DISPLAYLEVEL(1, __VA_ARGS__); \ + DISPLAYLEVEL(1, "\n"); \ + exit(error); \ +} + + +/* ******************************************************** +* Helper functions +**********************************************************/ +unsigned DiB_isError(size_t errorCode) { return ERR_isError(errorCode); } + +const char* DiB_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); } + + +/* ******************************************************** +* File related operations +**********************************************************/ +static unsigned long long DiB_getFileSize(const char* infilename) +{ + int r; +#if defined(_MSC_VER) + struct _stat64 statbuf; + r = _stat64(infilename, &statbuf); +#else + struct stat statbuf; + r = stat(infilename, &statbuf); +#endif + if (r || !S_ISREG(statbuf.st_mode)) return 0; /* No good... */ + return (unsigned long long)statbuf.st_size; +} + + +static unsigned long long DiB_getTotalFileSize(const char** fileNamesTable, unsigned nbFiles) +{ + unsigned long long total = 0; + unsigned n; + for (n=0; n bufferSize-pos) fileSize = 0; /* stop there, not enough memory to load all files */ + readSize = fread(buff+pos, 1, (size_t)fileSize, f); + if (readSize != (size_t)fileSize) EXM_THROW(11, "could not read %s", fileNamesTable[n]); + pos += readSize; + fileSizes[n] = (size_t)fileSize; + fclose(f); + } +} + + +/*-******************************************************** +* Dictionary training functions +**********************************************************/ +static size_t DiB_findMaxMem(unsigned long long requiredMem) +{ + size_t step = 8 MB; + void* testmem = NULL; + + requiredMem = (((requiredMem >> 23) + 1) << 23); + requiredMem += 2 * step; + if (requiredMem > maxMemory) requiredMem = maxMemory; + + while (!testmem) { + requiredMem -= step; + testmem = malloc((size_t)requiredMem); + } + + free(testmem); + return (size_t)(requiredMem - step); +} + + +static void DiB_fillNoise(void* buffer, size_t length) +{ + unsigned acc = PRIME1; + size_t p=0;; + + for (p=0; p> 21); + } +} + + +static void DiB_saveDict(const char* dictFileName, + const void* buff, size_t buffSize) +{ + FILE* f; + size_t n; + + f = fopen(dictFileName, "wb"); + if (f==NULL) EXM_THROW(3, "cannot open %s ", dictFileName); + + n = fwrite(buff, 1, buffSize, f); + if (n!=buffSize) EXM_THROW(4, "%s : write error", dictFileName) + + n = (size_t)fclose(f); + if (n!=0) EXM_THROW(5, "%s : flush error", dictFileName) +} + + +int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, + const char** fileNamesTable, unsigned nbFiles, + ZDICT_params_t params) +{ + void* srcBuffer; + size_t benchedSize; + size_t* fileSizes = (size_t*)malloc(nbFiles * sizeof(size_t)); + unsigned long long totalSizeToLoad = DiB_getTotalFileSize(fileNamesTable, nbFiles); + void* dictBuffer = malloc(maxDictSize); + size_t dictSize; + int result = 0; + + /* init */ + benchedSize = DiB_findMaxMem(totalSizeToLoad * MEMMULT) / MEMMULT; + if ((unsigned long long)benchedSize > totalSizeToLoad) benchedSize = (size_t)totalSizeToLoad; + if (benchedSize < totalSizeToLoad) + DISPLAYLEVEL(1, "Not enough memory; training on %u MB only...\n", (unsigned)(benchedSize >> 20)); + + /* Memory allocation & restrictions */ + srcBuffer = malloc(benchedSize+NOISELENGTH); /* + noise */ + if ((!fileSizes) || (!srcBuffer) || (!dictBuffer)) EXM_THROW(12, "not enough memory for DiB_trainFiles"); /* should not happen */ + + /* Load input buffer */ + DiB_loadFiles(srcBuffer, benchedSize, fileSizes, fileNamesTable, nbFiles); + DiB_fillNoise((char*)srcBuffer + benchedSize, NOISELENGTH); /* guard band, for end of buffer condition */ + + /* call buffer version */ + dictSize = ZDICT_trainFromBuffer_unsafe(dictBuffer, maxDictSize, + srcBuffer, fileSizes, nbFiles, + params); + if (ZDICT_isError(dictSize)) { + DISPLAYLEVEL(1, "dictionary training failed : %s", ZDICT_getErrorName(dictSize)); /* should not happen */ + result = 1; + goto _cleanup; + } + + /* save dict */ + DISPLAYLEVEL(2, "Save dictionary of size %u into file %s \n", (U32)dictSize, dictFileName); + DiB_saveDict(dictFileName, dictBuffer, dictSize); + + /* clean up */ +_cleanup: + free(srcBuffer); + free(dictBuffer); + free(fileSizes); + return result; +} diff --git a/dictBuilder/dibio.h b/dictBuilder/dibio.h new file mode 100644 index 000000000..c9aee1fcd --- /dev/null +++ b/dictBuilder/dibio.h @@ -0,0 +1,64 @@ +/* + dibio.h - I/O API for dictionary builder + Copyright (C) Yann Collet 2016 + + GPL v2 License + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + You can contact the author at : + - zstd source repository : https://github.com/Cyan4973/zstd + - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c +*/ + +/* This library is designed for a single-threaded console application. +* It exit() and printf() into stderr when it encounters an error condition. */ + +#ifndef DIBIO_H_003 +#define DIBIO_H_003 + + +/*-************************************* +* Dependencies +***************************************/ +#include "dictBuilder_static.h" /* ZDICT_params_t */ + + +/*-************************************* +* Public functions +***************************************/ +/*! DiB_trainFromFiles() : + Train a dictionary from a set of files provided by `fileNamesTable`. + Resulting dictionary is written into file `dictFileName`. + `parameters` is optional and can be provided with values set to 0, meaning "default". + @return : 0 == ok. Any other : error. +*/ +int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, + const char** fileNamesTable, unsigned nbFiles, + ZDICT_params_t parameters); + + +/*-************************************* +* Helper functions +***************************************/ +/*! DiB_setNotificationLevel + Set amount of notification to be displayed on the console. + default initial value : 0 = no console notification. + Note : not thread-safe (use a global constant) +*/ +void DiB_setNotificationLevel(unsigned l); + + +#endif diff --git a/dictBuilder/dictBuilder.h b/dictBuilder/dictBuilder.h deleted file mode 100644 index a022583eb..000000000 --- a/dictBuilder/dictBuilder.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - dictBuilder.h - Copyright (C) Yann Collet 2016 - - GPL v2 License - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - - You can contact the author at : - - zstd source repository : https://github.com/Cyan4973/zstd - - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c -*/ - -/* This library is designed for a single-threaded console application. -* It exit() and printf() into stderr when it encounters an error condition. */ - -#ifndef DICTBUILDER_H_001 -#define DICTBUILDER_H_001 - -/*-************************************* -* Version -***************************************/ -#define DiB_VERSION_MAJOR 0 /* for breaking interface changes */ -#define DiB_VERSION_MINOR 0 /* for new (non-breaking) interface capabilities */ -#define DiB_VERSION_RELEASE 1 /* for tweaks, bug-fixes, or development */ -#define DiB_VERSION_NUMBER (DiB_VERSION_MAJOR *100*100 + DiB_VERSION_MINOR *100 + DiB_VERSION_RELEASE) -unsigned DiB_versionNumber (void); - - -/*-************************************* -* Public type -***************************************/ -typedef struct { - unsigned selectivityLevel; /* 0 means default; larger => bigger selection => larger dictionary */ - unsigned compressionLevel; /* 0 means default; target a specific zstd compression level */ -} DiB_params_t; - - -/*-************************************* -* Public functions -***************************************/ -/*! DiB_trainFromBuffer - Train a dictionary from a memory buffer @samplesBuffer - where @nbSamples samples have been stored concatenated. - Each sample size is provided into an orderly table @sampleSizes. - Resulting dictionary will be saved into @dictBuffer. - @parameters is optional and can be provided with 0 values to mean "default". - @result : size of dictionary stored into @dictBuffer (<= @dictBufferSize) - or an error code, which can be tested by DiB_isError(). - note : DiB_trainFromBuffer() will send notifications into stderr if instructed to, using DiB_setNotificationLevel() -*/ -size_t DiB_trainFromBuffer(void* dictBuffer, size_t dictBufferSize, - const void* samplesBuffer, const size_t* sampleSizes, unsigned nbSamples, - DiB_params_t parameters); - - -/*! DiB_trainFromFiles - Train a dictionary from a set of files provided by @fileNamesTable - Resulting dictionary is written into file @dictFileName. - @parameters is optional and can be provided with 0 values. - @result : 0 == ok. Any other : error. -*/ -int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, - const char** fileNamesTable, unsigned nbFiles, - DiB_params_t parameters); - - -/*-************************************* -* Helper functions -***************************************/ -unsigned DiB_isError(size_t errorCode); -const char* DiB_getErrorName(size_t errorCode); - -/*! DiB_setNotificationLevel - Set amount of notification to be displayed on the console. - default initial value : 0 = no console notification. - Note : not thread-safe (use a global constant) -*/ -void DiB_setNotificationLevel(unsigned l); - - -#endif diff --git a/dictBuilder/dictionary b/dictBuilder/dictionary new file mode 100644 index 0000000000000000000000000000000000000000..d6bf575c61f3b366de2c0aadadb0b484deaf377d GIT binary patch literal 112640 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≀05TFZAy^Em{o^&%L40t&faFN%Y%9n)h#@RU1Con@K~$Q7K{S_vfuR8u`5_sp z3W-I@8JT6N3gC2|S*(y)T9TieSdy6x%KHkCiCoYKUm|#@BoFK@u#-|NN+2;0o;U?% z{UXpPN-20CNw-8_R~KZYCaABbpr8N?UrM zDl@Z01FTF(0UBxG9sy_p0s{l%43KhU3|6XOt5A?wlAHmZTL4YZ!{&7$V}`}hISE^| znF)|dSS$yxPQi3$Cbku0AS05BQWLYmAq3)qFm&jNfq@|i+LK?~hjZ&6? zBUAxA5LlF-lLKDL1diC8M9_>;QDR;(sKcF~r=XDnT4Ym{Us?=GO{xlzk^VHax-+$? z2-G_;1dU3AR|J7d9`(G`a$QKsf=Z*})a0Vn5)cb225l;WoDIXE;UZ8D0L_FznglxF z5sV~o?_N_=6V$D<2jaO>KyCm9Ex0uWTIB?)>%rlhoSR|` zTE>MD!r;C^F*tma^FdArPY>84)dnB|q@E(oS0Fkw4b-s5vRV!#3BoCfC7?7M4H}(B z>(oJlP(zaovb>FfadBQgD8-hf7UhBS26V2YBwryHl#W5OLz$pC<6Kb4D1Zl=A?^k> zn~S+XLvf&-4q88lC_NQ2^GZ_lQovJ3px$y~N=j-9blN1yH4I!JfE=o!?gWZ`Sl1Y2 zp=~K>g=At*d156gLzE!Xz$*$E7#OyII8Yp~p$=|{fR|-}+aAb67^R@;gxt)M5>RU! zGIRlV8^i#}$YN@8HaM;@@&dSm$Sg)0)8I-0ttiX{5xEMWDIyRHvg%MF8q5a`3xSdg z%-7(Q0*Wska4Q2kbx@QFn^ORfn%aUFrh!&@f)bYwsE3iB56z_c3dNb}dElAHJV^gM zHL)lMG>%f1S_B&62M?EnW3(t6+VfB-$j=1z6B9vh2e+__bre!dlA#5rXPQEuLQ!Hl zBws2ZH)WzhBd?%F4LGF0vt3|!E0knp7Q;+WEQa=8K;t2f2)`ufq$cLU{gPOc3iT~G zdLZHq3=9jw`86aT+${nJJg9G&3L4}AueD56NCVApfU_)g7_KBAyvQy!Pa!`~2Rdg0 z84FGXuXqD3Hh``&G_VG>v%#)SPAmp3{mX!_UIMoz!HFDfEyxD2TcEaNmVg?B#h@W? z&=3#2c~p`QZjfmpkKBR^M-6pQ04C<8fC|5O4Rz2c8JGuKS_(;IXrzWZymo`?bA{D* zplK}}O(>8d5S=+7|A7(|v_A!EPlCo@7#Q3WQy}Yq;cXIdjam#EK>{@&;GM105j27hTKcAtS^)}3 z$n-%d4k!p2M3X@iD2X|lRjDZoLC(R@vL?R(+!O&X*8?r#12u#d;DUPKG24uE z1<=9=aNK}eCy5H>iIpI`L3LDFYEGp>N+xJ|UJ_`*DR>16qTP((tC=~Pe+3hK{-A~PCdqDE4YW-K&fp{sP0!0T)vT0rY=K`D<}2~rznq$X#B z{E@0;1zK{IRGJRXYG5H9h3HuDOg5TQaK;9?0%C@Of)c26mz!CPSR|mQ5CASTAfx!8 znbRUra!AWeF9kIt^Yb7p#X*LkVI^=<0uRq20v>y{3|<2SS}W$62dbXH>p)AAL96T2 z5;Jp3i&Ej8Ls0mDM`bdLA**iiSYMJ49@?_f*UyD6z{$}At?$gsOa?Xj^vg4|GxeQH z(?g09le1HcKud=-x#Bg{LFooO-j>aJ44qAT&DGoq2C~WvDUPHa4s1h_V0I6j``aqRiZej_j zgos5lBVI!t*4z;$6RWD7$%sJupudFvX& zMu1@fqM(pltOxDsYozHYfHdeRfOLcM7-(@mcvYi1blo^OGZm$RS4x9gKt)BR1)!z{ zxXT8Pe+I^aOJK~vU=Owg(!R*a2ldWD%{8zQkZlc+X&eR6R4b@t1NA1M-4Lizw;321 z48f)-D1he76l@jJa`F>PKnsGQV+x3wG&Hqb&HsqYL7(pC%%j0-@TK~0hL($wPO zcuX8h6`R`1zI%-sd=HZ%JC2$bTSauu|bVnaDOAev_vm0r?fZ&X)pr1+8DIv z7hNh1G-jJ$te0Pqnx_G70D>kMQ$TZ=`Newv@j))(K?qwi(-hKDK-*sotQ7K#^-@X; zj5N|xbQBD*C^1A;Vu(eFkyUnTY5`Lr6}RB*CSOajfQBG%Ry>v84hr9vBZPL;4VwmRV26SDfH zC^Zc<<6V-kP*e&YILibZ3C>xdHUTI-=Rmgzf$hl51I?fngVrs9)+!@y-T)2JfxBg( zp|#9nh4j?C)FNu0{5)IM8ny0~-ozDW-sWQK@+#3S@^SD2rsKCa0op zbpo}93v?8~eSoUW0u2z>DgZ0g1kI4-rNTyfKrVn`c5K-g zj^4UipeDUenPxZ7z3>hdG{GJ0SY;Nra)S{n60pM~2GT{W?y#{L$B|{c`Ao5^RF1Rp*bq8ST7#J9W zLGFWLc-WyYR|l^EP_R-^2d(DKEm2TaC`e8N4fZI-fznH9aZPavauX0D2+0>@I-!^YZc~F=en^@XG}LoJnsf8hL1VRG10e)x?iW-r=H#b? z;uADk0?JfH2%m#gz-NbZq3de%i}gzLax(L>L6fCmjYuM(k!1$PMIZ~nvkKt0U1_Es zm;*{3swoP&`6-!cnUH}Xb%doge|-Oa;guhtw2J9R*!y z1r1161GjZ_9YLe-;3X(}3i#GvMi-@)A+>~+6+F{Gdqc88%~(ay1Y((jMy6h>9%vFB zRB?e9>860Hfg2jrIM zw7gi*BEOVWLkMLA8X77|&almeOc>dMrnMpYMWFzxi3KtpgfaV5AW;xjR>(;#1+9Dq zRqdd$RZv8Mx|oQD5l9&fV>lHi0iwaxEo`MWwC@b6B|wQO4Ya)i6hxpUUzw0yeV|5F zCUje8acL6L`c2SItbB#yRM2z)XmcQFArQ(EZykl)e9$xjXo+X4LQ#G`Bws^kNI(Gx zt&6xA!a*AjK)%y0(?=|lg-+~c7K184=$dy>zXmi@0daZ?0|TQI$XnpKo79R#$c!X> zq(lcc_zNB*0<9AUSyG-~1m5ur^9*PZ0-TURl8~+i$cog&Cku0e662MsN7SRfV~ae*=xsGkLjW6T50yVW$Q$Pc5 z;9RN)+O4FKi&UUN_o0FEDkyy=CV|_Qpp*x;5w>g+;q@CT-CC zeQ8b!cnEQ}x+bUz%fNUR+=$Of1-1P^D^e4aiVM;zP_qjtR5H^PU@AdL0wjcrA+n$q zz2Fs%@t{&R8kXMGLAw={oInFZ;2oaO76qs<0IlFu1uYyXDuFDE=K{5pz{5kJQ4`eA zS5Q#ET}0;=gLdJ@Yp8>|WuQrG-PGKC&=ME;_yDM*2I+}|(m7~0FTDs<-h#&k5Z-}| zEu_KK8X!a=stq}`4O9Hw=3)~GU)=0zR2Gq_q zW`L$aCSx-&wsWU}3MBAYLz<3)Qn?apGD$0dE}FoIGj-5HOmH^`I@qa@SeBTX15T8n zNCqWIMo@(ciYc&ekVgtY%h*ASJCOQ*pkZ22e*l!l5MA3cO@*|x0F}WC#rdU0$>2rVUd}IG z3ebuPbS?^bPe~=Lwg<-|xW-QeRfP(rkZnBRS_7;TX@^l-PGY(qS4wIQcs{H+8nmJa z(cy!2ABv%=3l#N;ga>H?a&a+~W`eqZpq5!aXz3&@zkzGx;>u#s`W_|KVuctb)#4Z> za5oL2R!1QXvfS?8y$)*df{_ixI?$XGcZE8EvA9CDyYYuiC4K-Pff=RwXM0Q&*9Jwy-G8PQGF zhpzfe0a=37Bu&gIhD>~dLm5&hppDgnMrjiZ3eehR@PY|EGZzc)4ugDEnyCjJ1GR$e zOoKMcK}}828vGJaeE|w{xFf*boMNy6@Rk*1S|J$Ho`;Kq5(X%sKwI~Uz+2qX!OQtm zD+-EIi$Ohm=s;x%XwV8ea-@)y3R)votN`lrfLdoIIh6_}8Hsrcp?R4V3h70u1$y8) z-~7@NP=N$0ep5hGRiF)v;JpnXgYxt8OG_Y!N`N9o2eLX}hfARpX@4^)l0of*RM1K` z%+>)Y{=p-BN(!pFTEz+qpr$W42ZGuN@j0n^pcOtv#U-FqRX|3duZY2V!V$t$kZ}wQ z400f6AmgH9&>&zMq}2}E9;2<0QdC(~ng_BLQYM3yqb)g%2KCG!F)+9z541j`0JJs} zyyg;=2tg690A2~5mYGwMT9gWIZ0Ug07-+;ZBehZ?BQXWEhz+a?v}ZCCx@b;W0h|X@ zD#2~~O7#@TA_A~F@M;a%_88FOH^|;cP%)BU0vbEW18>X)g)5}g0WZB!2NwqF&}kq& zbp>s34h4rfHlkX+RNYEJy)+N11GMr{y$B=(7pRTSEsjnD4IeWwYGkGqM}zwN;4NE4 zXo&`90jR;C2QG3_p&Ae+F-Q$~A#QRBXjKBJ?1W4Pqjfkl(-e|GX>O9 z`EU_XFhnasHpwV~8h0RjKrL7BaWbfS3lfV#OE7PNnwrS9HN9G@3=9nMQ0Kv^(oE3Q zT}gfsC_krVrfYy2%B2OU;RaG&lp3$06q5(t*$J7~1)oR)YJosTK%sKchE|}>o?Ph1 z3V=)jVNltEI9{MQwFEK(P^dY?!9SH_n zBE-O$SqwV$A~7#H6?RyPjzUs?eh!wVa85pG6QvUPEGbpc@Hlwf4N?q)90tOmnI^r& z0tN;KK@b;&p|zhO7X!mbP_hB7y9F;n-jE2cP?9r1Wj3fP1Fw+PcTCfQ^g@lU%yeJ%;sX$gCEkXh3c+d)Q@a8hu*7E|`umEC* zbEQIBX%VQk2{xq^d~P0ihkQv!aR%r>3eb!iw03a^A8H3N6*Oc3@)c+z53~yqqzpXE z1DQY02d{cV)dyhLl?1<`Jm93t9<+l1ie}KwDZF7>ba?4xF1ohJynD zR3w5n+oNVVka~=+BG~<)t|)9XAt*pW8`VJTV)CIY{K6B9@^ln}QbEHl3L2p0DA34; zOt83skGOzJq+}LnYwB@9(lJH@y9ks+KwTU7QW8XE51O!ttos2ic4BZ$Nl^f8uLDiS zLmB~~u!odrV2Rw!V({W!h$PrmAjg9O3(|(t<4P?7cNRgNFUV$3kOI(}JaDXo0tAL3 zr_JT(f!0(*2MHl9NQeQTlW9s6Qu0&5gGG>90Hzg0gQn$D%Mx=yqaPZO5rNb^EZGjE zwm2EG&%^-35g=Jm)eG)r6c;6f8mS;LEErV7!}cVB=Nm!8raB6sEg(vUF?mKYdB!n$ zCNa=uHK0-+Aq+YnsHg-QYr=*bxDe*vaOk`|}(os-XEmlwm?bl5NZLvwj zvT*?BA;fkAP{2VK{DapcQocEtu5gO2$mtAR|jN^+sHbgAaZL zFNp@l9cVrfv;JkcgacKdldjJ}q1s?zkJ|VQU06dSJ2ohBQ?LW>h z0WAuI_XqUQhEp&`lfkFfXmUaFBWOL!tz!7%G(?pNFHyjQNeFS!`JILe(Lt_ZMvx`U zpa6g@R0Ef<2%|s^JTy~4Lf}HIG#Auqg|w1DEYK23)I^BkY>ez3uc4Hj2nwdcQqb8b zprWiK6%;Cvu!1ZZ)qxhRkWO-9da)9yepOI#1Z`;sS53*KB|4x5bfBjmPjnhhMrJ@kS|sMZ@tPd0`I*74VZ$Kfq+-~f%=!3C7|Qz6w*M4 zzJeCyYNmt7Ng-n(prOM8y`t2_6i8DKlt&>fP$q_y9iT7AqmWz-+Ww;eD)AvR6QHsjX_pUl<2k6**N6r+KS1kZplcdI^Jd_&LC_xj;#eIn z4Rv2oWs{e$3m$F)@%2Myt63`KRpl%m< zm=-ki06EJ9tC}+V_xU54d6qx1olys;UYK3OV4tKsgFZs!E{o?V`lwl2ph}R#gwsxHx2; zd}@gTXlt{AhKYefQe{ahcq%$0wIVSkH90dk5xO8!)lWeIY3Vh1#t=Na0!o&U1d0GqjHCJ!k`5JY6+nYz@RRgFXA~BJ z7f~SM0F*M|qaaw9l7LizFx*V=IADHWP9OkGs0?>Jw8cNU;5h}rrmSV^Wn_#OU zt0ok{MI+1w5MD}Rx)NybN*x0OqdR!{73h#>(8@9J7z=!#131@%hi*XI~03WXhIz6@|IRn(C0!1b=E`Y5D zf(^kJAgvFCDJ+Nu?_vclRsq$eXag>gQ>AfizXTZpZxbnjic?TM4lZy&!?ob>g{lD^ zV+}g6yA--{3}h8(H5B+@S0(6>oKh@!`X3?&j(ijm@P11rh~VSR z6O)R;bWv&!n1*Ts?b1w4E!Hd2R!So2b$j3Q2?Kg4lyGH zbiQh03iuEZ(Dqz#=Ky>TNn#Ob4yyoEg@S5LC0!-ZiXc$A3@&QGgRY<GJaERM3PP(kTtdI~$-zL5gUw z7WlEv5Yr&-IM5lCpaY9Q+nk}*Qbu}tY7(d)otBvnsRcBOQ<07(2g@sgb~cx!gIu0m z3TXkrd;~heA+-#(>IKO`R2L`bg6FG1gO-_j={b;D-dn&7q&XtWEQoIrX&7_@!` zdLS0K=K@jyI@|zM&FIC$rp}-B=`vOl+?1+ocsbvlRYszRiPj!5j0&1ITZ{({0eph#C3XHpq0pA0Z?!t zH37j3Y(TRN>I!JHUnmMeN9q-&7UUo`2~p(L6;vY>Kr51SAqQ7P8zGJ8qN=P`Ev^Nr z1Z^CFu6|ZmEwWNjEdq&_K!(Q@GV{2gT^sNgKG5-AjG$%&j0Z9kgfkRu6{>6DK1!HB@l!ynk&E+-;N>`|dIAsU!Omn(LtDTGaw`a@C6`nbgH}C)m%-(MR?g_< zrsjh5CYMxbfG$o^DpJh^oxcb=QWiGbm;+wr20B0qG>jmufpoeHbeFv*7lVSGf&pkQ z2(pVARBsk5fX)pDU0whh0fkhzkdT0ggNNtAApmj!xI6;o^dfLJ2i^4n-BqKInwMXi zo&jocK$dHR&KCnsT|$~zU=vCbvq5nOSt6g7mYJNHnwMOuqmYqUlmbdRNIRUs86gMM zC`$+5CIWH{xF~{*lz@!`C2Y{pAgrGWUe*99R=^|lAO}NM2`FeV+Oab*+8Hr0Fj#`Z z7>0B6Q$T~z>Z->1p!^KFkO0(gR8uf8H#b*MQ>X(M-KDvS#o3^g8)wVF7?;h!z+eY5 z0JH%Lx*i&`3j^#b&^Z*aG9O%ZYk<`0fD(2wxWx)SDIo4J17qA_1_lOUkV)`^k0Ip) z17qApFlJ!v14)Ad19l>EW*&Ism0ocv=b;zrJ$iukYylA4X6f9E(P$uZqQ~h z$U(mF{j&;4J8+R&q#zqJ(;z$EQ;VZZkXGt|q(B(yItS1WkC?oeJW%kJWR~QlqIN1_ zs=-qLDH^$%dEjxE+{EluaQOz=PztsNREmN2%A|r0e=UOSsDb80&_Y`9Bn0Gco}^Up zmK|tc88j9H<|~wgH*go0g7c^z7szR<#UO{lM>9Z2c57thX=>_#j*Ur&j=vPAmSCw) zN)ka!&)_SsOA^zedj~=J>!dt;hN%GFKn`l) zW`d5k2TcqYaWOD5FfcTNbf9BU%?>`}t29%uIJE@QZPtLa;y@!v>e$bt;8I{%X2QU* zEP;W6Aq8Y+5vZexbbb$L$O^etV+d*1K<8VFKs!nBs5a73PzR0CsKa$JFf40kU|4pF zfq_92WFH8F-40v63UWQD=*lZ8)+jR6Q7AG3#mH(g28Px7uv;ELLuR(1O-|qpjHT@b z*+Kx81+BjV&Doac7o})`3KY<&Bx7+&kwz+73j*X65Y9~nZF@v6pA)lFA%fsun~s7; zfg!kYr=bbjjs<1nSWyHr5f_H8E!N=z4IF`+6FLf+DNqKaxdi2aMs1-?SQ8QX5RJbZ#-|Xse`B$TD{5_$4UDi%K9P^Tm1!3ZCGCy*O0?bW8!{@*9Pc z3Q&4aNogxIP zRf0>CK)o06Lcdhda8{ZE=r*PtNC6K$Hy%{ofOq327K64DLe7NO0PTW;o&yicneiIx ze)*7NO+gkT)<~*rYC;-tpo0*LHITMz!rQy?8lc%GaLHK=y3IuwyvPPJJPVo+h3MB% z*HhPw)&*Un1HJkSQ3`=74$znY=)ii=bUkWk0d7%>j)FR<>&68?wf(RHNmqmg`-cWO zyF#WQK!dM|$ahYGW+F;K?Oaflf>z#_lomsd60%LpD~5080G)S&a5-!%j1Fi80O(wP z(2PPEhyl5DAVo(3c50`sLU9S`f)~)LU{D#BT3iAdO+;RM0U8`t$V)9xEiO@jv|k`I z02rNL(6~CNr>LQB24ZFwl!0hS84g(}tl$|?W(FSqgI-q#N=2RlWhPk7Lb?Y*U59~z zL6j4e)iXfr`Z7{0!1WR6#v#U75YraqOb|my0aB!w7u&)ZNMmgv6EHDMVPY=mv}m|K z2$x9RNjZsm+29ljB6K0sHpt-!ISvHet^ws>kSb8gl!ScU6~t+vp$X7>Jy63rwIVgS z6kOkPF)%_F@Imjuf!2B8SvK%?qM}sL0;Wm@*r_d$<|F7l7Vt_Na1K-ece|h~C_wFM zCGa9S&@uQ$si_LZ`DrEPiAAZ9gEv6-LmG`>U7%q)kjp`9(!eL873(P=h7pwDcar$| z$K;hK78NDtl~h_Is{nPSQp-~Fz^3`S2042;`h_?;dHQ&UM1pd>n`elhYjCiFn}3jk zqe6gVP>82D3wbwOh*AVKhH`z86{ z6$qJmN#L0sja0pK$eIAFjC896P>~I~b07h-JR-le1WB0!SP5)#VS)~X4=y>uR)Sp& zRs+gmIjISnh@(u3^|(M=dqDXLQck3nXsD~^fG$%@QGgWhn(E+D6HrA4Nn#415i{^2 zBIwCR1)!LPoaO^6woCFAK-n)5G<^czzyKYZ0QGdhy$W!DEfaj*6~vED&|57aJrVH1 zB;Y1#C3r$I2{fY#DtS{tr?3}*&QJu^7SIw2d?Iot^c~vaN8Zs7InW5QVhJ=dp9$XmoeCP{ zD@ldUNP)5*XapLvmK_wJkQ44RL5C)R;uUnKA9!&;INgG--~(+O2d(ug0gp157AxeY zCgy<>6)0gquc!c>`;-XUq{ZN$3eHJLeHe@}HjF9*vf81t0DRO5_5ozj32U(Q54sl> zX^}Ea7({2LF)*-QbO0^*P0UNtPzO~lkT!n}cytuPR)2trXpIE4_=N3tgq*?&Rtvcl$j#FSdMOaHQ;if9 zNGhyA3u-_$RBB3cNd=;w!&s9N4>~orARio0pe50uZ_6=PtiwPRpla0F!>5C$Ki0xIb>6>JqiYmGp@(#y>TZ8<3bT_2K`Sz)V`k**8Q zO3+CQUC`VDqlS7WD5x^QU2{EhuIo?J{uL2+{*~I+igF%za@{BOr(1f=>B>bShJe8Qgv|Ft}^O zdi^kUpdB)xH2`3xiOJddr6q`iZ$XMc<7u$|emZEF0km8dq$|Hj14Mx|+kzON6YSyL z_|!7A5h##RAPhPPqZGF34si`F?ASGMX3Q_BEXqvJ09`o^G97$5kP`HMW_TwjUPB3X z$y|BKlhAXPz)nFrD9*D4v{(Xkvo+YZq*R4G@CbEcQ6(fHA_AwlG(8=3 z<*-6#i5?ed*&Fx{CQwDTBsxk*EKa!ONW#@{3{X z0hATMD_p^+FoLG8H8RqRQwwwypcGgkbon|soZ$9LpP#xqJ4tSwg5omfOsS0N;%J_*zU1C<9Q;BD*-2^z3e z06rBAazrXP3t}m|kUgXdKH?s9oeyHj09hVXZ^Cwn6oHk1Z)5;1rhwmx3DV7_0Ge?E ztqcII6$9lg*ylLPo>~N3j1SE; z3Xl$PW_}(xx<^b#yP;h{nMxd3E`1eABHZXxYN}1q&kcpu4^Fj5eLZX5m zXmyT4acLT;B!%7w2e~y9bm}D7nvi_ZS()HH%q8G%6lmQ~X#sS+QCBxFUl$?*8g)>I zF8Bq7vaW6__>c^+Rl2&M`VF+mih&7ya1W?+p{rXAK2INdQ4Mt912h>2Icx!P02$~q zLFfgqAWg-f?K+T&07z8{?qq_xL6FiHw3`8RSXpXWChE023=B&^K?cL1OgLy2~sxO#xDAfM$xow|~Kw z>VR?sxb+C@wQ4BoDnY7k$hbaOA2|Idr6%X+g6C*K-CeLI9UaI#6XZZ*$bIwh;dI7i z$dC-EMGd{(4sm%IEL=ca7eE&*rhuv_4bTJ&Xq*hT@&i2jqz*dFnSp`91f~Z@gLiI# z(uRgoVw#eU0%+zNvi=vexLPSO3Do9J*Vole2d(P{-&zO?J=khm@J3nimJ?8J0;vHH zr-KgT25q4Q`x)G11T`~Lh}LX*vXTQ{Q&X$~sg^I18~H^y(;4Mpz!m;$oVEVBeu?19cC1&_+XOFmE>m1Gvc*C>MSAVnAe zI`t90WVaa7*~DCd3om93+`xx7@&fQ zp%Z!j5#%Ef2CX*K2Ct`vBtp=c&6UwcpreqXqmT+z)SLnZ-7+OSx2dVaHr7FRgo2AzNTP;T zZ^fEc;Kc#3^bHCNkinppo}hF0k;esw))0mQWY;|SXjnZ&@&czJ$aI4ymjVL=!%~o! z!8lq&Jqa{20O{O;SdjG?ka1ve!vVBsAJkt+gdW>6>d3I)j0%TDIIHQ5L z-y-ibR{$Lt0^Z|P0@`Q}RtnnY16B=QABDKvOBr_VI4B>38}#6^K~DkP2Ey$su%VEh z>EKQW=#UgH1<(=x@ZlTqeO~#{`@ulP0z^+vW_Bv5xCa#t-~ki{M$qZM8TsY$@Eiw@ z5l{qyckSh+r-DX+Y(aBwpoL+e1*XuuTS5Kf@;p%a335MNKXejUA+y*DbR$bfei3BI z6iGp1aRz9852zcVQ4DEXL8@r*09k5Y38)`GAH0AB6vN>92;?GY&muRmKtmI>&<}K= zLN3Z;KT!Fe0df+!om!llq5(DlslftDTA(Hl=xDxz{OAlwy#Nvg;ml&t$vz6U;HfoG z+Zo&jhu<^?E+9ebKp3>_6s#OkWq^c17<7<{EogcMMFU8N(6K{cok|Lc;B!Ynr#6FY z9}uHF6?EubJZKmiJWB(L@5GW+P<_s*0A5;Lte2Ql25NkPr|U@-)UGJ3%V>3+`Z0EQ_xQ>Nk$xduAh-!1UWAZ zG^C{B;qU9JuLlwX)kdI<3_i{glw?3&g0}=UN{hjZ4i&(49O$MVP$xD6Tmxx>I?5<% z2^@U6`H(s2)I8AX9pLqKpfn6p2uc*tYDxp-4DhT6=;}aFyH^3E5o`kF1kW7U4NWQF zB&w;$<(*oI<>q@(g$-JqsbFtquf)Z`=$WPf8q>}%QUG7B8sr)Vawqr@A4uh?1Sz4w zrWPx~YiG~^RUW9>2zCR=xuCWx>=YM;#Ny)oxMVwBCi3KHy0-aO{AJH*m|o zq!@g)E@ol_U1_Ue3)#d63IuQ=60M$;m;yNm7s>~1@>54m?VtpiR|@K-fL5S`8vCGY zZ&FgB+vqa$ixfhGe89C-VhVTxV`?ra=o7&M(mCMq3s~@j{0Cb#3JR`L@L5M-uj>YZ z0t`NWr>UoaG4%x7O|1Y~TMCXo(9AR3_X-LM1x5MbMJCV`iddQoYJ!k=${HvDU>JEE z7POsQ!BzotS2n180pAs=rw5wX0c|8tEwZu#jdv#H7pFqjjw>j*Le4WThF`p;3oh9* zOTfcFsi4Vg@TzVN&@vLxViNFb5|~Rs*G7Yq3h3D2)MRk>(^gOiogD&B5#TTdsfDbW zE5&w*FZlZEvcwz=NtiwbTLuOOT@Vi$!xuv7mF9t#yg?4N1s5ZlTnwPx2J4!E+*hmv zz9bO3S{C_ED#*ASXfaYT7Xu@x0?AAP^JuTgVX?lhE_CT^ zW(jBwY&s;PfsRtoEdXEK3p=?-0X%;X>Xkuz9^iAnz_kb{m4X|wpgID?0WW+7UH_3- zte_6MuM~W+fw~?SLjdUdS=eM%UP@|_0%F7$)MYHn2OpCRG6azniy#MpDU@e`QUl0a z;DCa68&jb-Bo%<1U6cnpVI6e+UvX+-Dd@BTSTR`)y5c)Ir!)oBod&I3h0250tZ730 zodj7z2HKbh(h1EJ;ORHeb>*-jT~I-iSqyDmf({|g0Zqy2>VjGTI-sS@kP){0Jb0D{ z-EWI%Y(dxlfCNEf43KI%wFumJ0C^9BHPj({I*@i+g2o9zEmUx#fuFx#2AP=$ZQlWp zF_aa9x&jOg3`3x{0FTH*j}HMY#0U3`i$NFAfoC_NMHNz^s1E6e!pCEDKucURQ@}Un zflD~h#wtiMgoiJ0r`{%|Du9nzPfINVotXp~)J)FLD+8UU zo1d4M1D(8wT?GprI0YGm*{g(AX`sDe(7A;CA_Y*Q0~dsec`16JrU7Jd7?jAti=AM% z5r6{+d~_G63d&DY0L@gCrGn~G@Bjt)Brk9=2=)TFf-43c!IV>)n+I)BLi+R|+mfK` z-HR18it@{gH9=V-6`ZlbMnH9gRwp`wE+JxIVAu-{Ixq!YQ3@KdDXGu{?b0pE1dp3Q z7wm!+DL_^g!4@}zE=y5IYjlFt!OYUO1uY;%y^T?|SQE7L8r0~_NJT&H7gU5om(GLk znaRy8(E!a$+d>TlP28jw*@AMZ4i^Jshk=4dN@g)=ST+UHyf!p2P=KrQyn5LfEsAvb|)yGfCkK^1lz;KzzA7J0^TxI&R=)Moo6l75pxx+@odmGO;|kDQ zMM^Sr!DnWILKwVt2V7Wy=3ha}e{%9ctJ=YafK~y)H7kLR*h4<19>jrj_$x|(cENF&|q#4BOfje&Cm67Few*2TMClEaw;?E(7d9=yyOgA#z49* z5QnRyZ5+bZAchV;gXYvg6O9Uq&_Wf`HUN#6!Una}L3v&sG>-*J;z?DR1xAqJGiY@T zo4*82a)MNW%EHp(RM@(v$N6R&Eq%trt=!0a@F}P_8+U^ay z6%%>?A85tsFlYrRC@4hcmx5b(uI;RkAt=8 zD1h3i;2~ac8x_m~FEK*SXP^u0AvJPR5qKIM`Q%xc3qdrpy^!ms^Fb$1fKTQth7Yxa zRDv*OqC(Qoz`)Q2QUu1RW7CLLW}uo2H0}c(hE6Sp4@5ICFgyfl%`eDJ1l0x6(V!#R zL8lSqB<3ciBq~%`fmUaOPjv#d<1{Mtz?3HFh1?|4703Yy!O#{4m z0AJ?^vkq*R25em)7JI-4C_qjaMGyUw3O#Tu71WQ0tQ>&5PXRpT1=0p8UcstRhn+z6 z9LAh6=k!~!51xQXtpw{V2Tc+Fz9h9s19}0DI(YsQdWAW7LKk#U18DmcXsMaD zLMn9R1hVP|vSSnJ$}FU=4U%R(gJOhkE(WIe(N>^sg0T*<8TrK}(N>`2;9~W`Bg?P^ z0lF@**h*hN8kE-2m4mlymVz=1O2Y}1(4Y-5@brfsxOI=dMZb1Mhe(OD!saUUvyhRT*;O<&X9w?818m#$w3ZRLQ;*$I#9R<~5J#c16(um4bRVXHSFf*zSbx@lmC%-rq z)RTi`fz13o@Cqgd1_muu#Sk7isU)VPU^X;-APP`PjMiU9I%qHhe33e61yd>LvTAVJ z2DPJ0QWZec0I&;9KrL-h$qYFgJ`=R&9(2w~B4iv=Paz~T${Mm_1{5K_pp{h6>${*i%~8P? zvQZJr4+0Nvfc6qpp2FdUE?3Ep`HwCX+w&8$epavYuDp7)WNfg2r2jhgRtEPiFphR3>u)Y zgkjL~B#orf61X?OBUYeg`JgNZQw6gW6i~2k7`zPvUbqZO3Xm=|XsR3H1WZ$)n_0j^ z5LnF70IkY_*$JcJv94OIpbIW(LHEr->LVrCo_uhlKDQWhR~$?yM%vCTPS@npz&{j_ zlL{(eAzlHE2Izo?17Y*{3KfY(>BZ`rpwT>VS}MqgZJh;;oguD5gDtfOj|YHfHb7I+ zprH{^UktQR06Y(n3R>$1s&>F@Z4XmwaO6qaMaUEl)nR5<8d2Iw*5sKq=+R6;gkXM#49lz`7%1I_Y- zauTR%pbE{*Fn3_k8pRp;r8%Ij9PqFQ#V~k?uAnHtBtJPn2U0~8RDxFUCW6i-hm04% z&4S!qgk00ZQZ%yd(7nmX%0O8yuQ)BWNI@elvA6_$&bWe)qaWy;aUCuN4U|o!FzY}q zq@v99;-X~GBqwOd66A6#E(LXPddbgA1x*x!PRatEOr!u>%?Un76c!zz8AZ^9A9xoX zD20P(2}(id=z#hI;H^#h;6^TZubBd<&IA>zy6{Pzl6=s(d1^9fd=z8=XxuC(6?6sw zc;*ar@kUW%ZfZ$t5qQlM7Xt(PYX$}meFg>wSCB7CKyy`~E1)xT5{ux+(t!J6kjxD3 zh(Q+Pg2Enr8xQn)SIEpac!ef7a6z3nQ2m=(qM)k_UOS-+Q35stG-d-{?*;81fyRQ8 zbMpQCLtL%EgSiU1iIvcce@j492dNbWsmY*r8)S$W(&7a-bBn=CUo#;im|&}6yE{Rf zSo3oW5j+Rd?0~KnZrGub~2(+aJe5R2u(s7fZL@Lu_{0U!vgORYVo;D^F3iHU7ztd?It4lUIeS3!Gw3cxaGZc556e+f zplQuKg+y?|frKF>ejtl7kYZasFCS9kf>JMNRRJjPflUU58>BM@3IiSRE)-C^38VeoTErgIWKaZy8kx{_*q{TYVcXEbeLL{&+u(UgO}*^YO3=!5 zPy~SW=@o;nwuDrah|~`np$8>?rI8fuQY zNtx-T`K86s)3-pEUlo@?QZh(62t$tQQ?ONl4u~aNDJ1LVfbU)aU(F6`3Ko@ss;~?V zP|>9aYAk}z!3L)tkO?3R>a~Cp1!$Ewhz7MWk3 z+BsH7!57-KQHb`1T!rNe?WRO4LWVgsz{hNXMn51Yre>sr4K0ODMMEahAj|MDuh#%O z5mK^2=5n!JvBAIyI;9%ASQFICXJF6`$%n3rtps-y!GrwyX$qigazTq0K=ou%YGO$$ zc=A|5Nw-8vPeCCpF()&Hi-AEDvK|C=hYBc=un!r4WJ(g#!FJdxK(~^D1VI=%gQylO zs1_q9gyMq4WKi8!q@w^f091YIzz*E3u(V&7dcY*{Z`5X|WzuMqQJO zfmuNTIw=G?PA9qm++!#J74YE3FQmrI$xla|rLGB@^(g@DZ3CULg?#-xXtiga0;mmF z47$Y!Ns#KJrUI62I&R0CKPn>tV9Qy2pT^DHLj6+ZJQ?-tR;d-qIi;YLL$DBq z4rd}83^f+vCdh5ty3q4!LE)#YkeHX4Q(2V?iX2GW7Nb_`*-{R%mE59eTeKWDy%^JRhtYyaWX8m=e$m5zu%hcpW5)0+8X5{y4Pu z2e}ZGvmpbt(B)Tp8R_7)%HSp-xYqz`41k>h%Ad9h>Z+=s`}kCKRZ~!C$VrIsFa%9@ zMT6GKg1Uj=l0*a67z71c4y@${Dqf()1Y)EnS0OPkFCWyTSBTav0$oEA3p+6^5yUD5 z5h)-d4@4w`h@4mj(18$o@I%JHI|?!qLHqZ>B|4^*S@JEFZKz5?p@i>VkIw5W#)_V$jiakie?chb&Z8K-yFRZe)S-Gvwg*jLhPa{Gv)dE(V4m1qIM-32d^2 z*hv*U>WYgqu$eYEyW_>FC7{u>63_w(g&gpzx(v|C7Uc@ymBWzrV4&m+Is*)p=)pIw!X`h#fvlmIkq&9K zUW#3R;~2 zo}kIr_OnhrB?(gVw1Y)Bsv9eeJbjlQX{Vv$;kVWSpKf@;b(0UG_ zmM6wagS=$$GDlcS^h+&=<|@$8Lninbq7+axf~#Bbz=Z;6O(V4F0b98bvQ;l59im=O z!4b078(i%qrlf$Y9MIvbkQD+7po2*iQo$81Y(ZsSYDEdCLdpf58pAMBCW}FfMdK6m zDl_wvbrj-3od!^Dg6-U>M7nbsc5)(gJPAA_54z+AG;wLG0NK}{n4FOcIsrxl+V3y2 z0x!RhE{a8*R1I3z#}Hj$h{%bc^a;ZSpyQT7ZN}&VBkU@a!P_xGlV{*m0ABhHuD|m@ zGp%5Yp{FKsU&|2sGB+w-t zpxJA%uS$zkbre9u1>oi!q~}vyf-nNSpB^-$sgPQck(mTq-3}@mp_hFqBtmj*QlbL( z6O^$Zpq#1z**gQSRKU^4#Q-_MH#q}pGE(?L)`^3*Y-XlwsF#8dIs@0-=$ivT1r>M% zJzhgeLBkocwhh_=F3Hc&0Z)v8FVO<6+e|FUOv*`x?6CkFr-M080}5!+@p+(;-(1j@ z=Ab#G(xTK9J%xar)I@OEl$x9k3Z$akG*AT;pPgEX*6{f=6*P)c;hh|C z1VF6-rF_uzm!hqLdJ>iu0^n{1tOWw&Ms3=OaX7t0u5$?XSs_~b3hA6S)CXdSj!n081&%U6u<|sg8ERU z#h}4O96H(K85r1?FfcH<<>#b;@<(O~WYaE@UQ>tY0SzEAYN&&boq=3O4cbyfZDI%v9!GWcyQmjSRFFl4H^@HH1vx#K_h`inDGPZQ9$m?84^cQW}ps| zBr1TKuHZ%@tkIYUJ1!9v$wjGUph08^1<7cj^**UZ8u{RrlgZ^N8k#z#1)!l7NUerz z5>ykkdkZ?751zXN?OiLXgq;YH2#PM~FcNq-B79H@RIz~yHgM!7=2ey_R)UV2E6D)g zF$0ncN1<9)w`+ ze#n|I@NwRt0dde7iHZ29$w5M4g04%}W7ItRt?8h4ciAl0nTw$PFg3k>ApGpQ^#{;_h6f)Zh$^9UYfPxH^ZQ+K1kBEZwm7qI6OF)$_ zsQd+~SG0vTdWurZ5Dmj1@L*dpbn_l~j0xPCOUncGKoGWpw#$L;Qq0s#CFam6(7Ko+ z1=wL!&|?QdX232hP6ajSGr)5y#i^x5Ip71VKwWuIH?A~O56iAOP(Xn&sM>*a*OXL2 zi2<^R2zfv*MubtLkO6hOfW8VHM42W^Fm1-19mKuwKQ(3Mz-#Efi8K|W|FU@GXk zo|Meuf}F%kSn4k(^9=dYJn)PIsJwvgNP-S2fY&R5suR#!A5b|2NqC?ESI{a}@NRo> z{=gWqP|yIKRs+rh;Q40A0F`cNf+k|_0aUP*C+2~t_@VRB;B!Sl^&O}<1eLgnc?$VC zpzZrmo52ks$Te56wG4=HdgM^TV5jDlWftY<*;cE2xX1hXySS=bDS);&9Z-`1vY`tag^=z5TpGMc ziGdMzh!1F!f)3=25L<-|$g*iY2nFt7L;K6%-R0oa11Up68*MV+n;dLy6%4FE`^q5W zGSFFt6!^|tP|Ff>Z3So>5M*u#G~*1ZIzbb8kT`%Gikk^4n?S>PpfgtTGD|WOb3nJ` zC4#OU0e9me(>S1k7Erq>>FrZL|-HgfKH&x zfFwb;xfDR{G(B~7#58PXnnGG0xU2+Cd4gL4sAVIhwE!wJ5iJIo@sO4S zcDXdrB_rS#JgC6YNJG1%5H!&WPB&>-_R;0#r|6=c8Va)#jaDjv^x44;Z%9rDFT*T> zET;t3j-VI-?|uelE6A!X(3DwHDrANnlJh|2Ze|Lkr~(b~fEGyQ>6R2_mSrY_?z#po z)`cA2S_C<{5}ac|jTlhV6Lg7kacM62n$k4rQJUbhDnRyUmgp&fmh6E`bKNq1U0vwK z(+Z$#^M!J!RZRr`_CxJ*GL2R^UyK1vXBj3JPe@ z2uTWf^NE6Lu@z`6KuHsH(%k7X%od`NBH8n*E zDOkY+X`qH=YH~ItA~e93fmcZ}Fw}izU}$*5z`)c3cMn(^5j=UR<%!9lU1Xq%GjPER zQVB}`V52khz*Zv-j)A1XQmD3qgiv!hD10D>XBI1fOt<1vumxS-tfd7iL!sSuB_$=u z)E%Uu3@UYUQo)M`K#eIZ$8EvR;sGVz#Jm(xj}Gi?Xh#>k&{iEZ)s&xCj67Zk6#^Y@ zgH-w}C_qjz1kHz+fyReHLoJ|DV_OB}#xUyHt`IGnItuyV(@s*05sO(t8v!#C^Atk! zGAk57rzU{zbSr@jHG@uvD=2}CUj|f`WaQ`R2c#B(&f`i?ttbGk{PrwSC{6{f^hyOK zQrP^R0(d$Z)K`V}*ERC+E_eckZZv4yAGp}T*55BcJrD(Q!y0JyQ?Ulp zTnq!e;V~p5RRPk`hOElKbD9a{UJOQkD=N|h9|f!tub~9Kum?087Lx}qoIooe5jm^~+)q@{ zHRMt+hR^51=M6!%GN|y#ohStLQ}aO0@yufA zYQ#+NQTB|Wq8mJRor+c@6o4*kMrnhk=qMB*&8dUZ0BFcP4K&!Ku8U>F8F`pi2{hMI z3F<3>ZG#lm#U&}3d7#ih1Ov!a5C#wRfEKouBxmR$FCi$dEY<_-108H&s{pEYU@Z>V zaVL6^gT^#8L5xbI^MO#uD?rvHmsEg`X9qVNAoU-p#sYPeGT}ScK5Jgv+ zpOT8S0RW^lxugO%nFVdlgN@8jNi{SBG z1vMlx5<%BNfwmeznsuHopo6g?qZ#>mkhUOfP74&>AalTx02-bIWsOA8wKD|;sd)-1 zpxvJNpkWNq73rx(3dO0A79eP(3N-5j>ehm%06|wrW`Zw51|4Junq~(b9toOD1se?- z;>b-b(c|J`P*!jTkB@;ywiG~n<3Y=mG%7U}^79mma}$d|MI`uO=6)s2#+6;Ix zC{2SaF_0t%R#gD)uPQ3h0QXp712#yF0L*lXtzn@~VGkTMfCE~13fe3LKBu(=blx5V zgDr-GArmK%f($ey1S{+{a*LzWV)aT33Q~(SG<6ixG(pveU#Ks1>j>yRAW$s>>dC@3 ze}Pm$<~hNYEJ#YXxTG=%G#UwM(t?hLfOK}j#>8@QAr2e_RfV7$9~`(E>Y!>%9U%*{ z3%U;!WKDW$YB8wZ1+|c%yRkr9RT1hHGz@HPi*0NT4Gc7)C$0p0`g-~}26+zMwM>u+ z3eb`U@CJKA2g|@BJ2o0TotKlEXBCUcF)&#e4QiAXgZl(}u;b#P?LL?abhzbF+n zDP#zaGjwTawFg$k#icO9W}mQ4ZlZ^ff&z4O-WD=QufxT_aEpO~!5)i3+(MuM3R`sz zdn-LH{TfYBI~vrQ1ML9-PfLQUHPGg(l6(zNl^UHE3+eFbfX<)*?+_^k&$D4B4dgZ; z@}`2+yyX0p)D-aX(M73cpe}AnW-{n%Y6gaoY#jyg*{G138dOhbrWS)oz;wVhEtoU{ zlX>74EO;p|`r#6pX$s&|V8N@8QA=b{NPs<(4H`@;LrHt!ZXDQps740Hl+-lvktFfp zWs0Bz1AJG64!DmGyE+SYl?3#pxa8avmS0eVmzc-K}*W^O8UZUE#2j9LV|;Tt3a4ibm~h;Rf|Pw=J; z)Ey8th*SVl18WyWgE&U9@NFF6hy#g1n_#Iq#S9FLD5o+MrGm~9P6dq^MuQJ&Rsf%5 z4$=haSAiUdjzJBl)N)V@5gbI(d9jcacVZQ6pl7mx=j#!@LXZLADjH%L!iOLU5C)}T z$czW``VsP2TFOqyQ+y?qKafSj3^3OPy&kuX6=JA#d} z1sjr^SOB^z9c&pWFhNpKF;Gi45q6Z6k}7EM3$!jm17-qvEdbi6bzXi7=D$7(wxA{$NFgZeLBybEm4kCHNJbA-;S_5?eF-XFOF+Az zlR>LaG{AKN$Pq|w2hg>OAU&YtZW7Z$p@wQD-0z?{eef9~DXAb;V9TIxP%i*w6L1Fv zxw#4MoI^z6Cw_qZq@bbBz`&plW+D+tJ0{g*@<44}Q0fC0l?;rB6-xD>S2ttr(1V6r zz;^{`a)I+EC+Ak&}`P{>9pL=r)k2eEUD)8Ti-L6^0I ztOX@i@PYYAyBk1>I~P`JBXv?C!%>Esda&tjX#UNG*8-5@AJn0Rs5L@S%fPULfq~%= z$Th(k`Q_jdPlyh10SZoUpg04SZitZ#P_siHbijQ+WDoYySDv^Sv)RKkKbx`GQxaQq?0f{RiUi}Ul4N)T|(hd8$m)WHQAlnPme266)o!-q3K zqnT)QST_ys$NCbRF!kMQG3};yx7#NH}0STFg zg>6O#wSJI~hXeT&GEiKUS_UeX85sWaGcf!IozkJ}tgovJKEn)DgBOA7a`0Fg=1e!F z6alFMRS2+Y5l~`brkYa)4^j1prckm(`uk&iXg^;!vm5D^tc#Y!IN^H zF0kXDLD#31=H%$+q~@iUWPs)!QxrhmvAlFW1=s=-$cPBY4F-_KIEIiGQf40R zBaDq>L4$L;XvIG$Je3s!62W%?6z60ngD;~2<+7Yq(4-G2jPgpr`v}3V2dRf)h$_$# zXrPKGH4l6^8mQ32e>NFRJ5e;K)e1RHt|T)Tbarbh_%0FXVK&%@%0M+1ct)r=wLn1| zTCs!5KU5px%D@{6;MohZqONLs1Ww0KCG8~fLKy^KMPdL~JU0sljMt+e3#9Rf?;5zt*Rt5Mr zKF}y6X!|=TeJX&Q4LbV-)PMlF7LpG@x4MCP(BLKBplXCmp#aMYS5T4!VP()JRM4`d z^!yU&U0@(yDtwKlf^KeNQ3`0W0_f!2l+5H3JH{;O7=)7J~-TAv>GEQ@M~sT8lyBe4ru)6xyIY7VxcD;LU{K zs7OjxfLurqDnUR&3u-N)+&rzv1v{k-vgHzd8W3n^0p$cI$nCDsEijOmDUXb~-VGoBSVoj?{ILzKZu&~}=fR0Yr!1|;!-cU8kCa=@;JtA$+dfcKP3=n0n@ znc!m*b-)E=X+cINmV@BI?LN?v=%BU{D7-~ER^p54t13=Ch< zTns*yGaBWHc;tgn)D_h=t-zPsWu$^`kOdt!kKu9nS@gvSMWEu_3Ve7n$U^9W^jIv5 zHbm-cgOp-UFMvehR)B9s1RD4N8 zg=v8=qGx~%5u(RcUOr?ABv=;QlGP7pU;tsp{U9?y4Rpv3FUY#TBG9@%@KjJSWMv>y zr&t+wE-UE9j6CRCid4|86QHwBKtr>jvzOq<&w~nf&`Ke=laygY7@))qZN!4s|AEpv zwC#bIVuQ$omJNg2Dd54p;%I|dr13nsxu8*t)I1HS4lD~{iZc}yKrT^0zmX1f=6EJ} z%O1*>W*r6i`4ET#Eh0mCQ-2+L@;OngtOHhsgSAxv;L01)m zb`OBhi3QI)fp3XREh<(*9}xhJAQU6tc#S-g04my0i^7s3jRMH%BV>3Me5?<wLmhhl zWpQeWI`oiVa4`;Q)tA816KL8k6+FF$aF~XAI>_^&bI4FMf>r_{#zDc0S21)#ZU{{T z9i53dZ52%;=q5b$&;}1@f^Muvu@NMo02(g>H7p?Y0?0S$njs+(tq$t*#e%kpgUfVK zI?;pGAfSS_Bo%VP59kP8dvz-=2F8$lg|x)v%$!V6rxSE(9JuxbW$dE-939YA>Lo>) zNu{8EK4iTeXyFaWEugg(iRs0V@CI*825nX@F3ATC3WBHMK@A0HwXCFndSyDOUISmwo(kF$4c4BQnhY8d0_{ps zPyp}0ERF^RIB2?~Bpov942oM&13kY)0k)0>oGHPZqHLj>APdGIdx${gLQ!fN>L3$* zC6FH4U38#sFKDqDqHzO`0Fdd5whATbC1A@S=7Ty2;FyVr83$dUV#URfmI}Rm5;`vo z3gwKDdC_vdvDpgk5)>n16`Bm=Tg0ICk` z6sUgCI1=(JwZEX*v=hp*mINGwV(%>^G)0!m5HaTM@HV9<0A zUL*_}!GvA%R8pRr3R>KeUkvK3Lspm;g9l{5E0I7gdC&+1I7uU~_5pbiVg`7016d8I zVo3xgVQ4sGG<(3gKnGIqm^Wdj1fHi}Kz`C*NOvx`n)tr)Ff=#~yY@rwEbdG|2q(NO!n^qHgWiNC*7gR1l zmaM~;PC>@1K;!Sl8W1)jQ$s6zhz3wy59)UfkCY6WB!S&^3hMrX&s>9+7?4r|+XJB9g@4*8V4WNl`#B%w}GzAR}P&Y8Y2vj11 z_daT^w;f#is?A7zRHRL6p+lA_U?#mWkxb3?%6 z!#a@J(d7Ih(CK905i6*#pba7}@FXm#EI``&0ZNQ8j9B3hZhnI5GRST}$bpwIWgr@q zDvK2CY(b4+j4BJH0EEH&8NpEn;(=`kk3A!H89=-X>iUDckemTNZ5njC4Cs=`($r$e zLPh9&3arrxF8h-5Q!4d92Q`+0uIB*_$tQx=(4~MclLfU#4uTGx2SqmIVl!|80`E$M zmT;h22Gp=fMKrEJ5un4xz?1@tj#Thk1W=_38c!&*RZ;@?CeoHMFr;l`U|<06+=u!J zv|~*Pv}r!=CIdry3~VD4WYipF1X6(j+Fc0_6Hu}PHTOYBRUpmyFfe4)F)(C`FfcGg zfP#(COc4WQR1%~V1;fWi)fK?&LO`=<;MOd7{SbVi322Ny12o~6oSzG-XEW2lqo%O^ zWT5i9JR`9LK9rig2E6ybXy4-)CC`qo&qiyz&7g^DMWzX0l88p0yLrk%G%(9 z0BTlh33y5ne)=fvXcbT|2ed*8w6h?;Sg$y>08#kDLKKu4p$o4vi&HW|Q`+EQ)B|si zf^7T*O}ZzRWI$GbgW9|WX%(8_9S@LH4l@fzgBM*X*eax!CFX!8;WR)~4h1=>XnSYi z%1eqeL9(EUL#R_hy3njMz_EG^d>g$7jKs`5&?sbL zUJA%6P?AOULvl_kXyGpE)zBavpc)NqVsuezS!}d1WPlFl2gs67usTIhO^Mdj1t|lY ztZl1+xn2#l^u|^Jq!}F3AjL2Y62xzF5oCQgNTH4b$PTW-wgw7v(=sU0!W&iKjS5AT zppptC4y$`$iz%TKwxFA7q3dsag9G49mBF1_=Hs}Ic@Wo=_ZD!y(XYkS3IiMC^5x9B= z8w2S&gO5=Mbuz%G3W0avgO1s%N-fF<9XJoV#3Zq#6m%PEVjif;p9*ifgAK_nR!B-r z0qxEA=V4#~VTS3DG@%P#PXY=xMDB-nd2%WhAmLo&tCjj+%z=sfkkF5aR!&eMBaR9o7 z0^AN}^ac3}d}0u|mjN0%E(6t$nVL+y8FI%nXnYfXHxc-@XHXdmZA61DN`_>2P{ALquBQ%NV+NK& zjID#p5O`}Fw4(AQp5?HuRKP@B%?d$&PDH{4g9n&MXF3dc_LhE_qREI(QE& zD93@Pl0h4Wit+DQ1P3{MR4@_LtuIPZNX`e{GOeHlHbn_k-GX;rrb3Pb1dBq<=3-z3 z%}Ri7@Bp=V@ve?zU{t_;Gy=Rm1K;d4!pGl01vb(N6ySIQ6%#NFDYI-rn@Es4o-kSP zL>H(HlboSZ3Q7-vRP=(4v77`#E1MVoGo!1YO zhp%kX0Iza`3Bzc}2s@02Ov6t11Z!hpDoQOg1ou^pV3Qvp#Y##_xrup@1Gz!_l_0SJ z-r@{vSU@XA%zbZ=W+6DzASD23GkaQokpgHl3Mf&4if2f>95l&TmRbZJ_X3^ORt!12 z64FoyMhV5o!% zf*c1LZUvo43Yq-`+YOTjo&5)10tZ?Th1#SADFKx+kcG%fx%r^eofTAz;ayVDnf;)h zMWBt%piZ=oLW!m(=th!n3=E7CprwqEQ7wg(RM7o&5RNqpPcJnOWU&TF8>2P@1Jj_c z4nd3fAfvsYupxkzO7n_K3!v9KfQlXk&@~8(;H{QLX^?ss*$D7hH3I{KH?klOHe~08 zEo}K2=v)i%K{)XmO1`N@$)!c0ZTl{np#D=*Dd=>ZU}s-YOd)JVWHHb>KImFKkZsD~ z>JgL?pyN)6tP2{thpw$b97lt6Cpbtu!rXWb^`yk&%w*WGd9i{9^12Eo&{B1f4lGz5 zoMcS1=r`G_8g+k4LeC8GY>MS!o|SQ4<3{O-CB_eIszgkKN;E~1%yn`5rv@lz!Hm#T*95J*1|1%dn1Zxu6qJh-GtrKcfSZrD zM3aGGohbvux_kx(1{+Y|!%|Ty`1SYyXZ81}tj z0AmIdkU21%1YRBoU7Vt$0A8i0U<=-%4_n0n8UyBHU^wuFf#IMN0|R3QOfQUvm;qYS zrw7_L9&MGQmz`?_5ud1L~eUt`5hJuEPfkIMc3Fv4q z(B__sM9^SQZek83Q>ywYD8Q0aei~%(FSQujF@trRAj6KTK?({W`yd-Z;2l7yZixL! z3JTzn0Z{4zWoA$%2Z>}sMGUbRk-9(&0U;)VSfrZ->*z5sFj%15UXTmgLJq2+kp>?jBf+Sv#u;O|7#Lbk zGcdG#gKd@q4FZ9x_*76qt^q!15tKVBN^}&`a`RJCZI#NCAj6>@PZ$_FIT;ujz@y>F zZUEU1+AN@sj6deVn z#3YdZXvoEe;61CL`Etl+9N6hkkhPnze5?T46$0`Ccxs1%u@_v@fU6|P1xUpuMc~~6 zpl)Ju3HVSHPznO2cy(}=fo{J6ha%>rHss#}q)7cQIVHC^aV$v|R*jNJ&0;DGOx09FmAYqb`h~^{}AL@oD)*$*G9;6l8ot z2h_`l98?Wkp{Jm&0K2tT8!|!wU9$(a1>7b8hdUmlp!z|xa9~Z~lmlwCA=v>LNru}H z54!LhbQx}HMP_jcXp|qU6SZND;by2spdKsenk(EEg4cI|mKT7oz$%VLJ7XKw7LaQ} z7`#@EA&v%2X2T-Y(G#L8+3=9lCP**E} zR@s5tM4)zBUOKpa2;Q@or%(=Bv7HAU8UhVf=jW!DWPm&YS}p~;J{{#ea1H2Aqx>S! z8XM3VIG~lApq^_k)K2ZGJK$ErY}% zTH-a7H2m_xdtMbl>uMF?n=~|)AQdD?E$aRdkO&k*41qVcKy8L%4Fk}IPq_W4egYMu zAmv4%urB}|L=IO7btv|M7iEQF(EdHpiMRQ%3%{Ul0A+h{>j^aY11bSQtsKboCRkXn zG!t}#7-+=3G!to29ZWl@T+#!zpHoYqM}sSsrzR=sDCFy)TMDVkA#=fr;GtP)3jvfu zKqVM>1QArwLt5{dpj&}UQj<%tkI^C<2Q?@adV?nDj)U?<1_qTy3=AqS7#J8p?H-tm zK}Q&YOF*#yK&{dWjr;;ba3@gp1_OiYFVL;$pt=)MFC$GLf;Vr2d*#Smlo`|-8NisK z5F8z$c{!jX6Ldk%l4SIQZXjkt0s$1F5bWe^kP;1bJ@5(*$R*C8W0M#dMk^f9Hf59wCo?rgT~i&@ zS5F2{F+k4bfpn@s%k{x23!a407@*Va!S{E8PD29iBLX*vK8${2b6eHqhZNh$A484MSn8!>=D(@88ToD@dqeyO2C4ko!Ai1fW$y9 z&eTx=?_U6=9X$|%WfT%LQj!T9MDnGh^WEdwv^*8~kwr6ZybWH2fQg$FTb6oT49h&9g)3=Gbw z=73LK1s%0eQUtMCuLyJ+vxc#ug02GiRF=%VbkOh)=;#q8aHB;@0oGL2v;sFoKnu9? ziz*=lg86CSC2x?XjZ#Tsk&+eYoDJ9&wmJ&n8?ZoY;EJKGWTld%DkF4NpjD$P_ZjC7@gmUV94~2g)gcjCX)hWpbZHLaxNd=9D zKn8fh`)I){=fEW;cx8AhI5jFjyH608K!#lsp)d2X=7qhDrj6W1=Lc8p1=UE>oQA9U`H2&r#uv(8uSz# zb8@&Cz`g?2w$LsKhzY59K}#T&K>4vIxj+d~PJ@q^LP{vn8tRUq6b2r3LEdWvZM{Pd z;{yjVc!hXkPEl%NN~Hp96bd8Rrh!aL%O9;pK`9oD(Q8p((3$zL%`}kF%#xzSR!L7)?-VABrq8tUMsn4qn^pu2>?85vq^f$!o& z6dDlS1x5Lw{D|xbNbv>J1UcFswAU4;6xAQl31DOcpd}wv27CcWQ7*Lp$V&k)@ za3u$h3kVUfp$@(6tRS@rR6r?!S`qnq;M@e;UyPJVAiB^=&_rE)Cgi3>@QhKkI+Ul5 zXcD4p!p4Ul9spW|0cwYqCgxRw@-b3>9_%oX7}jhaV*t6iDkcxoC*&}J&6VAN_hv1!QrNtWHkhRSPuL(`eLs}yS3oPjPG;}L@T8Z zHV3>a9K0D7wD}3PMNY3g1H8d16?FMhNoF3TtN<-P$pcSGfQCDu-D?flW=l{bDLPh% zfq`KfC=hcEL5q{Y(F_?F04)s!)mzXlvxe}I(p)24D&sZOL0xK4M-p7_z~`%rAi|w1CPEDZ6jn%Iu+YkILKP4l_}`s;UGDPR?wJuL25GS<_l;lQ9#}o4leLPsv%fI z-5FHULy8JmjR)#eYJiIk&|XaVrbqb99VDPZ!`}=HO-i8Tud53Y0}WPy>b1;bg_P8S zqSWNX641TSIG4Y`uA%^?5zziNh$-p{pmDU+#1z!kCrO~90h9uu`@o=Esv&x8ArzuO z0grcqDzjKF1yBzrUPC>|H4N^3NL39fyyG?0!3TST`c26hpk_44PoNSCx^o6{(OPDS z0w~YI#=2ABX2F6I6q1njO3>hdRlmroCSF55I#x$P9onk{*_i?AfkTei2Q86+7zZLX z)FVJEas^#KT1qB7qG|)9xu-*)4Isx3P0M88}ZPo#K4P(WM0(g=E zGI9VK@jz4zAZH-s0?-;VghFJWAu9vjWD8kV91S`u1^xa%kkV8I1xWi#0X!nAhk6y>KIkS2@U0hp;J9I6oUDkNgh2L!*HD7ii-V5>N7*Bhs9>uAo@`G`)YJo) zbcpl>>g9k&ZIV#K2Hq?MT^9*98ocLQAuTa8CpCpQ>%oBtn!g6!R0?((0|O)Y#!tl7 zr)W^y46>L8yo(LeJ^*dBhmGKZ>tJZh27F+jp$_P-1W^6`-(2bfPIq>v8p*v5&Eh$hV7`8ZGAu+iqzZkR|x&U@; z6r|=xG@e10fO_np6c5=|p$pzTohr1AIKO`8v}mTZLVHXY7S^4lctVBu3jqWNIo!+ zivc{Hr2x9=wkR<#IU}`LFF7Z_I5h>*{sb8W!+H6jQ->97K?i~>Xh2kHqK$ZBj>>>^ zW7?6)#lXPQ&A`C26ZtX>@IWpoU4W`f(6vUO(P~(UZ^gynn^=?$Zc2c<*5I*aa2FhM z=}56PcpEK)!NQxw#+&;xZOKzz`pxR3>+png#a=$6?0ykaX*9e`+k zK$noFfGRPVVIUfOb#Dpwa}o7Gt!}JyB%r(rDJek71AKfacr{BA`Y8lRyD>ni2XZ0? zv^vw!MBbeNatyfLlbfHS7Y{z>1lqHJW^sgm$Y?EirxZy5<%~arY4;hy8 z3-tjnTmcQoKt#aD9)QbbkR1@Lp$-}7D9r)y-NTX9A-!kNj0}9t4Ybt=a@qlG)itF4 z2d$q59p+W60M2MRmEZ+8;N|b&)-}^Q9<*Wrax|EF zOkPZ$x+d4qo@@inYcq3N{XY^!MVu*x+G5>dDH{! zWKao~Ur++R>#+z-f>w-zTBsV)$tBQS|WnhsY51LKo;V{pjK2)4rquN zRAxpemw?V@g0y9DX;DxBDTnkx!Io%RL3TWVG=N%7`Nbu$O~^=-r?5M*A#I;%b;x;E z>ajYYMto{+K}jWO8RcMGR>kn6nt|cRSq27%DvU<5U8bqzuDJPeGCehjJ5$=jStP!SHh%^73> zXcJCpULGhFf>Xb4sJ^Z)?7%QhE2P*_0G+*-lb^1jTcn@_*(a(2Ew43|xVRV?qHaSl zV>ifP7zXvcz*B#TC8^QsPz~y_D9igQl2Z#x6j1vNF#V7-_Fygo-RGAx;Nwk5EqTzE zZY~Cf#Sk}vW*90#r!|4D&P^=>H!_gdTI6YRae)Rw6ciLPGV@Ao<295($B%(}%b*&u zSRK?~1)VPdIxGV$qJ&h|gPV0I%OGuR6%0|kFc^y=;x&}=@)7fju(OUp7J=(Y1#A~h z!n*Ph72t#cDx;u>-he7@P&S5{r34*&LW(j%-UFW#3Yt_a#c1 z!~)FFbM^Cg^$W4$Qh-c(XXKYdODj;uK@2E?$|6W+few=0MoV{_06Zu#sEvJSC);2D;Rv zARjz|rJ4e602M3f5}s35$8p~%q%8$X83Y$tDS+YtoVY>D1R1fV08mOQ0xz9XC<3jP z1hqvq(h{M0Aq~{41Fwt+t!mdufi{#uEdx*sxw;ly_mvb?BC-a!GY{R`3A(cZlw6X_ zQ*2?a;FQcFm>oKhK!O~w3Q0)Np$%}la|CS%)lo=An2lxBAQ_Z@A)^LXsDl=8#YzfF z3fiD)VU1K!&t3_n4D4=@-@(oW4<4lEBCRe%?G=K~o5?IL0S^xpYl2FA_zlI#VTQI3 z6z%}f7)NPdYDGb6GH8ETL1GE0q5(A$Qj@duOFx|o*_ zUiAj+)qvJS;W*4OI1zLX0jOI7ZA3y2Yyn3ucoYwuz!2LxLEZrsNebW#K|w4?3lQG^ z0i9_A@i}zF7^FroIk5n|aZ)`!wFF`jXrl$lFc8M52bAE-G$6Y(5L*+IDnW~9K)Vt^ z216_dE&2l;m|2t#$x^As#fj;u;Ir+Z7XZT&0AvUsv>m0uPzN$p2u{8zcO-)Hrba=U zj)Hno5@)20r1 zNe|cwpg03Vf+kQ_GdUXq*vS#6$_s*sXjo|luK2r4ze)kSq;aDhsj$G>)YJDKo&0dZJg# zLbp(X;{fCXWL%UAKH5{k7HuRGrY0>jFEJ+vsp5l4fM`%#AEMuifq}ut0otL}PzTRy zfeQG7)MV(&H1GsVaDb~bD7U7hrYRt+L5j!Jih?50z!4)uJRbu?d?^D1!y1rX$QarM z08ya%2n>%wOEsi6KC*5o8#XeYl$e>5nFi@WrhuyxNYMyY2B$L8^}rKhU?q?;3UVC? z_+YtW$USMGUSoV40|N-7Zr20PkR$b1K$A}(4}dlXCcR@|0AYr7xNT4dHeKLx$`p`Z zXpI-kr7*PCI2M3oOsTXgvp~s8p(?Wg-#SYyionY(6+qJgkO4x_#yD7E2P@$~yG@XK z8~LRr;B9=M5)K^K3=E8uL4gc8pXKoE5cIXyYxWgJdhJD6p(IOf!x)R z2D)%sA9G9|WHe}#6=>WUdqo6N0mH>$WwwxRdm8A#A?#@oq#mqRuNbsI7rUZN1zYGD z$a>ITHCT%dcnPE?mjVL=BO}P5G;rcluvLICU^ml%;|3~(WD98ICoK=OZ78t>d@B`1 z38He%OjAe$4{n2wHbw}8Y(mVQD}f{nK#>66iDp4Vg1f;8@i%XLr%@i&M z#&{hD#`qfy3=H={rok}CLU3J~nFlf@Ex#x|6?^9o)+h(pam5;tIhQm|r0M}?CWr<# zXhC}&!3_h@LeAWL)cck|(-hDpdZl@wC1csCDd163kZxR9RRL}-7ig9wBN1#U`eX^X z+J&5T3!f4J#|UIRFduZh08|esxfYayN87-y1GoxsH4N7cHW75AW{9R{EM#m9oB>k7 z!(|G#3K|;lRZF1RHD7hmA(tuOyZW&7!@=1OytoOZ7__bt%)zA+)PXEZ1+DW{4^jus zMSzaFO2MTXJS_xKt*8!N4wQ;hHFU}YzW79F_&ejMc^(X3mO2mbR;0z0`=)nhwnxZCuP?7*|g$IwEf>sHF8PFxD zAa52YgBvWc={QJX1CDl(UJyp@sewd5n2@R98EeoP-za8*bmkY7z-)`xPzrPO33XM{ zR8R)BuRwDf3Sdb{Y5^$+;mkBpAH~HrAjs9(F~rqHNfXop1Z~*_4^V^VfDo6AVTJ&_ z5a0r*$YN+q4OFI(x)={M)`Z&f1htD2L6vd|Ob*=p1KllBS^}|8Q%@l{KR1<&fx)vJ zbJGo^C`IYwgNh}jQ`S>UpbHzo4FEmp`jR5VY4o54QqX;}pt(TkY%_F`2*|nMF;mdq zGRUX~Xs0aWI`H|bnJHWh45Hl(45H^@n;i;@QVYOcNIeD6@u5n(1xg^VLCmNGts>6{ zt?>kP_(8=fsCWk1QBahcmRSKB+!vE)U=VX>VUE!1#$cM@_-ZLpr6UM$$H42(*kvwf2j^VCb=XT>Li zij+)Hx&@cTiJG#r)B1)fO?Wh{Vos}6x)#L5pYij5_PG`*`Nz0 z)M3Xbqg-PFS`VcFmw_!*SAdLgrDTHk*ML{ZfH(Mn6{n2Wkf}vU`Nc@%y`cC3VR*sE zr7+TJ1yH4eloLS9ATjT0hK{Cyf=VeaUITQbS9)qm2`DQ=u0TZ;VxTi#b5ct{R{(2( z7F2>(8s~vqmsnL7fKoqXIX}4Y0$Bm7I>7r%K}}@1C`d*bJRt{Kj;8=tfLiS+D=2_- zI;7M=)2IO51p(UTnVAP0C52@mJc^+;A7m&8p5rhyfW=WDyOR>LL8FffwhBtB#d`TgndzXtu|=tnZD1f3$QX9A zBk1HBXlD$1wl8cWO@12aY{Epyp@fiWsA9Brb;t%n+lSzd1O@qerFm(YIVGt@sVN$o z(V*qd*shsE)(>JM%qS@>$Vt^GfR6EiNBqFk_ywvU_ka>S$a5N?U3sAUSU_96!TWDP z-8#@b7!zo+9%Ljk29JzEq6Rh9!W4nVNsAzNsKA6kG_2xCO3ciO&rE~Plj0gKgBSuj z$^%@FKpT(t(#kXw|%D;gmKgUCr3wA30}rDY~VCn&+^ZKTjXSBgRgM~ErkIs z>0y|5hJj()1K2`END~+4Qqbrl^8LA>86qx*r?AVLLA#nV)6zgG4s`Q#G}sx?GjBkx zcU{o%GN|W-T#th!pqn;f(h8}G$r;d*BG5QbCi-qM@LlW0@UeK%@KixjeoARFXn+cI zt_oz|A86BMDrj&VepLdvvIm7dXxJU3u)G-LS_N%|Xf6f@S#1VT|6~wMx0dFDX4KJE z4S?JY!k`i1d{A!!ny$g6MqV;_&=|T=1az1aqTmK;f??1=4D2*Rzx)#L?XU2|r$NoR z67UsD8KB$cK&P&PZvah7O@(gJf*FH_R)-vel$xR!lLxxQ_baNi)28q<-5^$%y2oe++ZF5k|7j$zP=#X(xm?kBrKo(j; zMj0W#fn7fesZo(u#U&@^rDTGuSx9f7I2CfxJ7{BGUS57_9_Wf@&?Oj|CE!F2o&W>K z324zZY~z9+7eihuQbPeep#{#Cpl%rSxI)ToeIf<|*e14Rm; zD>uL)3i1p(Rt7}~c)eXpKB&o%Uj$m{l%k-kn+jT^4Qd+04vYg&PJ)Vs97x!r8wKJk zLr-0VM0N@&T0u9MLR<*R8<5E!kYaQUTB8n{$i(Vc>;pqEBS2cgckL;Fk5kZ5fDTZ= z!V}~WP(vptu~J=A6Qwf(H6k9|DS@?66ry#D6ySHlf|S5kg24CiK}Y;R!&;yg80h-4 zJWzOpN&zev(Lz%LwCe#f5nN(|RtvydZV&-bEP!e~(EJfd83==>-E0+L>Jn4H-8ytd z5C?%;anP0^SO8?4f&zH94_0BrhICTPAmtHi(1Iphpl6P9F+{`GCX+MukP2Eb13u4S zHmH#X9R~y@DfD?q=*C`Kh3Jgb3Q&~;zDpkD5)IH`E+_~<7*wm5=Au^U5UsF-LO>^s zfi`r2Hcf)s1>mFvI{FOMwkk>njkIeZHL75n)-=>X`&>ZFrqeRh!DSj`gdTLy4fMQW z&GF=)YutwK_MevSsHl7g(=fJ?!mEHe#y>YUu@p431hkF?pPtM-1!VPU;6*}UZJ@*c48frdHUv~2z+7R)r2y*v ztD~1NXxT+Wy&R+rGK37e{8_gc)C7Yy6~KWDs^}pKKt)4IssdOE{^Tt-7=A&1Xoq$(ul=9lJ`fT~9DMST!E;SC85btfceC*>sO zW$Qv50NvY%?(pQ?6i~`gu!XFU1C1KQr&gqbk2=dQ0`CC?H_p){po`r>8$dw=g)8b9 z7*;G`U|S69|qo(BU`Wx)Qn^Rsqp~02vIbYDUL9)s;av zY7idp1g*`0p1cB!8OXg2C7{)T;0XrU7#(O;UTGeb2ifIP480f#w8H>&s2}7mb5K1C zZl-{u7L)=@!5gF?sz2aeewaODIZ00r$!S5SbT*AH5)mzt*$T>&mN z!Kb)^;up(7qa|xdEvJK?*?_(x(Hv3B-jg z$4f3Pf{TC`gMcoZ0_`4wpEs#qnh7d%(m?ejWV{tT(*+s4R|j2U0Fnk(5DZM9-IYb~ zt>~Zufy9#h+{|PJjoid+P-$6QT9m2~S=-GVT})klu}S}3U&)9g!2nh5eAhO zfI`1AzZ7zCCcNoe0$RnKovHvfwKBi72ztgN*c9;IC(uE`MJYL%dD+DZ8m_sC$&eds z!RPzNh0|AP0*lL5jdNJR*Av0xQ;?`X>tar zb)H)YY9FV-LMJm1x(E?eN`Y1;=I1FClqTh5CWDU;1W&nx=1~yc0!UE?S-l0ib`|7S zkY-Si8*~pHqLE(JFkAc+TQbPC+{&;+gYMa`@r6QLbXq}9G4Q4j`gWCoQypasz2jm+SH zA$mF4AQ%Em1YfO!>1UAdKyjy+pHy62!oa|=5+s7Q_Z@s2Jt*?vJ!4Rb4>}4X4LtP? zx_v9Nz{)@Y(zynw0MK!cK)__b!#wq!kC7|)H zlHzDkp9a#?1f667xfUI=_8N3sduA%y_F~XDCTOi7xaftiI!G;pG)zI$df@%oWyOd_ zDX3&cbqaXNGI)cyl0T>vg_Zx&6|u44?hrybWQ{YpSr6Ws09xK$k`JmX^D3dEN=WNi zK}8uj{pEsIb%QJTcs(!$YUDsx=R>k7Xe0tQHjBKZ0C}T5*d$PWlLl&U=OTp!Xw$Jq z8d47x6u8iS0Jx8!1e&!#UaJjK0K)KsRS7(94mo&SBeys@Emp6zpdhtKLsLf~4QZwn zqzSw+3f_@b0=22InVnm#2a?iA16{oUUEmJV4#H?gFfee%F)(n=Wnf@%0!gQ*mVgJt zpk1rv#N>=ra0efDxPTR;&jnHh>bzHgMovK-@L7ut3|zk$7`SgUFfek0Ov^6--NIlC zngs_{&gwb}NXBG>c8wL4fFv})#(-Ix@X1;j&`{4S%}q)L&DkP!!|jHS96*{iFf9ri z>d+cG6|@ZkNm~YJeInR4=x7D{vMdeoS=iu`7aZ*VpGpK$~}jS_O=ngXP?0ZK!l0u;HpgsfY(GI)U6cMJ=_fq zLj6EZY={P^kW&;$D7`AP0H(-2N*%Jx3B_KBiQo)|5QpUF%rpgr5Nw17;>Yx&{L%tF zge+1%#!|YdLznSEjRRj<0Gk9#g>Jgn)dhJC)Jp(+6xkZ^nmmYI8p-K83ebyGAR-`L znp_O=I?(NF5T}D87*wF>LD!u@PBQ{+BFhDzUs9~03Eur=2wL~Rz`!EJz`)YWz`!sS zq!Cm+flu>J#B!=K^k{hSu^*tA)d3yDQw-_x=x~AOIYC3ABWvhcw?JQ47qTu5)TV*7 zx^S*w14l4KHE3fzYO@S|JN&zLAC7?50AqzFZ z!*8Gkm6_;U4?$LG+bXEXp$WVy1EdKu%nz~<;xg#MAuxq*6ST|#PddOXf%pWga>%NI zc+japC|baZvAYXtLIQMuC1??xEqDceG0H-DP_RSgVQcciDHtRUN+{q`0(2OP4&=-c z@S0hu2GoemO#=y6D%dLIrh!Y`#H3>lK%zWadHY9#jiaYeA3`Kp3GJw4h5P2Vxh-kyy|@uActjU2>ov z6GrYx%q&iYG;`ohO~|q~P(L0tUXq(x0^8W7psrf14w`)cT`dIEjLd|)dU@f z2Cer?iYg%|{N?ARA}y`VD9y_TwFJO}7HADCk>ib`POkW2_|_JLB2k|r1AT3666NR9NI{G`O3 zVo*L*0xf^Z$xH&Zra(t9X6AyT;n3t~r8$wGg z0UdL!P@JEfomzrhJEV<~m;+ty0dC)dF24m8910of<*7+}#i>PQsYMFK#TgJ5=o&o+ zl_UlRm39UO1~*XX!Z4^a5DysvfR46jq{1#af~f(~8R?LoG*l6|TcBFbz@WO2fq_9O zB{dDYLJBFRfp={n&Nx-mU|?Wipy2AAs;jv zoT{TxTv@E6P@I{bmzbjiQmms;T9lKMnWUpokdg$7{hZVa@RFJmmn96_iF`8bJ{cF&VTDQ%3=G2sh}qsGI^FNU8vx zZk1aAN)|9J@I;^kNd-EvWT2w}Ne4R6gaFe3i+0cv2B0-Y;CR=8MZ6A5%LD?3%VGX{$4mPNsUIaRIJ_WHn zT(y|+nH&o08s(t1N>IJv1fZG%+Jm48x|q2L95J9ZhKvfJfzcx3@6k#vQAh+=-jE^| z+@ONYdK70QrsS7{CRh}}OFcm)4@41Y&{Ay%0|N+yH!gzw3>u0D%>aSY4!E@hS`D0> zst%ds0p|ly{~wfOpeN`-&aFi)^gz{BVp3`jtgRhg09C938D0Y~xCEO49oaeD6HpFW)e1^LknZc(RA81?zbeLymG5B_6gak-E);3#y zel}!!cx_T3ts0I%JPF6rrG@4moESWzZcw@(o%$rGY-o9t%3z zjwhah0fZSL^H89bN|3R4l(Alra6Cj@T@y6(2+BdAmOD6SXQnA=fK)&ffX5a!Kng%L zVl>jQd@Q6&M3RH(P>)640FROd85md=!2J(pC_^^2fR3O6*#hYbfNx=godXPZ6;w5t z0#{xssi1BmWGWQ3Gy$uDY&Qe1skKr-YRKf}LmS)0;O%;#^~w3*y9`0wFcgYXp;w&4 z%z)82D?-qqT5cLB5J3Tm-66{0qiVqR!S*S_M&?0n3GiBu(mc>E1km9*iN&Z3kzr0y zP*y0;2dxDG1rvB61F>)mBZxqnkS`HWEkatlrCO|rR!4x8ft(99SKJ!{yK8r$4d z4e%Hsq#{At{!RS-ixABqM}h{XK@%|0%NIdH@Ik<$RBRV8f|S58XgzMGUKwP2AZURq zDB8f`iJ4wOi>x3=^u~i0>B5hw0G&gjpo*D6z%GNW21Xe)1m{xl=r?qVDW#|~9(1t} zC>;wsnmK?C|F zsmZzE^E)tBMZ*lsNJlmcbp9yx`WyuX1(YlWF&aUFuZsYC7CIbK09xgn3%XYYED9@q zA!E~EAxOOg8N5wQ0WGOW%`1VfG-iwjrGAv631Jt6rK+F->P&;q3jiMnpjVPuq?c4> zgkA)xm!wyzTPZ}V>wy?L3hH2m=~Wo&AXBK(>UtmsQaM(OHeXa(kP4asfE_pw$_}X& zC7}69_Xt3{(tM5kg#_Y1B*NOY+&f}WTat2Ey$u9EiF)t zLlcdX66~M_NJ9^@hzGpqLm?45(x?Cy1l3HCeN2#`Mp;LJYo#<~l{9Eyw{B^yLbRWw zuWPIxctbbXji9yBpwkvJ(~+GC*#!c>M;#I=N=ix~)u19LDKjrM1-3h-7_t={wEqrt zDP&HLLPmN~GT1Z45Qm0mmSlhylOz_Umx2!PCd0yzzhMY1r^KSEAF8CNc2Dk!VHJ6%?Fzej$-iCbt34JusqPd8j$(O z#^;vilw^X}sFLPTu-PEPKr0DLG7x7pL!AYwQju-a)dioz2VR8(y`Mt?eEciO1KcCwP@cHo21-hWB9kTs3AKf28;Inp%6%0W4b`_Tu5;WwnlG3Ye=;?xvKqc6Wmp(L{aGA4*(U~&c*1B0M11A|~L z0|SFGC_h1lOJGaUK+Efpw+VxC1f==~U!((??vrR|V31f&wsyr03=E2A7#JAzLAHaM zKS(o1=+=XFDMNRBb1^VjXD~2W_cJgs>-510p?+EcqveFL2^lIQ66Gn7Q_~;_icghH>pU@DNVtD;WEs;SRL@; z38Tj=fbN0Aa=Zd0q_L8aMHJ8@9*~9?krm_Z%OER6VuL2}^g!ziK`k2%$QlbB1(-eH zq6$ehsEk3Jat5jjkvnPXx~j#Xwn%=o0rV(%WUbKELa<(#x-MKb?BIBiYS17Ec-OlU zc!pI$RRMIAH{^PHs0m2EhqUD&^;>do3aHJ2RJ?#T<`v`@cO())Cop1!7|0Y5R)!y2QVdG}pt+HZ%)E4*>OrMV zZW`nS5k=6d81VWS+%5&#k&y_RDAa&0B|_@kgJh90_O&fA6>xKqmLego2*R7rK&y;& z!7Zg?*tSj3W>9dW1tbS)ML|jz2By*S05%N^s_Rw3XT^aMK4_c|XVL&g(@-c67+CEX z7+7-{7#K`JPKIHWZUV}#bp_Zlp`aleP~(F=gn@y576Su=D@ZfwBtTH(NVgcYS`k!+ zmgFm>q?UjVlYrcq2it_G0B)!zg0g2~ZYt=0b2|kC&?%to4;dIZ)EF2TTtEhvWaJm8 zDimktX67UoDWvA*m!^Yvl0ghB2Ccx%MA(&>oeH|4tsu21IW?~&F&%W6B1Z-T1IKFE zvi5?+B8YW*3NB!0fu?aGhCyAX03JpyPpnh`-MN&Ms*qYy0J?>(EEP1*%U{F5z`uy_ zp@sa585jf{85kI1K)xV$lnT`31l?i>Izq6d0&@@wbb}$N^n~4R$iN^_&A=dVh=GB@ z4`dGv!;9#64JFlLD^O1?v8WQ<)d20q0?m^6y@6Z?3_dSkK}ok{bZa)Pw`PMP8&bO}fVXXP zF)*x|&cLu{9|Hq}5J(a%3O_iVfnlvI1H)Py(25%dh7D&J7&b0pU|`qwRaSRR~C zLG2h&?)3?OwV(@vl*Bj7`qQEy{Fs&_$J zu#PB#n?8A|@rbplunt~MemYbTd@==QSb?rX1T~xxx)bv%%M&X>V~LomK`ww{NOuK$ ztijZPXpG(pNDvu=Ljh}Lhxhn>kP!t%`DyU8Iza;1FldekG%b;lUs9ZrUjn-Bx};bS zyvj}qboWnDej1*MCa`YMD%#9~cu;Q+bmsv!TND()N8S~K*Fi%L#n(^=t;+(9B!e!n z!MAY~VhMP30jkx+05kMcK~-rx-12DXffr;yUu7E*

VMjn!g<(BBgA<=pyrCYf-2U+2IO8aF3r?~41Gc_@YR5h zA3|;r03EbmQUpHo2dN(l)(0iv%_DWyVq0)q9@HWN83Gzs)PbA -#endif - - -/*- Private Functions -*/ - -/* Sorts suffixes of type B*. */ -static -saidx_t -sort_typeBstar(const sauchar_t *T, saidx_t *SA, - saidx_t *bucket_A, saidx_t *bucket_B, - saidx_t n) { - saidx_t *PAb, *ISAb, *buf; -#ifdef _OPENMP - saidx_t *curbuf; - saidx_t l; -#endif - saidx_t i, j, k, t, m, bufsize; - saint_t c0, c1; -#ifdef _OPENMP - saint_t d0, d1; - int tmp; -#endif - - /* Initialize bucket arrays. */ - for(i = 0; i < BUCKET_A_SIZE; ++i) { bucket_A[i] = 0; } - for(i = 0; i < BUCKET_B_SIZE; ++i) { bucket_B[i] = 0; } - - /* Count the number of occurrences of the first one or two characters of each - type A, B and B* suffix. Moreover, store the beginning position of all - type B* suffixes into the array SA. */ - for(i = n - 1, m = n, c0 = T[n - 1]; 0 <= i;) { - /* type A suffix. */ - do { ++BUCKET_A(c1 = c0); } while((0 <= --i) && ((c0 = T[i]) >= c1)); - if(0 <= i) { - /* type B* suffix. */ - ++BUCKET_BSTAR(c0, c1); - SA[--m] = i; - /* type B suffix. */ - for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) { - ++BUCKET_B(c0, c1); - } - } - } - m = n - m; -/* -note: - A type B* suffix is lexicographically smaller than a type B suffix that - begins with the same first two characters. -*/ - - /* Calculate the index of start/end point of each bucket. */ - for(c0 = 0, i = 0, j = 0; c0 < ALPHABET_SIZE; ++c0) { - t = i + BUCKET_A(c0); - BUCKET_A(c0) = i + j; /* start point */ - i = t + BUCKET_B(c0, c0); - for(c1 = c0 + 1; c1 < ALPHABET_SIZE; ++c1) { - j += BUCKET_BSTAR(c0, c1); - BUCKET_BSTAR(c0, c1) = j; /* end point */ - i += BUCKET_B(c0, c1); - } - } - - if(0 < m) { - /* Sort the type B* suffixes by their first two characters. */ - PAb = SA + n - m; ISAb = SA + m; - for(i = m - 2; 0 <= i; --i) { - t = PAb[i], c0 = T[t], c1 = T[t + 1]; - SA[--BUCKET_BSTAR(c0, c1)] = i; - } - t = PAb[m - 1], c0 = T[t], c1 = T[t + 1]; - SA[--BUCKET_BSTAR(c0, c1)] = m - 1; - - /* Sort the type B* substrings using sssort. */ -#ifdef _OPENMP - tmp = omp_get_max_threads(); - buf = SA + m, bufsize = (n - (2 * m)) / tmp; - c0 = ALPHABET_SIZE - 2, c1 = ALPHABET_SIZE - 1, j = m; -#pragma omp parallel default(shared) private(curbuf, k, l, d0, d1, tmp) - { - tmp = omp_get_thread_num(); - curbuf = buf + tmp * bufsize; - k = 0; - for(;;) { - #pragma omp critical(sssort_lock) - { - if(0 < (l = j)) { - d0 = c0, d1 = c1; - do { - k = BUCKET_BSTAR(d0, d1); - if(--d1 <= d0) { - d1 = ALPHABET_SIZE - 1; - if(--d0 < 0) { break; } - } - } while(((l - k) <= 1) && (0 < (l = k))); - c0 = d0, c1 = d1, j = k; - } - } - if(l == 0) { break; } - sssort(T, PAb, SA + k, SA + l, - curbuf, bufsize, 2, n, *(SA + k) == (m - 1)); - } - } -#else - buf = SA + m, bufsize = n - (2 * m); - for(c0 = ALPHABET_SIZE - 2, j = m; 0 < j; --c0) { - for(c1 = ALPHABET_SIZE - 1; c0 < c1; j = i, --c1) { - i = BUCKET_BSTAR(c0, c1); - if(1 < (j - i)) { - sssort(T, PAb, SA + i, SA + j, - buf, bufsize, 2, n, *(SA + i) == (m - 1)); - } - } - } -#endif - - /* Compute ranks of type B* substrings. */ - for(i = m - 1; 0 <= i; --i) { - if(0 <= SA[i]) { - j = i; - do { ISAb[SA[i]] = i; } while((0 <= --i) && (0 <= SA[i])); - SA[i + 1] = i - j; - if(i <= 0) { break; } - } - j = i; - do { ISAb[SA[i] = ~SA[i]] = j; } while(SA[--i] < 0); - ISAb[SA[i]] = j; - } - - /* Construct the inverse suffix array of type B* suffixes using trsort. */ - trsort(ISAb, SA, m, 1); - - /* Set the sorted order of tyoe B* suffixes. */ - for(i = n - 1, j = m, c0 = T[n - 1]; 0 <= i;) { - for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) >= c1); --i, c1 = c0) { } - if(0 <= i) { - t = i; - for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) { } - SA[ISAb[--j]] = ((t == 0) || (1 < (t - i))) ? t : ~t; - } - } - - /* Calculate the index of start/end point of each bucket. */ - BUCKET_B(ALPHABET_SIZE - 1, ALPHABET_SIZE - 1) = n; /* end point */ - for(c0 = ALPHABET_SIZE - 2, k = m - 1; 0 <= c0; --c0) { - i = BUCKET_A(c0 + 1) - 1; - for(c1 = ALPHABET_SIZE - 1; c0 < c1; --c1) { - t = i - BUCKET_B(c0, c1); - BUCKET_B(c0, c1) = i; /* end point */ - - /* Move all type B* suffixes to the correct position. */ - for(i = t, j = BUCKET_BSTAR(c0, c1); - j <= k; - --i, --k) { SA[i] = SA[k]; } - } - BUCKET_BSTAR(c0, c0 + 1) = i - BUCKET_B(c0, c0) + 1; /* start point */ - BUCKET_B(c0, c0) = i; /* end point */ - } - } - - return m; -} - -/* Constructs the suffix array by using the sorted order of type B* suffixes. */ -static -void -construct_SA(const sauchar_t *T, saidx_t *SA, - saidx_t *bucket_A, saidx_t *bucket_B, - saidx_t n, saidx_t m) { - saidx_t *i, *j, *k; - saidx_t s; - saint_t c0, c1, c2; - - if(0 < m) { - /* Construct the sorted order of type B suffixes by using - the sorted order of type B* suffixes. */ - for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) { - /* Scan the suffix array from right to left. */ - for(i = SA + BUCKET_BSTAR(c1, c1 + 1), - j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1; - i <= j; - --j) { - if(0 < (s = *j)) { - assert(T[s] == c1); - assert(((s + 1) < n) && (T[s] <= T[s + 1])); - assert(T[s - 1] <= T[s]); - *j = ~s; - c0 = T[--s]; - if((0 < s) && (T[s - 1] > c0)) { s = ~s; } - if(c0 != c2) { - if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; } - k = SA + BUCKET_B(c2 = c0, c1); - } - assert(k < j); - *k-- = s; - } else { - assert(((s == 0) && (T[s] == c1)) || (s < 0)); - *j = ~s; - } - } - } - } - - /* Construct the suffix array by using - the sorted order of type B suffixes. */ - k = SA + BUCKET_A(c2 = T[n - 1]); - *k++ = (T[n - 2] < c2) ? ~(n - 1) : (n - 1); - /* Scan the suffix array from left to right. */ - for(i = SA, j = SA + n; i < j; ++i) { - if(0 < (s = *i)) { - assert(T[s - 1] >= T[s]); - c0 = T[--s]; - if((s == 0) || (T[s - 1] < c0)) { s = ~s; } - if(c0 != c2) { - BUCKET_A(c2) = k - SA; - k = SA + BUCKET_A(c2 = c0); - } - assert(i < k); - *k++ = s; - } else { - assert(s < 0); - *i = ~s; - } - } -} - -/* Constructs the burrows-wheeler transformed string directly - by using the sorted order of type B* suffixes. */ -static -saidx_t -construct_BWT(const sauchar_t *T, saidx_t *SA, - saidx_t *bucket_A, saidx_t *bucket_B, - saidx_t n, saidx_t m) { - saidx_t *i, *j, *k, *orig; - saidx_t s; - saint_t c0, c1, c2; - - if(0 < m) { - /* Construct the sorted order of type B suffixes by using - the sorted order of type B* suffixes. */ - for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) { - /* Scan the suffix array from right to left. */ - for(i = SA + BUCKET_BSTAR(c1, c1 + 1), - j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1; - i <= j; - --j) { - if(0 < (s = *j)) { - assert(T[s] == c1); - assert(((s + 1) < n) && (T[s] <= T[s + 1])); - assert(T[s - 1] <= T[s]); - c0 = T[--s]; - *j = ~((saidx_t)c0); - if((0 < s) && (T[s - 1] > c0)) { s = ~s; } - if(c0 != c2) { - if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; } - k = SA + BUCKET_B(c2 = c0, c1); - } - assert(k < j); - *k-- = s; - } else if(s != 0) { - *j = ~s; -#ifndef NDEBUG - } else { - assert(T[s] == c1); -#endif - } - } - } - } - - /* Construct the BWTed string by using - the sorted order of type B suffixes. */ - k = SA + BUCKET_A(c2 = T[n - 1]); - *k++ = (T[n - 2] < c2) ? ~((saidx_t)T[n - 2]) : (n - 1); - /* Scan the suffix array from left to right. */ - for(i = SA, j = SA + n, orig = SA; i < j; ++i) { - if(0 < (s = *i)) { - assert(T[s - 1] >= T[s]); - c0 = T[--s]; - *i = c0; - if((0 < s) && (T[s - 1] < c0)) { s = ~((saidx_t)T[s - 1]); } - if(c0 != c2) { - BUCKET_A(c2) = k - SA; - k = SA + BUCKET_A(c2 = c0); - } - assert(i < k); - *k++ = s; - } else if(s != 0) { - *i = ~s; - } else { - orig = i; - } - } - - return orig - SA; -} - - -/*---------------------------------------------------------------------------*/ - -/*- Function -*/ - -saint_t -divsufsort(const sauchar_t *T, saidx_t *SA, saidx_t n) { - saidx_t *bucket_A, *bucket_B; - saidx_t m; - saint_t err = 0; - - /* Check arguments. */ - if((T == NULL) || (SA == NULL) || (n < 0)) { return -1; } - else if(n == 0) { return 0; } - else if(n == 1) { SA[0] = 0; return 0; } - else if(n == 2) { m = (T[0] < T[1]); SA[m ^ 1] = 0, SA[m] = 1; return 0; } - - bucket_A = (saidx_t *)malloc(BUCKET_A_SIZE * sizeof(saidx_t)); - bucket_B = (saidx_t *)malloc(BUCKET_B_SIZE * sizeof(saidx_t)); - - /* Suffixsort. */ - if((bucket_A != NULL) && (bucket_B != NULL)) { - m = sort_typeBstar(T, SA, bucket_A, bucket_B, n); - construct_SA(T, SA, bucket_A, bucket_B, n, m); - } else { - err = -2; - } - - free(bucket_B); - free(bucket_A); - - return err; -} - -saidx_t -divbwt(const sauchar_t *T, sauchar_t *U, saidx_t *A, saidx_t n) { - saidx_t *B; - saidx_t *bucket_A, *bucket_B; - saidx_t m, pidx, i; - - /* Check arguments. */ - if((T == NULL) || (U == NULL) || (n < 0)) { return -1; } - else if(n <= 1) { if(n == 1) { U[0] = T[0]; } return n; } - - if((B = A) == NULL) { B = (saidx_t *)malloc((size_t)(n + 1) * sizeof(saidx_t)); } - bucket_A = (saidx_t *)malloc(BUCKET_A_SIZE * sizeof(saidx_t)); - bucket_B = (saidx_t *)malloc(BUCKET_B_SIZE * sizeof(saidx_t)); - - /* Burrows-Wheeler Transform. */ - if((B != NULL) && (bucket_A != NULL) && (bucket_B != NULL)) { - m = sort_typeBstar(T, B, bucket_A, bucket_B, n); - pidx = construct_BWT(T, B, bucket_A, bucket_B, n, m); - - /* Copy to output string. */ - U[0] = T[n - 1]; - for(i = 0; i < pidx; ++i) { U[i + 1] = (sauchar_t)B[i]; } - for(i += 1; i < n; ++i) { U[i] = (sauchar_t)B[i]; } - pidx += 1; - } else { - pidx = -2; - } - - free(bucket_B); - free(bucket_A); - if(A == NULL) { free(B); } - - return pidx; -} - -const char * -divsufsort_version(void) { - return PROJECT_VERSION_FULL; -} diff --git a/dictBuilder/divsufsort.h b/dictBuilder/divsufsort.h deleted file mode 100644 index 6d3e64870..000000000 --- a/dictBuilder/divsufsort.h +++ /dev/null @@ -1,180 +0,0 @@ -/* - * divsufsort.h for libdivsufsort - * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _DIVSUFSORT_H -#define _DIVSUFSORT_H 1 - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#include - -#ifndef DIVSUFSORT_API -# ifdef DIVSUFSORT_BUILD_DLL -# define DIVSUFSORT_API -# else -# define DIVSUFSORT_API -# endif -#endif - -/*- Datatypes -*/ -#ifndef SAUCHAR_T -#define SAUCHAR_T -typedef uint8_t sauchar_t; -#endif /* SAUCHAR_T */ -#ifndef SAINT_T -#define SAINT_T -typedef int32_t saint_t; -#endif /* SAINT_T */ -#ifndef SAIDX_T -#define SAIDX_T -typedef int32_t saidx_t; -#endif /* SAIDX_T */ -#ifndef PRIdSAINT_T -#define PRIdSAINT_T PRId32 -#endif /* PRIdSAINT_T */ -#ifndef PRIdSAIDX_T -#define PRIdSAIDX_T PRId32 -#endif /* PRIdSAIDX_T */ - - -/*- Prototypes -*/ - -/** - * Constructs the suffix array of a given string. - * @param T[0..n-1] The input string. - * @param SA[0..n-1] The output array of suffixes. - * @param n The length of the given string. - * @return 0 if no error occurred, -1 or -2 otherwise. - */ -DIVSUFSORT_API -saint_t -divsufsort(const sauchar_t *T, saidx_t *SA, saidx_t n); - -/** - * Constructs the burrows-wheeler transformed string of a given string. - * @param T[0..n-1] The input string. - * @param U[0..n-1] The output string. (can be T) - * @param A[0..n-1] The temporary array. (can be NULL) - * @param n The length of the given string. - * @return The primary index if no error occurred, -1 or -2 otherwise. - */ -DIVSUFSORT_API -saidx_t -divbwt(const sauchar_t *T, sauchar_t *U, saidx_t *A, saidx_t n); - -/** - * Returns the version of the divsufsort library. - * @return The version number string. - */ -DIVSUFSORT_API -const char * -divsufsort_version(void); - - -/** - * Constructs the burrows-wheeler transformed string of a given string and suffix array. - * @param T[0..n-1] The input string. - * @param U[0..n-1] The output string. (can be T) - * @param SA[0..n-1] The suffix array. (can be NULL) - * @param n The length of the given string. - * @param idx The output primary index. - * @return 0 if no error occurred, -1 or -2 otherwise. - */ -DIVSUFSORT_API -saint_t -bw_transform(const sauchar_t *T, sauchar_t *U, - saidx_t *SA /* can NULL */, - saidx_t n, saidx_t *idx); - -/** - * Inverse BW-transforms a given BWTed string. - * @param T[0..n-1] The input string. - * @param U[0..n-1] The output string. (can be T) - * @param A[0..n-1] The temporary array. (can be NULL) - * @param n The length of the given string. - * @param idx The primary index. - * @return 0 if no error occurred, -1 or -2 otherwise. - */ -DIVSUFSORT_API -saint_t -inverse_bw_transform(const sauchar_t *T, sauchar_t *U, - saidx_t *A /* can NULL */, - saidx_t n, saidx_t idx); - -/** - * Checks the correctness of a given suffix array. - * @param T[0..n-1] The input string. - * @param SA[0..n-1] The input suffix array. - * @param n The length of the given string. - * @param verbose The verbose mode. - * @return 0 if no error occurred. - */ -DIVSUFSORT_API -saint_t -sufcheck(const sauchar_t *T, const saidx_t *SA, saidx_t n, saint_t verbose); - -/** - * Search for the pattern P in the string T. - * @param T[0..Tsize-1] The input string. - * @param Tsize The length of the given string. - * @param P[0..Psize-1] The input pattern string. - * @param Psize The length of the given pattern string. - * @param SA[0..SAsize-1] The input suffix array. - * @param SAsize The length of the given suffix array. - * @param idx The output index. - * @return The count of matches if no error occurred, -1 otherwise. - */ -DIVSUFSORT_API -saidx_t -sa_search(const sauchar_t *T, saidx_t Tsize, - const sauchar_t *P, saidx_t Psize, - const saidx_t *SA, saidx_t SAsize, - saidx_t *left); - -/** - * Search for the character c in the string T. - * @param T[0..Tsize-1] The input string. - * @param Tsize The length of the given string. - * @param SA[0..SAsize-1] The input suffix array. - * @param SAsize The length of the given suffix array. - * @param c The input character. - * @param idx The output index. - * @return The count of matches if no error occurred, -1 otherwise. - */ -DIVSUFSORT_API -saidx_t -sa_simplesearch(const sauchar_t *T, saidx_t Tsize, - const saidx_t *SA, saidx_t SAsize, - saint_t c, saidx_t *left); - - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ - -#endif /* _DIVSUFSORT_H */ diff --git a/dictBuilder/divsufsort_private.h b/dictBuilder/divsufsort_private.h deleted file mode 100644 index 0a18f6d28..000000000 --- a/dictBuilder/divsufsort_private.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - * divsufsort_private.h for libdivsufsort - * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _DIVSUFSORT_PRIVATE_H -#define _DIVSUFSORT_PRIVATE_H 1 - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* ************************* -* Includes -***************************/ -#include -#include /* unconditional */ -#include -#include "config.h" /* unconditional */ - - -#if HAVE_STRING_H -# include -#endif -#if HAVE_MEMORY_H -# include -#endif -#if HAVE_STDDEF_H -# include -#endif -#if HAVE_STRINGS_H -# ifdef _WIN32 -# include -# else -# include -# endif -#endif -#if HAVE_INTTYPES_H -# include -#else -# if HAVE_STDINT_H -# include -# endif -#endif -#if defined(BUILD_DIVSUFSORT64) -# include "divsufsort64.h" -# ifndef SAIDX_T -# define SAIDX_T -# define saidx_t saidx64_t -# endif /* SAIDX_T */ -# ifndef PRIdSAIDX_T -# define PRIdSAIDX_T PRIdSAIDX64_T -# endif /* PRIdSAIDX_T */ -# define divsufsort divsufsort64 -# define divbwt divbwt64 -# define divsufsort_version divsufsort64_version -# define bw_transform bw_transform64 -# define inverse_bw_transform inverse_bw_transform64 -# define sufcheck sufcheck64 -# define sa_search sa_search64 -# define sa_simplesearch sa_simplesearch64 -# define sssort sssort64 -# define trsort trsort64 -#else -# include "divsufsort.h" -#endif - - -/*- Constants -*/ -#if !defined(UINT8_MAX) -# define UINT8_MAX (255) -#endif /* UINT8_MAX */ -#if defined(ALPHABET_SIZE) && (ALPHABET_SIZE < 1) -# undef ALPHABET_SIZE -#endif -#if !defined(ALPHABET_SIZE) -# define ALPHABET_SIZE (UINT8_MAX + 1) -#endif -/* for divsufsort.c */ -#define BUCKET_A_SIZE (ALPHABET_SIZE) -#define BUCKET_B_SIZE (ALPHABET_SIZE * ALPHABET_SIZE) -/* for sssort.c */ -#if defined(SS_INSERTIONSORT_THRESHOLD) -# if SS_INSERTIONSORT_THRESHOLD < 1 -# undef SS_INSERTIONSORT_THRESHOLD -# define SS_INSERTIONSORT_THRESHOLD (1) -# endif -#else -# define SS_INSERTIONSORT_THRESHOLD (8) -#endif -#if defined(SS_BLOCKSIZE) -# if SS_BLOCKSIZE < 0 -# undef SS_BLOCKSIZE -# define SS_BLOCKSIZE (0) -# elif 32768 <= SS_BLOCKSIZE -# undef SS_BLOCKSIZE -# define SS_BLOCKSIZE (32767) -# endif -#else -# define SS_BLOCKSIZE (1024) -#endif -/* minstacksize = log(SS_BLOCKSIZE) / log(3) * 2 */ -#if SS_BLOCKSIZE == 0 -# if defined(BUILD_DIVSUFSORT64) -# define SS_MISORT_STACKSIZE (96) -# else -# define SS_MISORT_STACKSIZE (64) -# endif -#elif SS_BLOCKSIZE <= 4096 -# define SS_MISORT_STACKSIZE (16) -#else -# define SS_MISORT_STACKSIZE (24) -#endif -#if defined(BUILD_DIVSUFSORT64) -# define SS_SMERGE_STACKSIZE (64) -#else -# define SS_SMERGE_STACKSIZE (32) -#endif -/* for trsort.c */ -#define TR_INSERTIONSORT_THRESHOLD (8) -#if defined(BUILD_DIVSUFSORT64) -# define TR_STACKSIZE (96) -#else -# define TR_STACKSIZE (64) -#endif - - -/*- Macros -*/ -#ifndef SWAP -# define SWAP(_a, _b) do { t = (_a); (_a) = (_b); (_b) = t; } while(0) -#endif /* SWAP */ -#ifndef MIN -# define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) -#endif /* MIN */ -#ifndef MAX -# define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) -#endif /* MAX */ -#define STACK_PUSH(_a, _b, _c, _d)\ - do {\ - assert(ssize < STACK_SIZE);\ - stack[ssize].a = (_a), stack[ssize].b = (_b),\ - stack[ssize].c = (_c), stack[ssize++].d = (_d);\ - } while(0) -#define STACK_PUSH5(_a, _b, _c, _d, _e)\ - do {\ - assert(ssize < STACK_SIZE);\ - stack[ssize].a = (_a), stack[ssize].b = (_b),\ - stack[ssize].c = (_c), stack[ssize].d = (_d), stack[ssize++].e = (_e);\ - } while(0) -#define STACK_POP(_a, _b, _c, _d)\ - do {\ - assert(0 <= ssize);\ - if(ssize == 0) { return; }\ - (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\ - (_c) = stack[ssize].c, (_d) = stack[ssize].d;\ - } while(0) -#define STACK_POP5(_a, _b, _c, _d, _e)\ - do {\ - assert(0 <= ssize);\ - if(ssize == 0) { return; }\ - (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\ - (_c) = stack[ssize].c, (_d) = stack[ssize].d, (_e) = stack[ssize].e;\ - } while(0) -/* for divsufsort.c */ -#define BUCKET_A(_c0) bucket_A[(_c0)] -#if ALPHABET_SIZE == 256 -#define BUCKET_B(_c0, _c1) (bucket_B[((_c1) << 8) | (_c0)]) -#define BUCKET_BSTAR(_c0, _c1) (bucket_B[((_c0) << 8) | (_c1)]) -#else -#define BUCKET_B(_c0, _c1) (bucket_B[(_c1) * ALPHABET_SIZE + (_c0)]) -#define BUCKET_BSTAR(_c0, _c1) (bucket_B[(_c0) * ALPHABET_SIZE + (_c1)]) -#endif - - -/*- Private Prototypes -*/ -/* sssort.c */ -void -sssort(const sauchar_t *Td, const saidx_t *PA, - saidx_t *first, saidx_t *last, - saidx_t *buf, saidx_t bufsize, - saidx_t depth, saidx_t n, saint_t lastsuffix); -/* trsort.c */ -void -trsort(saidx_t *ISA, saidx_t *SA, saidx_t n, saidx_t depth); - - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ - -#endif /* _DIVSUFSORT_PRIVATE_H */ diff --git a/dictBuilder/lfs.h b/dictBuilder/lfs.h deleted file mode 100644 index 7ef88f0b4..000000000 --- a/dictBuilder/lfs.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * lfs.h for libdivsufsort - * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _LFS_H -#define _LFS_H 1 - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef __STRICT_ANSI__ -# define LFS_OFF_T off_t -# define LFS_FOPEN fopen -# define LFS_FTELL ftello -# define LFS_FSEEK fseeko -# define LFS_PRId PRIdMAX -#else -# define LFS_OFF_T long -# define LFS_FOPEN fopen -# define LFS_FTELL ftell -# define LFS_FSEEK fseek -# define LFS_PRId "ld" -#endif -#ifndef PRIdOFF_T -# define PRIdOFF_T LFS_PRId -#endif - - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ - -#endif /* _LFS_H */ diff --git a/dictBuilder/sssort.c b/dictBuilder/sssort.c deleted file mode 100644 index 07cb5bd1b..000000000 --- a/dictBuilder/sssort.c +++ /dev/null @@ -1,844 +0,0 @@ -/* - * sssort.c for libdivsufsort - * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -/*- Compiler specifics -*/ -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wshorten-64-to-32" -#endif - -#if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -/* inline is defined */ -#elif defined(_MSC_VER) -# define inline __inline -#else -# define inline /* disable inline */ -#endif - -#ifdef _MSC_VER /* Visual Studio */ -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -# define FORCE_INLINE static __forceinline -#else -# if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif -# else -# define FORCE_INLINE static -# endif /* __STDC_VERSION__ */ -#endif - -/*- Dependencies -*/ -#include "divsufsort_private.h" - - -/*- Private Functions -*/ - -static const saint_t lg_table[256]= { - -1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 -}; - -#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) - -static INLINE -saint_t -ss_ilg(saidx_t n) { -#if SS_BLOCKSIZE == 0 -# if defined(BUILD_DIVSUFSORT64) - return (n >> 32) ? - ((n >> 48) ? - ((n >> 56) ? - 56 + lg_table[(n >> 56) & 0xff] : - 48 + lg_table[(n >> 48) & 0xff]) : - ((n >> 40) ? - 40 + lg_table[(n >> 40) & 0xff] : - 32 + lg_table[(n >> 32) & 0xff])) : - ((n & 0xffff0000) ? - ((n & 0xff000000) ? - 24 + lg_table[(n >> 24) & 0xff] : - 16 + lg_table[(n >> 16) & 0xff]) : - ((n & 0x0000ff00) ? - 8 + lg_table[(n >> 8) & 0xff] : - 0 + lg_table[(n >> 0) & 0xff])); -# else - return (n & 0xffff0000) ? - ((n & 0xff000000) ? - 24 + lg_table[(n >> 24) & 0xff] : - 16 + lg_table[(n >> 16) & 0xff]) : - ((n & 0x0000ff00) ? - 8 + lg_table[(n >> 8) & 0xff] : - 0 + lg_table[(n >> 0) & 0xff]); -# endif -#elif SS_BLOCKSIZE < 256 - return lg_table[n]; -#else - return (n & 0xff00) ? - 8 + lg_table[(n >> 8) & 0xff] : - 0 + lg_table[(n >> 0) & 0xff]; -#endif -} - -#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */ - -#if SS_BLOCKSIZE != 0 - -static const saint_t sqq_table[256] = { - 0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57, 59, 61, - 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81, 83, 84, 86, 87, 89, - 90, 91, 93, 94, 96, 97, 98, 99, 101, 102, 103, 104, 106, 107, 108, 109, -110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, -128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, -143, 144, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155, -156, 157, 158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168, -169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 178, 179, 180, -181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190, 191, -192, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 199, 200, 201, 201, -202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211, -212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 221, -221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230, -230, 231, 231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, -239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, -247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255 -}; - -static INLINE -saidx_t -ss_isqrt(saidx_t x) { - saidx_t y, e; - - if(x >= (SS_BLOCKSIZE * SS_BLOCKSIZE)) { return SS_BLOCKSIZE; } - e = (x & 0xffff0000) ? - ((x & 0xff000000) ? - 24 + lg_table[(x >> 24) & 0xff] : - 16 + lg_table[(x >> 16) & 0xff]) : - ((x & 0x0000ff00) ? - 8 + lg_table[(x >> 8) & 0xff] : - 0 + lg_table[(x >> 0) & 0xff]); - - if(e >= 16) { - y = sqq_table[x >> ((e - 6) - (e & 1))] << ((e >> 1) - 7); - if(e >= 24) { y = (y + 1 + x / y) >> 1; } - y = (y + 1 + x / y) >> 1; - } else if(e >= 8) { - y = (sqq_table[x >> ((e - 6) - (e & 1))] >> (7 - (e >> 1))) + 1; - } else { - return sqq_table[x] >> 4; - } - - return (x < (y * y)) ? y - 1 : y; -} - -#endif /* SS_BLOCKSIZE != 0 */ - - -/*---------------------------------------------------------------------------*/ - -/* Compares two suffixes. */ -static INLINE -saint_t -ss_compare(const sauchar_t *T, - const saidx_t *p1, const saidx_t *p2, - saidx_t depth) { - const sauchar_t *U1, *U2, *U1n, *U2n; - - for(U1 = T + depth + *p1, - U2 = T + depth + *p2, - U1n = T + *(p1 + 1) + 2, - U2n = T + *(p2 + 1) + 2; - (U1 < U1n) && (U2 < U2n) && (*U1 == *U2); - ++U1, ++U2) { - } - - return U1 < U1n ? - (U2 < U2n ? *U1 - *U2 : 1) : - (U2 < U2n ? -1 : 0); -} - - -/*---------------------------------------------------------------------------*/ - -#if (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1) - -/* Insertionsort for small size groups */ -static -void -ss_insertionsort(const sauchar_t *T, const saidx_t *PA, - saidx_t *first, saidx_t *last, saidx_t depth) { - saidx_t *i, *j; - saidx_t t; - saint_t r; - - for(i = last - 2; first <= i; --i) { - for(t = *i, j = i + 1; 0 < (r = ss_compare(T, PA + t, PA + *j, depth));) { - do { *(j - 1) = *j; } while((++j < last) && (*j < 0)); - if(last <= j) { break; } - } - if(r == 0) { *j = ~*j; } - *(j - 1) = t; - } -} - -#endif /* (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1) */ - - -/*---------------------------------------------------------------------------*/ - -#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) - -static INLINE -void -ss_fixdown(const sauchar_t *Td, const saidx_t *PA, - saidx_t *SA, saidx_t i, saidx_t size) { - saidx_t j, k; - saidx_t v; - saint_t c, d, e; - - for(v = SA[i], c = Td[PA[v]]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) { - d = Td[PA[SA[k = j++]]]; - if(d < (e = Td[PA[SA[j]]])) { k = j; d = e; } - if(d <= c) { break; } - } - SA[i] = v; -} - -/* Simple top-down heapsort. */ -static -void -ss_heapsort(const sauchar_t *Td, const saidx_t *PA, saidx_t *SA, saidx_t size) { - saidx_t i, m; - saidx_t t; - - m = size; - if((size % 2) == 0) { - m--; - if(Td[PA[SA[m / 2]]] < Td[PA[SA[m]]]) { SWAP(SA[m], SA[m / 2]); } - } - - for(i = m / 2 - 1; 0 <= i; --i) { ss_fixdown(Td, PA, SA, i, m); } - if((size % 2) == 0) { SWAP(SA[0], SA[m]); ss_fixdown(Td, PA, SA, 0, m); } - for(i = m - 1; 0 < i; --i) { - t = SA[0], SA[0] = SA[i]; - ss_fixdown(Td, PA, SA, 0, i); - SA[i] = t; - } -} - - -/*---------------------------------------------------------------------------*/ - -/* Returns the median of three elements. */ -static INLINE -saidx_t * -ss_median3(const sauchar_t *Td, const saidx_t *PA, - saidx_t *v1, saidx_t *v2, saidx_t *v3) { - saidx_t *t; - if(Td[PA[*v1]] > Td[PA[*v2]]) { SWAP(v1, v2); } - if(Td[PA[*v2]] > Td[PA[*v3]]) { - if(Td[PA[*v1]] > Td[PA[*v3]]) { return v1; } - else { return v3; } - } - return v2; -} - -/* Returns the median of five elements. */ -static INLINE -saidx_t * -ss_median5(const sauchar_t *Td, const saidx_t *PA, - saidx_t *v1, saidx_t *v2, saidx_t *v3, saidx_t *v4, saidx_t *v5) { - saidx_t *t; - if(Td[PA[*v2]] > Td[PA[*v3]]) { SWAP(v2, v3); } - if(Td[PA[*v4]] > Td[PA[*v5]]) { SWAP(v4, v5); } - if(Td[PA[*v2]] > Td[PA[*v4]]) { SWAP(v2, v4); SWAP(v3, v5); } - if(Td[PA[*v1]] > Td[PA[*v3]]) { SWAP(v1, v3); } - if(Td[PA[*v1]] > Td[PA[*v4]]) { SWAP(v1, v4); SWAP(v3, v5); } - if(Td[PA[*v3]] > Td[PA[*v4]]) { return v4; } - return v3; -} - -/* Returns the pivot element. */ -static INLINE -saidx_t * -ss_pivot(const sauchar_t *Td, const saidx_t *PA, saidx_t *first, saidx_t *last) { - saidx_t *middle; - saidx_t t; - - t = last - first; - middle = first + t / 2; - - if(t <= 512) { - if(t <= 32) { - return ss_median3(Td, PA, first, middle, last - 1); - } else { - t >>= 2; - return ss_median5(Td, PA, first, first + t, middle, last - 1 - t, last - 1); - } - } - t >>= 3; - first = ss_median3(Td, PA, first, first + t, first + (t << 1)); - middle = ss_median3(Td, PA, middle - t, middle, middle + t); - last = ss_median3(Td, PA, last - 1 - (t << 1), last - 1 - t, last - 1); - return ss_median3(Td, PA, first, middle, last); -} - - -/*---------------------------------------------------------------------------*/ - -/* Binary partition for substrings. */ -static INLINE -saidx_t * -ss_partition(const saidx_t *PA, - saidx_t *first, saidx_t *last, saidx_t depth) { - saidx_t *a, *b; - saidx_t t; - for(a = first - 1, b = last;;) { - for(; (++a < b) && ((PA[*a] + depth) >= (PA[*a + 1] + 1));) { *a = ~*a; } - for(; (a < --b) && ((PA[*b] + depth) < (PA[*b + 1] + 1));) { } - if(b <= a) { break; } - t = ~*b; - *b = *a; - *a = t; - } - if(first < a) { *first = ~*first; } - return a; -} - -/* Multikey introsort for medium size groups. */ -static -void -ss_mintrosort(const sauchar_t *T, const saidx_t *PA, - saidx_t *first, saidx_t *last, - saidx_t depth) { -#define STACK_SIZE SS_MISORT_STACKSIZE - struct { saidx_t *a, *b, c; saint_t d; } stack[STACK_SIZE]; - const sauchar_t *Td; - saidx_t *a, *b, *c, *d, *e, *f; - saidx_t s, t; - saint_t ssize; - saint_t limit; - saint_t v, x = 0; - - for(ssize = 0, limit = ss_ilg(last - first);;) { - - if((last - first) <= SS_INSERTIONSORT_THRESHOLD) { -#if 1 < SS_INSERTIONSORT_THRESHOLD - if(1 < (last - first)) { ss_insertionsort(T, PA, first, last, depth); } -#endif - STACK_POP(first, last, depth, limit); - continue; - } - - Td = T + depth; - if(limit-- == 0) { ss_heapsort(Td, PA, first, last - first); } - if(limit < 0) { - for(a = first + 1, v = Td[PA[*first]]; a < last; ++a) { - if((x = Td[PA[*a]]) != v) { - if(1 < (a - first)) { break; } - v = x; - first = a; - } - } - if(Td[PA[*first] - 1] < v) { - first = ss_partition(PA, first, a, depth); - } - if((a - first) <= (last - a)) { - if(1 < (a - first)) { - STACK_PUSH(a, last, depth, -1); - last = a, depth += 1, limit = ss_ilg(a - first); - } else { - first = a, limit = -1; - } - } else { - if(1 < (last - a)) { - STACK_PUSH(first, a, depth + 1, ss_ilg(a - first)); - first = a, limit = -1; - } else { - last = a, depth += 1, limit = ss_ilg(a - first); - } - } - continue; - } - - /* choose pivot */ - a = ss_pivot(Td, PA, first, last); - v = Td[PA[*a]]; - SWAP(*first, *a); - - /* partition */ - for(b = first; (++b < last) && ((x = Td[PA[*b]]) == v);) { } - if(((a = b) < last) && (x < v)) { - for(; (++b < last) && ((x = Td[PA[*b]]) <= v);) { - if(x == v) { SWAP(*b, *a); ++a; } - } - } - for(c = last; (b < --c) && ((x = Td[PA[*c]]) == v);) { } - if((b < (d = c)) && (x > v)) { - for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) { - if(x == v) { SWAP(*c, *d); --d; } - } - } - for(; b < c;) { - SWAP(*b, *c); - for(; (++b < c) && ((x = Td[PA[*b]]) <= v);) { - if(x == v) { SWAP(*b, *a); ++a; } - } - for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) { - if(x == v) { SWAP(*c, *d); --d; } - } - } - - if(a <= d) { - c = b - 1; - - if((s = a - first) > (t = b - a)) { s = t; } - for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } - if((s = d - c) > (t = last - d - 1)) { s = t; } - for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } - - a = first + (b - a), c = last - (d - c); - b = (v <= Td[PA[*a] - 1]) ? a : ss_partition(PA, a, c, depth); - - if((a - first) <= (last - c)) { - if((last - c) <= (c - b)) { - STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); - STACK_PUSH(c, last, depth, limit); - last = a; - } else if((a - first) <= (c - b)) { - STACK_PUSH(c, last, depth, limit); - STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); - last = a; - } else { - STACK_PUSH(c, last, depth, limit); - STACK_PUSH(first, a, depth, limit); - first = b, last = c, depth += 1, limit = ss_ilg(c - b); - } - } else { - if((a - first) <= (c - b)) { - STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); - STACK_PUSH(first, a, depth, limit); - first = c; - } else if((last - c) <= (c - b)) { - STACK_PUSH(first, a, depth, limit); - STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); - first = c; - } else { - STACK_PUSH(first, a, depth, limit); - STACK_PUSH(c, last, depth, limit); - first = b, last = c, depth += 1, limit = ss_ilg(c - b); - } - } - } else { - limit += 1; - if(Td[PA[*first] - 1] < v) { - first = ss_partition(PA, first, last, depth); - limit = ss_ilg(last - first); - } - depth += 1; - } - } -#undef STACK_SIZE -} - -#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */ - - -/*---------------------------------------------------------------------------*/ - -#if SS_BLOCKSIZE != 0 - -static INLINE -void -ss_blockswap(saidx_t *a, saidx_t *b, saidx_t n) { - saidx_t t; - for(; 0 < n; --n, ++a, ++b) { - t = *a, *a = *b, *b = t; - } -} - -static INLINE -void -ss_rotate(saidx_t *first, saidx_t *middle, saidx_t *last) { - saidx_t *a, *b, t; - saidx_t l, r; - l = middle - first, r = last - middle; - for(; (0 < l) && (0 < r);) { - if(l == r) { ss_blockswap(first, middle, l); break; } - if(l < r) { - a = last - 1, b = middle - 1; - t = *a; - do { - *a-- = *b, *b-- = *a; - if(b < first) { - *a = t; - last = a; - if((r -= l + 1) <= l) { break; } - a -= 1, b = middle - 1; - t = *a; - } - } while(1); - } else { - a = first, b = middle; - t = *a; - do { - *a++ = *b, *b++ = *a; - if(last <= b) { - *a = t; - first = a + 1; - if((l -= r + 1) <= r) { break; } - a += 1, b = middle; - t = *a; - } - } while(1); - } - } -} - - -/*---------------------------------------------------------------------------*/ - -static -void -ss_inplacemerge(const sauchar_t *T, const saidx_t *PA, - saidx_t *first, saidx_t *middle, saidx_t *last, - saidx_t depth) { - const saidx_t *p; - saidx_t *a, *b; - saidx_t len, half; - saint_t q, r; - saint_t x; - - for(;;) { - if(*(last - 1) < 0) { x = 1; p = PA + ~*(last - 1); } - else { x = 0; p = PA + *(last - 1); } - for(a = first, len = middle - first, half = len >> 1, r = -1; - 0 < len; - len = half, half >>= 1) { - b = a + half; - q = ss_compare(T, PA + ((0 <= *b) ? *b : ~*b), p, depth); - if(q < 0) { - a = b + 1; - half -= (len & 1) ^ 1; - } else { - r = q; - } - } - if(a < middle) { - if(r == 0) { *a = ~*a; } - ss_rotate(a, middle, last); - last -= middle - a; - middle = a; - if(first == middle) { break; } - } - --last; - if(x != 0) { while(*--last < 0) { } } - if(middle == last) { break; } - } -} - - -/*---------------------------------------------------------------------------*/ - -/* Merge-forward with internal buffer. */ -static -void -ss_mergeforward(const sauchar_t *T, const saidx_t *PA, - saidx_t *first, saidx_t *middle, saidx_t *last, - saidx_t *buf, saidx_t depth) { - saidx_t *a, *b, *c, *bufend; - saidx_t t; - saint_t r; - - bufend = buf + (middle - first) - 1; - ss_blockswap(buf, first, middle - first); - - for(t = *(a = first), b = buf, c = middle;;) { - r = ss_compare(T, PA + *b, PA + *c, depth); - if(r < 0) { - do { - *a++ = *b; - if(bufend <= b) { *bufend = t; return; } - *b++ = *a; - } while(*b < 0); - } else if(r > 0) { - do { - *a++ = *c, *c++ = *a; - if(last <= c) { - while(b < bufend) { *a++ = *b, *b++ = *a; } - *a = *b, *b = t; - return; - } - } while(*c < 0); - } else { - *c = ~*c; - do { - *a++ = *b; - if(bufend <= b) { *bufend = t; return; } - *b++ = *a; - } while(*b < 0); - - do { - *a++ = *c, *c++ = *a; - if(last <= c) { - while(b < bufend) { *a++ = *b, *b++ = *a; } - *a = *b, *b = t; - return; - } - } while(*c < 0); - } - } -} - -/* Merge-backward with internal buffer. */ -static -void -ss_mergebackward(const sauchar_t *T, const saidx_t *PA, - saidx_t *first, saidx_t *middle, saidx_t *last, - saidx_t *buf, saidx_t depth) { - const saidx_t *p1, *p2; - saidx_t *a, *b, *c, *bufend; - saidx_t t; - saint_t r; - saint_t x; - - bufend = buf + (last - middle) - 1; - ss_blockswap(buf, middle, last - middle); - - x = 0; - if(*bufend < 0) { p1 = PA + ~*bufend; x |= 1; } - else { p1 = PA + *bufend; } - if(*(middle - 1) < 0) { p2 = PA + ~*(middle - 1); x |= 2; } - else { p2 = PA + *(middle - 1); } - for(t = *(a = last - 1), b = bufend, c = middle - 1;;) { - r = ss_compare(T, p1, p2, depth); - if(0 < r) { - if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; } - *a-- = *b; - if(b <= buf) { *buf = t; break; } - *b-- = *a; - if(*b < 0) { p1 = PA + ~*b; x |= 1; } - else { p1 = PA + *b; } - } else if(r < 0) { - if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; } - *a-- = *c, *c-- = *a; - if(c < first) { - while(buf < b) { *a-- = *b, *b-- = *a; } - *a = *b, *b = t; - break; - } - if(*c < 0) { p2 = PA + ~*c; x |= 2; } - else { p2 = PA + *c; } - } else { - if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; } - *a-- = ~*b; - if(b <= buf) { *buf = t; break; } - *b-- = *a; - if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; } - *a-- = *c, *c-- = *a; - if(c < first) { - while(buf < b) { *a-- = *b, *b-- = *a; } - *a = *b, *b = t; - break; - } - if(*b < 0) { p1 = PA + ~*b; x |= 1; } - else { p1 = PA + *b; } - if(*c < 0) { p2 = PA + ~*c; x |= 2; } - else { p2 = PA + *c; } - } - } -} - -/* D&C based merge. */ -static -void -ss_swapmerge(const sauchar_t *T, const saidx_t *PA, - saidx_t *first, saidx_t *middle, saidx_t *last, - saidx_t *buf, saidx_t bufsize, saidx_t depth) { -#define STACK_SIZE SS_SMERGE_STACKSIZE -#define GETIDX(a) ((0 <= (a)) ? (a) : (~(a))) -#define MERGE_CHECK(a, b, c)\ - do {\ - if(((c) & 1) ||\ - (((c) & 2) && (ss_compare(T, PA + GETIDX(*((a) - 1)), PA + *(a), depth) == 0))) {\ - *(a) = ~*(a);\ - }\ - if(((c) & 4) && ((ss_compare(T, PA + GETIDX(*((b) - 1)), PA + *(b), depth) == 0))) {\ - *(b) = ~*(b);\ - }\ - } while(0) - struct { saidx_t *a, *b, *c; saint_t d; } stack[STACK_SIZE]; - saidx_t *l, *r, *lm, *rm; - saidx_t m, len, half; - saint_t ssize; - saint_t check, next; - - for(check = 0, ssize = 0;;) { - if((last - middle) <= bufsize) { - if((first < middle) && (middle < last)) { - ss_mergebackward(T, PA, first, middle, last, buf, depth); - } - MERGE_CHECK(first, last, check); - STACK_POP(first, middle, last, check); - continue; - } - - if((middle - first) <= bufsize) { - if(first < middle) { - ss_mergeforward(T, PA, first, middle, last, buf, depth); - } - MERGE_CHECK(first, last, check); - STACK_POP(first, middle, last, check); - continue; - } - - for(m = 0, len = MIN(middle - first, last - middle), half = len >> 1; - 0 < len; - len = half, half >>= 1) { - if(ss_compare(T, PA + GETIDX(*(middle + m + half)), - PA + GETIDX(*(middle - m - half - 1)), depth) < 0) { - m += half + 1; - half -= (len & 1) ^ 1; - } - } - - if(0 < m) { - lm = middle - m, rm = middle + m; - ss_blockswap(lm, middle, m); - l = r = middle, next = 0; - if(rm < last) { - if(*rm < 0) { - *rm = ~*rm; - if(first < lm) { for(; *--l < 0;) { } next |= 4; } - next |= 1; - } else if(first < lm) { - for(; *r < 0; ++r) { } - next |= 2; - } - } - - if((l - first) <= (last - r)) { - STACK_PUSH(r, rm, last, (next & 3) | (check & 4)); - middle = lm, last = l, check = (check & 3) | (next & 4); - } else { - if((next & 2) && (r == middle)) { next ^= 6; } - STACK_PUSH(first, lm, l, (check & 3) | (next & 4)); - first = r, middle = rm, check = (next & 3) | (check & 4); - } - } else { - if(ss_compare(T, PA + GETIDX(*(middle - 1)), PA + *middle, depth) == 0) { - *middle = ~*middle; - } - MERGE_CHECK(first, last, check); - STACK_POP(first, middle, last, check); - } - } -#undef STACK_SIZE -} - -#endif /* SS_BLOCKSIZE != 0 */ - - -/*---------------------------------------------------------------------------*/ - -/*- Function -*/ - -/* Substring sort */ -void -sssort(const sauchar_t *T, const saidx_t *PA, - saidx_t *first, saidx_t *last, - saidx_t *buf, saidx_t bufsize, - saidx_t depth, saidx_t n, saint_t lastsuffix) { - saidx_t *a; -#if SS_BLOCKSIZE != 0 - saidx_t *b, *middle, *curbuf; - saidx_t j, k, curbufsize, limit; -#endif - saidx_t i; - - if(lastsuffix != 0) { ++first; } - -#if SS_BLOCKSIZE == 0 - ss_mintrosort(T, PA, first, last, depth); -#else - if((bufsize < SS_BLOCKSIZE) && - (bufsize < (last - first)) && - (bufsize < (limit = ss_isqrt(last - first)))) { - if(SS_BLOCKSIZE < limit) { limit = SS_BLOCKSIZE; } - buf = middle = last - limit, bufsize = limit; - } else { - middle = last, limit = 0; - } - for(a = first, i = 0; SS_BLOCKSIZE < (middle - a); a += SS_BLOCKSIZE, ++i) { -#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE - ss_mintrosort(T, PA, a, a + SS_BLOCKSIZE, depth); -#elif 1 < SS_BLOCKSIZE - ss_insertionsort(T, PA, a, a + SS_BLOCKSIZE, depth); -#endif - curbufsize = last - (a + SS_BLOCKSIZE); - curbuf = a + SS_BLOCKSIZE; - if(curbufsize <= bufsize) { curbufsize = bufsize, curbuf = buf; } - for(b = a, k = SS_BLOCKSIZE, j = i; j & 1; b -= k, k <<= 1, j >>= 1) { - ss_swapmerge(T, PA, b - k, b, b + k, curbuf, curbufsize, depth); - } - } -#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE - ss_mintrosort(T, PA, a, middle, depth); -#elif 1 < SS_BLOCKSIZE - ss_insertionsort(T, PA, a, middle, depth); -#endif - for(k = SS_BLOCKSIZE; i != 0; k <<= 1, i >>= 1) { - if(i & 1) { - ss_swapmerge(T, PA, a - k, a, middle, buf, bufsize, depth); - a -= k; - } - } - if(limit != 0) { -#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE - ss_mintrosort(T, PA, middle, last, depth); -#elif 1 < SS_BLOCKSIZE - ss_insertionsort(T, PA, middle, last, depth); -#endif - ss_inplacemerge(T, PA, first, middle, last, depth); - } -#endif - - if(lastsuffix != 0) { - /* Insert last type B* suffix. */ - saidx_t PAi[2]; PAi[0] = PA[*(first - 1)], PAi[1] = n - 2; - for(a = first, i = *(first - 1); - (a < last) && ((*a < 0) || (0 < ss_compare(T, &(PAi[0]), PA + *a, depth))); - ++a) { - *(a - 1) = *a; - } - *(a - 1) = i; - } -} diff --git a/dictBuilder/trsort.c b/dictBuilder/trsort.c deleted file mode 100644 index 9e21e68ec..000000000 --- a/dictBuilder/trsort.c +++ /dev/null @@ -1,615 +0,0 @@ -/* - * trsort.c for libdivsufsort - * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -/*- Compiler specifics -*/ -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wshorten-64-to-32" -#endif - -#if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) -/* inline is defined */ -#elif defined(_MSC_VER) -# define inline __inline -#else -# define inline /* disable inline */ -#endif - -#ifdef _MSC_VER /* Visual Studio */ -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -# define FORCE_INLINE static __forceinline -#else -# if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif -# else -# define FORCE_INLINE static -# endif /* __STDC_VERSION__ */ -#endif - -/*- Dependencies -*/ -#include "divsufsort_private.h" - - -/*- Private Functions -*/ - -static const saint_t lg_table[256]= { - -1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 -}; - -static INLINE -saint_t -tr_ilg(saidx_t n) { -#if defined(BUILD_DIVSUFSORT64) - return (n >> 32) ? - ((n >> 48) ? - ((n >> 56) ? - 56 + lg_table[(n >> 56) & 0xff] : - 48 + lg_table[(n >> 48) & 0xff]) : - ((n >> 40) ? - 40 + lg_table[(n >> 40) & 0xff] : - 32 + lg_table[(n >> 32) & 0xff])) : - ((n & 0xffff0000) ? - ((n & 0xff000000) ? - 24 + lg_table[(n >> 24) & 0xff] : - 16 + lg_table[(n >> 16) & 0xff]) : - ((n & 0x0000ff00) ? - 8 + lg_table[(n >> 8) & 0xff] : - 0 + lg_table[(n >> 0) & 0xff])); -#else - return (n & 0xffff0000) ? - ((n & 0xff000000) ? - 24 + lg_table[(n >> 24) & 0xff] : - 16 + lg_table[(n >> 16) & 0xff]) : - ((n & 0x0000ff00) ? - 8 + lg_table[(n >> 8) & 0xff] : - 0 + lg_table[(n >> 0) & 0xff]); -#endif -} - - -/*---------------------------------------------------------------------------*/ - -/* Simple insertionsort for small size groups. */ -static -void -tr_insertionsort(const saidx_t *ISAd, saidx_t *first, saidx_t *last) { - saidx_t *a, *b; - saidx_t t, r; - - for(a = first + 1; a < last; ++a) { - for(t = *a, b = a - 1; 0 > (r = ISAd[t] - ISAd[*b]);) { - do { *(b + 1) = *b; } while((first <= --b) && (*b < 0)); - if(b < first) { break; } - } - if(r == 0) { *b = ~*b; } - *(b + 1) = t; - } -} - - -/*---------------------------------------------------------------------------*/ - -static INLINE -void -tr_fixdown(const saidx_t *ISAd, saidx_t *SA, saidx_t i, saidx_t size) { - saidx_t j, k; - saidx_t v; - saidx_t c, d, e; - - for(v = SA[i], c = ISAd[v]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) { - d = ISAd[SA[k = j++]]; - if(d < (e = ISAd[SA[j]])) { k = j; d = e; } - if(d <= c) { break; } - } - SA[i] = v; -} - -/* Simple top-down heapsort. */ -static -void -tr_heapsort(const saidx_t *ISAd, saidx_t *SA, saidx_t size) { - saidx_t i, m; - saidx_t t; - - m = size; - if((size % 2) == 0) { - m--; - if(ISAd[SA[m / 2]] < ISAd[SA[m]]) { SWAP(SA[m], SA[m / 2]); } - } - - for(i = m / 2 - 1; 0 <= i; --i) { tr_fixdown(ISAd, SA, i, m); } - if((size % 2) == 0) { SWAP(SA[0], SA[m]); tr_fixdown(ISAd, SA, 0, m); } - for(i = m - 1; 0 < i; --i) { - t = SA[0], SA[0] = SA[i]; - tr_fixdown(ISAd, SA, 0, i); - SA[i] = t; - } -} - - -/*---------------------------------------------------------------------------*/ - -/* Returns the median of three elements. */ -static INLINE -saidx_t * -tr_median3(const saidx_t *ISAd, saidx_t *v1, saidx_t *v2, saidx_t *v3) { - saidx_t *t; - if(ISAd[*v1] > ISAd[*v2]) { SWAP(v1, v2); } - if(ISAd[*v2] > ISAd[*v3]) { - if(ISAd[*v1] > ISAd[*v3]) { return v1; } - else { return v3; } - } - return v2; -} - -/* Returns the median of five elements. */ -static INLINE -saidx_t * -tr_median5(const saidx_t *ISAd, - saidx_t *v1, saidx_t *v2, saidx_t *v3, saidx_t *v4, saidx_t *v5) { - saidx_t *t; - if(ISAd[*v2] > ISAd[*v3]) { SWAP(v2, v3); } - if(ISAd[*v4] > ISAd[*v5]) { SWAP(v4, v5); } - if(ISAd[*v2] > ISAd[*v4]) { SWAP(v2, v4); SWAP(v3, v5); } - if(ISAd[*v1] > ISAd[*v3]) { SWAP(v1, v3); } - if(ISAd[*v1] > ISAd[*v4]) { SWAP(v1, v4); SWAP(v3, v5); } - if(ISAd[*v3] > ISAd[*v4]) { return v4; } - return v3; -} - -/* Returns the pivot element. */ -static INLINE -saidx_t * -tr_pivot(const saidx_t *ISAd, saidx_t *first, saidx_t *last) { - saidx_t *middle; - saidx_t t; - - t = last - first; - middle = first + t / 2; - - if(t <= 512) { - if(t <= 32) { - return tr_median3(ISAd, first, middle, last - 1); - } else { - t >>= 2; - return tr_median5(ISAd, first, first + t, middle, last - 1 - t, last - 1); - } - } - t >>= 3; - first = tr_median3(ISAd, first, first + t, first + (t << 1)); - middle = tr_median3(ISAd, middle - t, middle, middle + t); - last = tr_median3(ISAd, last - 1 - (t << 1), last - 1 - t, last - 1); - return tr_median3(ISAd, first, middle, last); -} - - -/*---------------------------------------------------------------------------*/ - -typedef struct _trbudget_t trbudget_t; -struct _trbudget_t { - saidx_t chance; - saidx_t remain; - saidx_t incval; - saidx_t count; -}; - -static INLINE -void -trbudget_init(trbudget_t *budget, saidx_t chance, saidx_t incval) { - budget->chance = chance; - budget->remain = budget->incval = incval; -} - -static INLINE -saint_t -trbudget_check(trbudget_t *budget, saidx_t size) { - if(size <= budget->remain) { budget->remain -= size; return 1; } - if(budget->chance == 0) { budget->count += size; return 0; } - budget->remain += budget->incval - size; - budget->chance -= 1; - return 1; -} - - -/*---------------------------------------------------------------------------*/ - -static INLINE -void -tr_partition(const saidx_t *ISAd, - saidx_t *first, saidx_t *middle, saidx_t *last, - saidx_t **pa, saidx_t **pb, saidx_t v) { - saidx_t *a, *b, *c, *d, *e, *f; - saidx_t t, s; - saidx_t x = 0; - - for(b = middle - 1; (++b < last) && ((x = ISAd[*b]) == v);) { } - if(((a = b) < last) && (x < v)) { - for(; (++b < last) && ((x = ISAd[*b]) <= v);) { - if(x == v) { SWAP(*b, *a); ++a; } - } - } - for(c = last; (b < --c) && ((x = ISAd[*c]) == v);) { } - if((b < (d = c)) && (x > v)) { - for(; (b < --c) && ((x = ISAd[*c]) >= v);) { - if(x == v) { SWAP(*c, *d); --d; } - } - } - for(; b < c;) { - SWAP(*b, *c); - for(; (++b < c) && ((x = ISAd[*b]) <= v);) { - if(x == v) { SWAP(*b, *a); ++a; } - } - for(; (b < --c) && ((x = ISAd[*c]) >= v);) { - if(x == v) { SWAP(*c, *d); --d; } - } - } - - if(a <= d) { - c = b - 1; - if((s = a - first) > (t = b - a)) { s = t; } - for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } - if((s = d - c) > (t = last - d - 1)) { s = t; } - for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } - first += (b - a), last -= (d - c); - } - *pa = first, *pb = last; -} - -static -void -tr_copy(saidx_t *ISA, const saidx_t *SA, - saidx_t *first, saidx_t *a, saidx_t *b, saidx_t *last, - saidx_t depth) { - /* sort suffixes of middle partition - by using sorted order of suffixes of left and right partition. */ - saidx_t *c, *d, *e; - saidx_t s, v; - - v = b - SA - 1; - for(c = first, d = a - 1; c <= d; ++c) { - if((0 <= (s = *c - depth)) && (ISA[s] == v)) { - *++d = s; - ISA[s] = d - SA; - } - } - for(c = last - 1, e = d + 1, d = b; e < d; --c) { - if((0 <= (s = *c - depth)) && (ISA[s] == v)) { - *--d = s; - ISA[s] = d - SA; - } - } -} - -static -void -tr_partialcopy(saidx_t *ISA, const saidx_t *SA, - saidx_t *first, saidx_t *a, saidx_t *b, saidx_t *last, - saidx_t depth) { - saidx_t *c, *d, *e; - saidx_t s, v; - saidx_t rank, lastrank, newrank = -1; - - v = b - SA - 1; - lastrank = -1; - for(c = first, d = a - 1; c <= d; ++c) { - if((0 <= (s = *c - depth)) && (ISA[s] == v)) { - *++d = s; - rank = ISA[s + depth]; - if(lastrank != rank) { lastrank = rank; newrank = d - SA; } - ISA[s] = newrank; - } - } - - lastrank = -1; - for(e = d; first <= e; --e) { - rank = ISA[*e]; - if(lastrank != rank) { lastrank = rank; newrank = e - SA; } - if(newrank != rank) { ISA[*e] = newrank; } - } - - lastrank = -1; - for(c = last - 1, e = d + 1, d = b; e < d; --c) { - if((0 <= (s = *c - depth)) && (ISA[s] == v)) { - *--d = s; - rank = ISA[s + depth]; - if(lastrank != rank) { lastrank = rank; newrank = d - SA; } - ISA[s] = newrank; - } - } -} - -static -void -tr_introsort(saidx_t *ISA, const saidx_t *ISAd, - saidx_t *SA, saidx_t *first, saidx_t *last, - trbudget_t *budget) { -#define STACK_SIZE TR_STACKSIZE - struct { const saidx_t *a; saidx_t *b, *c; saint_t d, e; }stack[STACK_SIZE]; - saidx_t *a, *b, *c; - saidx_t t; - saidx_t v, x = 0; - saidx_t incr = ISAd - ISA; - saint_t limit, next; - saint_t ssize, trlink = -1; - - for(ssize = 0, limit = tr_ilg(last - first);;) { - - if(limit < 0) { - if(limit == -1) { - /* tandem repeat partition */ - tr_partition(ISAd - incr, first, first, last, &a, &b, last - SA - 1); - - /* update ranks */ - if(a < last) { - for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; } - } - if(b < last) { - for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; } - } - - /* push */ - if(1 < (b - a)) { - STACK_PUSH5(NULL, a, b, 0, 0); - STACK_PUSH5(ISAd - incr, first, last, -2, trlink); - trlink = ssize - 2; - } - if((a - first) <= (last - b)) { - if(1 < (a - first)) { - STACK_PUSH5(ISAd, b, last, tr_ilg(last - b), trlink); - last = a, limit = tr_ilg(a - first); - } else if(1 < (last - b)) { - first = b, limit = tr_ilg(last - b); - } else { - STACK_POP5(ISAd, first, last, limit, trlink); - } - } else { - if(1 < (last - b)) { - STACK_PUSH5(ISAd, first, a, tr_ilg(a - first), trlink); - first = b, limit = tr_ilg(last - b); - } else if(1 < (a - first)) { - last = a, limit = tr_ilg(a - first); - } else { - STACK_POP5(ISAd, first, last, limit, trlink); - } - } - } else if(limit == -2) { - /* tandem repeat copy */ - a = stack[--ssize].b, b = stack[ssize].c; - if(stack[ssize].d == 0) { - tr_copy(ISA, SA, first, a, b, last, ISAd - ISA); - } else { - if(0 <= trlink) { stack[trlink].d = -1; } - tr_partialcopy(ISA, SA, first, a, b, last, ISAd - ISA); - } - STACK_POP5(ISAd, first, last, limit, trlink); - } else { - /* sorted partition */ - if(0 <= *first) { - a = first; - do { ISA[*a] = a - SA; } while((++a < last) && (0 <= *a)); - first = a; - } - if(first < last) { - a = first; do { *a = ~*a; } while(*++a < 0); - next = (ISA[*a] != ISAd[*a]) ? tr_ilg(a - first + 1) : -1; - if(++a < last) { for(b = first, v = a - SA - 1; b < a; ++b) { ISA[*b] = v; } } - - /* push */ - if(trbudget_check(budget, a - first)) { - if((a - first) <= (last - a)) { - STACK_PUSH5(ISAd, a, last, -3, trlink); - ISAd += incr, last = a, limit = next; - } else { - if(1 < (last - a)) { - STACK_PUSH5(ISAd + incr, first, a, next, trlink); - first = a, limit = -3; - } else { - ISAd += incr, last = a, limit = next; - } - } - } else { - if(0 <= trlink) { stack[trlink].d = -1; } - if(1 < (last - a)) { - first = a, limit = -3; - } else { - STACK_POP5(ISAd, first, last, limit, trlink); - } - } - } else { - STACK_POP5(ISAd, first, last, limit, trlink); - } - } - continue; - } - - if((last - first) <= TR_INSERTIONSORT_THRESHOLD) { - tr_insertionsort(ISAd, first, last); - limit = -3; - continue; - } - - if(limit-- == 0) { - tr_heapsort(ISAd, first, last - first); - for(a = last - 1; first < a; a = b) { - for(x = ISAd[*a], b = a - 1; (first <= b) && (ISAd[*b] == x); --b) { *b = ~*b; } - } - limit = -3; - continue; - } - - /* choose pivot */ - a = tr_pivot(ISAd, first, last); - SWAP(*first, *a); - v = ISAd[*first]; - - /* partition */ - tr_partition(ISAd, first, first + 1, last, &a, &b, v); - if((last - first) != (b - a)) { - next = (ISA[*a] != v) ? tr_ilg(b - a) : -1; - - /* update ranks */ - for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; } - if(b < last) { for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; } } - - /* push */ - if((1 < (b - a)) && (trbudget_check(budget, b - a))) { - if((a - first) <= (last - b)) { - if((last - b) <= (b - a)) { - if(1 < (a - first)) { - STACK_PUSH5(ISAd + incr, a, b, next, trlink); - STACK_PUSH5(ISAd, b, last, limit, trlink); - last = a; - } else if(1 < (last - b)) { - STACK_PUSH5(ISAd + incr, a, b, next, trlink); - first = b; - } else { - ISAd += incr, first = a, last = b, limit = next; - } - } else if((a - first) <= (b - a)) { - if(1 < (a - first)) { - STACK_PUSH5(ISAd, b, last, limit, trlink); - STACK_PUSH5(ISAd + incr, a, b, next, trlink); - last = a; - } else { - STACK_PUSH5(ISAd, b, last, limit, trlink); - ISAd += incr, first = a, last = b, limit = next; - } - } else { - STACK_PUSH5(ISAd, b, last, limit, trlink); - STACK_PUSH5(ISAd, first, a, limit, trlink); - ISAd += incr, first = a, last = b, limit = next; - } - } else { - if((a - first) <= (b - a)) { - if(1 < (last - b)) { - STACK_PUSH5(ISAd + incr, a, b, next, trlink); - STACK_PUSH5(ISAd, first, a, limit, trlink); - first = b; - } else if(1 < (a - first)) { - STACK_PUSH5(ISAd + incr, a, b, next, trlink); - last = a; - } else { - ISAd += incr, first = a, last = b, limit = next; - } - } else if((last - b) <= (b - a)) { - if(1 < (last - b)) { - STACK_PUSH5(ISAd, first, a, limit, trlink); - STACK_PUSH5(ISAd + incr, a, b, next, trlink); - first = b; - } else { - STACK_PUSH5(ISAd, first, a, limit, trlink); - ISAd += incr, first = a, last = b, limit = next; - } - } else { - STACK_PUSH5(ISAd, first, a, limit, trlink); - STACK_PUSH5(ISAd, b, last, limit, trlink); - ISAd += incr, first = a, last = b, limit = next; - } - } - } else { - if((1 < (b - a)) && (0 <= trlink)) { stack[trlink].d = -1; } - if((a - first) <= (last - b)) { - if(1 < (a - first)) { - STACK_PUSH5(ISAd, b, last, limit, trlink); - last = a; - } else if(1 < (last - b)) { - first = b; - } else { - STACK_POP5(ISAd, first, last, limit, trlink); - } - } else { - if(1 < (last - b)) { - STACK_PUSH5(ISAd, first, a, limit, trlink); - first = b; - } else if(1 < (a - first)) { - last = a; - } else { - STACK_POP5(ISAd, first, last, limit, trlink); - } - } - } - } else { - if(trbudget_check(budget, last - first)) { - limit = tr_ilg(last - first), ISAd += incr; - } else { - if(0 <= trlink) { stack[trlink].d = -1; } - STACK_POP5(ISAd, first, last, limit, trlink); - } - } - } -#undef STACK_SIZE -} - - - -/*---------------------------------------------------------------------------*/ - -/*- Function -*/ - -/* Tandem repeat sort */ -void -trsort(saidx_t *ISA, saidx_t *SA, saidx_t n, saidx_t depth) { - saidx_t *ISAd; - saidx_t *first, *last; - trbudget_t budget; - saidx_t t, skip, unsorted; - - trbudget_init(&budget, tr_ilg(n) * 2 / 3, n); -/* trbudget_init(&budget, tr_ilg(n) * 3 / 4, n); */ - for(ISAd = ISA + depth; -n < *SA; ISAd += ISAd - ISA) { - first = SA; - skip = 0; - unsorted = 0; - do { - if((t = *first) < 0) { first -= t; skip += t; } - else { - if(skip != 0) { *(first + skip) = skip; skip = 0; } - last = SA + ISA[t] + 1; - if(1 < (last - first)) { - budget.count = 0; - tr_introsort(ISA, ISAd, SA, first, last, &budget); - if(budget.count != 0) { unsorted += budget.count; } - else { skip = first - last; } - } else if((last - first) == 1) { - skip = -1; - } - first = last; - } - } while(first < (SA + n)); - if(skip != 0) { *(first + skip) = skip; } - if(unsorted == 0) { break; } - } -} diff --git a/dictBuilder/utils.c b/dictBuilder/utils.c deleted file mode 100644 index 90fb23efa..000000000 --- a/dictBuilder/utils.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * utils.c for libdivsufsort - * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "divsufsort_private.h" - - -/*- Private Function -*/ - -/* Binary search for inverse bwt. */ -static -saidx_t -binarysearch_lower(const saidx_t *A, saidx_t size, saidx_t value) { - saidx_t half, i; - for(i = 0, half = size >> 1; - 0 < size; - size = half, half >>= 1) { - if(A[i + half] < value) { - i += half + 1; - half -= (size & 1) ^ 1; - } - } - return i; -} - - -/*- Functions -*/ - -/* Burrows-Wheeler transform. */ -saint_t -bw_transform(const sauchar_t *T, sauchar_t *U, saidx_t *SA, - saidx_t n, saidx_t *idx) { - saidx_t *A, i, j, p, t; - saint_t c; - - /* Check arguments. */ - if((T == NULL) || (U == NULL) || (n < 0) || (idx == NULL)) { return -1; } - if(n <= 1) { - if(n == 1) { U[0] = T[0]; } - *idx = n; - return 0; - } - - if((A = SA) == NULL) { - i = divbwt(T, U, NULL, n); - if(0 <= i) { *idx = i; i = 0; } - return (saint_t)i; - } - - /* BW transform. */ - if(T == U) { - t = n; - for(i = 0, j = 0; i < n; ++i) { - p = t - 1; - t = A[i]; - if(0 <= p) { - c = T[j]; - U[j] = (j <= p) ? T[p] : (sauchar_t)A[p]; - A[j] = c; - j++; - } else { - *idx = i; - } - } - p = t - 1; - if(0 <= p) { - c = T[j]; - U[j] = (j <= p) ? T[p] : (sauchar_t)A[p]; - A[j] = c; - } else { - *idx = i; - } - } else { - U[0] = T[n - 1]; - for(i = 0; A[i] != 0; ++i) { U[i + 1] = T[A[i] - 1]; } - *idx = i + 1; - for(++i; i < n; ++i) { U[i] = T[A[i] - 1]; } - } - - if(SA == NULL) { - /* Deallocate memory. */ - free(A); - } - - return 0; -} - -/* Inverse Burrows-Wheeler transform. */ -saint_t -inverse_bw_transform(const sauchar_t *T, sauchar_t *U, saidx_t *A, - saidx_t n, saidx_t idx) { - saidx_t C[ALPHABET_SIZE]; - sauchar_t D[ALPHABET_SIZE]; - saidx_t *B; - saidx_t i, p; - saint_t c, d; - - /* Check arguments. */ - if((T == NULL) || (U == NULL) || (n < 0) || (idx < 0) || - (n < idx) || ((0 < n) && (idx == 0))) { - return -1; - } - if(n <= 1) { return 0; } - - if((B = A) == NULL) { - /* Allocate n*sizeof(saidx_t) bytes of memory. */ - if((B = (saidx_t *)malloc((size_t)n * sizeof(saidx_t))) == NULL) { return -2; } - } - - /* Inverse BW transform. */ - for(c = 0; c < ALPHABET_SIZE; ++c) { C[c] = 0; } - for(i = 0; i < n; ++i) { ++C[T[i]]; } - for(c = 0, d = 0, i = 0; c < ALPHABET_SIZE; ++c) { - p = C[c]; - if(0 < p) { - C[c] = i; - D[d++] = (sauchar_t)c; - i += p; - } - } - for(i = 0; i < idx; ++i) { B[C[T[i]]++] = i; } - for( ; i < n; ++i) { B[C[T[i]]++] = i + 1; } - for(c = 0; c < d; ++c) { C[c] = C[D[c]]; } - for(i = 0, p = idx; i < n; ++i) { - U[i] = D[binarysearch_lower(C, d, p)]; - p = B[p - 1]; - } - - if(A == NULL) { - /* Deallocate memory. */ - free(B); - } - - return 0; -} - -/* Checks the suffix array SA of the string T. */ -saint_t -sufcheck(const sauchar_t *T, const saidx_t *SA, - saidx_t n, saint_t verbose) { - saidx_t C[ALPHABET_SIZE]; - saidx_t i, p, q, t; - saint_t c; - - if(verbose) { fprintf(stderr, "sufcheck: "); } - - /* Check arguments. */ - if((T == NULL) || (SA == NULL) || (n < 0)) { - if(verbose) { fprintf(stderr, "Invalid arguments.\n"); } - return -1; - } - if(n == 0) { - if(verbose) { fprintf(stderr, "Done.\n"); } - return 0; - } - - /* check range: [0..n-1] */ - for(i = 0; i < n; ++i) { - if((SA[i] < 0) || (n <= SA[i])) { - if(verbose) { - fprintf(stderr, "Out of the range [0,%" PRIdSAIDX_T "].\n" - " SA[%" PRIdSAIDX_T "]=%" PRIdSAIDX_T "\n", - n - 1, i, SA[i]); - } - return -2; - } - } - - /* check first characters. */ - for(i = 1; i < n; ++i) { - if(T[SA[i - 1]] > T[SA[i]]) { - if(verbose) { - fprintf(stderr, "Suffixes in wrong order.\n" - " T[SA[%" PRIdSAIDX_T "]=%" PRIdSAIDX_T "]=%d" - " > T[SA[%" PRIdSAIDX_T "]=%" PRIdSAIDX_T "]=%d\n", - i - 1, SA[i - 1], T[SA[i - 1]], i, SA[i], T[SA[i]]); - } - return -3; - } - } - - /* check suffixes. */ - for(i = 0; i < ALPHABET_SIZE; ++i) { C[i] = 0; } - for(i = 0; i < n; ++i) { ++C[T[i]]; } - for(i = 0, p = 0; i < ALPHABET_SIZE; ++i) { - t = C[i]; - C[i] = p; - p += t; - } - - q = C[T[n - 1]]; - C[T[n - 1]] += 1; - for(i = 0; i < n; ++i) { - p = SA[i]; - if(0 < p) { - c = T[--p]; - t = C[c]; - } else { - c = T[p = n - 1]; - t = q; - } - if((t < 0) || (p != SA[t])) { - if(verbose) { - fprintf(stderr, "Suffix in wrong position.\n" - " SA[%" PRIdSAIDX_T "]=%" PRIdSAIDX_T " or\n" - " SA[%" PRIdSAIDX_T "]=%" PRIdSAIDX_T "\n", - t, (0 <= t) ? SA[t] : -1, i, SA[i]); - } - return -4; - } - if(t != q) { - ++C[c]; - if((n <= C[c]) || (T[SA[C[c]]] != c)) { C[c] = -1; } - } - } - - if(1 <= verbose) { fprintf(stderr, "Done.\n"); } - return 0; -} - - -static -int -_compare(const sauchar_t *T, saidx_t Tsize, - const sauchar_t *P, saidx_t Psize, - saidx_t suf, saidx_t *match) { - saidx_t i, j; - saint_t r; - for(i = suf + *match, j = *match, r = 0; - (i < Tsize) && (j < Psize) && ((r = T[i] - P[j]) == 0); ++i, ++j) { } - *match = j; - return (r == 0) ? -(j != Psize) : r; -} - -/* Search for the pattern P in the string T. */ -saidx_t -sa_search(const sauchar_t *T, saidx_t Tsize, - const sauchar_t *P, saidx_t Psize, - const saidx_t *SA, saidx_t SAsize, - saidx_t *idx) { - saidx_t size, lsize, rsize, half; - saidx_t match, lmatch, rmatch; - saidx_t llmatch, lrmatch, rlmatch, rrmatch; - saidx_t i, j, k; - saint_t r; - - if(idx != NULL) { *idx = -1; } - if((T == NULL) || (P == NULL) || (SA == NULL) || - (Tsize < 0) || (Psize < 0) || (SAsize < 0)) { return -1; } - if((Tsize == 0) || (SAsize == 0)) { return 0; } - if(Psize == 0) { if(idx != NULL) { *idx = 0; } return SAsize; } - - for(i = j = k = 0, lmatch = rmatch = 0, size = SAsize, half = size >> 1; - 0 < size; - size = half, half >>= 1) { - match = MIN(lmatch, rmatch); - r = _compare(T, Tsize, P, Psize, SA[i + half], &match); - if(r < 0) { - i += half + 1; - half -= (size & 1) ^ 1; - lmatch = match; - } else if(r > 0) { - rmatch = match; - } else { - lsize = half, j = i, rsize = size - half - 1, k = i + half + 1; - - /* left part */ - for(llmatch = lmatch, lrmatch = match, half = lsize >> 1; - 0 < lsize; - lsize = half, half >>= 1) { - lmatch = MIN(llmatch, lrmatch); - r = _compare(T, Tsize, P, Psize, SA[j + half], &lmatch); - if(r < 0) { - j += half + 1; - half -= (lsize & 1) ^ 1; - llmatch = lmatch; - } else { - lrmatch = lmatch; - } - } - - /* right part */ - for(rlmatch = match, rrmatch = rmatch, half = rsize >> 1; - 0 < rsize; - rsize = half, half >>= 1) { - rmatch = MIN(rlmatch, rrmatch); - r = _compare(T, Tsize, P, Psize, SA[k + half], &rmatch); - if(r <= 0) { - k += half + 1; - half -= (rsize & 1) ^ 1; - rlmatch = rmatch; - } else { - rrmatch = rmatch; - } - } - - break; - } - } - - if(idx != NULL) { *idx = (0 < (k - j)) ? j : i; } - return k - j; -} - -/* Search for the character c in the string T. */ -saidx_t -sa_simplesearch(const sauchar_t *T, saidx_t Tsize, - const saidx_t *SA, saidx_t SAsize, - saint_t c, saidx_t *idx) { - saidx_t size, lsize, rsize, half; - saidx_t i, j, k, p; - saint_t r; - - if(idx != NULL) { *idx = -1; } - if((T == NULL) || (SA == NULL) || (Tsize < 0) || (SAsize < 0)) { return -1; } - if((Tsize == 0) || (SAsize == 0)) { return 0; } - - for(i = j = k = 0, size = SAsize, half = size >> 1; - 0 < size; - size = half, half >>= 1) { - p = SA[i + half]; - r = (p < Tsize) ? T[p] - c : -1; - if(r < 0) { - i += half + 1; - half -= (size & 1) ^ 1; - } else if(r == 0) { - lsize = half, j = i, rsize = size - half - 1, k = i + half + 1; - - /* left part */ - for(half = lsize >> 1; - 0 < lsize; - lsize = half, half >>= 1) { - p = SA[j + half]; - r = (p < Tsize) ? T[p] - c : -1; - if(r < 0) { - j += half + 1; - half -= (lsize & 1) ^ 1; - } - } - - /* right part */ - for(half = rsize >> 1; - 0 < rsize; - rsize = half, half >>= 1) { - p = SA[k + half]; - r = (p < Tsize) ? T[p] - c : -1; - if(r <= 0) { - k += half + 1; - half -= (rsize & 1) ^ 1; - } - } - - break; - } - } - - if(idx != NULL) { *idx = (0 < (k - j)) ? j : i; } - return k - j; -} diff --git a/lib/Makefile b/lib/Makefile index e0ca0c626..5ce8c18b7 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,6 +1,6 @@ # ################################################################ # ZSTD library - Makefile -# Copyright (C) Yann Collet 2015 +# Copyright (C) Yann Collet 2015-2016 # All rights reserved. # # BSD license @@ -28,7 +28,6 @@ # # You can contact the author at : # - ZSTD homepage : http://www.zstd.net -# - ZSTD source repository : https://github.com/Cyan4973/zstd # ################################################################ # Version numbers @@ -52,7 +51,7 @@ FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(MOREFLAGS) LIBDIR ?= $(PREFIX)/lib INCLUDEDIR=$(PREFIX)/include -ZSTD_FILES := zstd_compress.c zstd_decompress.c fse.c huff0.c +ZSTD_FILES := zstd_compress.c zstd_decompress.c fse.c huff0.c dictBuilder.c divsufsort.c ZSTD_LEGACY:= legacy/zstd_v01.c legacy/zstd_v02.c legacy/zstd_v03.c legacy/zstd_v04.c ifeq ($(ZSTD_LEGACY_SUPPORT), 0) @@ -119,6 +118,7 @@ install: libzstd libzstd.pc @cp -a libzstd.pc $(DESTDIR)$(LIBDIR)/pkgconfig/ @install -m 644 libzstd.a $(DESTDIR)$(LIBDIR)/libzstd.a @install -m 644 zstd.h $(DESTDIR)$(INCLUDEDIR)/zstd.h + @install -m 644 zstd.h $(DESTDIR)$(INCLUDEDIR)/zstd_buffered.h @echo zstd static and shared library installed uninstall: diff --git a/dictBuilder/dictBuilder.c b/lib/dictBuilder.c similarity index 72% rename from dictBuilder/dictBuilder.c rename to lib/dictBuilder.c index d8b2bdb30..ede3b3d2a 100644 --- a/dictBuilder/dictBuilder.c +++ b/lib/dictBuilder.c @@ -1,28 +1,37 @@ /* - dictBuilder - dictionary builder for LZ algorithms + dictBuilder - dictionary builder for zstd Copyright (C) Yann Collet 2016 - GPL v2 License + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - zstd source repository : https://github.com/Cyan4973/zstd + - Zstd source repository : https://www.zstd.net */ -/* ************************************** +/*-************************************** * Compiler Options ****************************************/ /* Disable some Visual warning messages */ @@ -41,7 +50,7 @@ /*-************************************* -* Includes +* Dependencies ***************************************/ #include /* malloc, free */ #include /* memset */ @@ -53,9 +62,10 @@ #include "mem.h" /* read */ #include "error_private.h" #include "divsufsort.h" -#include "dictBuilder.h" -#include "zstd_compress.c" +#include "dictBuilder_static.h" +#include "fse.h" #include "huff0_static.h" +#include "zstd_internal.h" /*-************************************* @@ -94,16 +104,16 @@ static const size_t g_min_fast_dictContent = 192; #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) #define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } static unsigned g_displayLevel = 0; /* 0 : no display; 1: errors; 2: default; 4: full information */ -void DiB_setNotificationLevel(unsigned l) { g_displayLevel=l; } +void ZDICT_setNotificationLevel(unsigned l) { g_displayLevel=l; } #define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ - if (DiB_GetMilliSpan(g_time) > refreshRate) \ + if (ZDICT_GetMilliSpan(g_time) > refreshRate) \ { g_time = clock(); DISPLAY(__VA_ARGS__); \ if (g_displayLevel>=4) fflush(stdout); } } static const unsigned refreshRate = 300; static clock_t g_time = 0; -void DiB_printHex(U32 dlevel, const void* ptr, size_t length) +void ZDICT_printHex(U32 dlevel, const void* ptr, size_t length) { const BYTE* const b = (const BYTE*)ptr; size_t u; @@ -133,81 +143,25 @@ void DiB_printHex(U32 dlevel, const void* ptr, size_t length) } -/* ******************************************************** +/*-******************************************************** * Helper functions **********************************************************/ -unsigned DiB_versionNumber (void) { return DiB_VERSION_NUMBER; } - -static unsigned DiB_GetMilliSpan(clock_t nPrevious) +static unsigned ZDICT_GetMilliSpan(clock_t nPrevious) { clock_t nCurrent = clock(); unsigned nSpan = (unsigned)(((nCurrent - nPrevious) * 1000) / CLOCKS_PER_SEC); return nSpan; } -unsigned DiB_isError(size_t errorCode) { return ERR_isError(errorCode); } +unsigned ZDICT_isError(size_t errorCode) { return ERR_isError(errorCode); } -const char* DiB_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); } - - -/* ******************************************************** -* File related operations -**********************************************************/ -static unsigned long long DiB_getFileSize(const char* infilename) -{ - int r; -#if defined(_MSC_VER) - struct _stat64 statbuf; - r = _stat64(infilename, &statbuf); -#else - struct stat statbuf; - r = stat(infilename, &statbuf); -#endif - if (r || !S_ISREG(statbuf.st_mode)) return 0; /* No good... */ - return (unsigned long long)statbuf.st_size; -} - - -static unsigned long long DiB_getTotalFileSize(const char** fileNamesTable, unsigned nbFiles) -{ - unsigned long long total = 0; - unsigned n; - for (n=0; n bufferSize-pos) fileSize = 0; /* stop there, not enough memory to load all files */ - readSize = fread(buff+pos, 1, (size_t)fileSize, f); - if (readSize != (size_t)fileSize) EXM_THROW(11, "could not read %s", fileNamesTable[n]); - pos += readSize; - fileSizes[n] = (size_t)fileSize; - fclose(f); - } -} +const char* ZDICT_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); } /*-******************************************************** * Dictionary training functions **********************************************************/ -static size_t DiB_read_ARCH(const void* p) { size_t r; memcpy(&r, p, sizeof(r)); return r; } - -static unsigned DiB_NbCommonBytes (register size_t val) +static unsigned ZDICT_NbCommonBytes (register size_t val) { if (MEM_isLittleEndian()) { if (MEM_64bits()) { @@ -266,17 +220,17 @@ static unsigned DiB_NbCommonBytes (register size_t val) } -/*! DiB_count() : +/*! ZDICT_count() : Count the nb of common bytes between 2 pointers. Note : this function presumes end of buffer followed by noisy guard band. */ -static size_t DiB_count(const void* pIn, const void* pMatch) +static size_t ZDICT_count(const void* pIn, const void* pMatch) { const char* const pStart = (const char*)pIn; for (;;) { - size_t diff = DiB_read_ARCH(pMatch) ^ DiB_read_ARCH(pIn); + size_t diff = MEM_readST(pMatch) ^ MEM_readST(pIn); if (!diff) { pIn = (const char*)pIn+sizeof(size_t); pMatch = (const char*)pMatch+sizeof(size_t); continue; } - pIn = (const char*)pIn+DiB_NbCommonBytes(diff); + pIn = (const char*)pIn+ZDICT_NbCommonBytes(diff); return (size_t)((const char*)pIn - pStart); } } @@ -288,7 +242,7 @@ typedef struct { U32 savings; } dictItem; -void DiB_initDictItem(dictItem* d) +static void ZDICT_initDictItem(dictItem* d) { d->pos = 1; d->length = 0; @@ -298,9 +252,9 @@ void DiB_initDictItem(dictItem* d) #define LLIMIT 64 /* heuristic determined experimentally */ #define MINMATCHLENGTH 7 /* heuristic determined experimentally */ -static dictItem DiB_analyzePos( +static dictItem ZDICT_analyzePos( BYTE* doneMarks, - const saidx_t* suffix, U32 start, + const int* suffix, U32 start, const void* buffer, U32 minRatio) { U32 lengthList[LLIMIT] = {0}; @@ -334,12 +288,12 @@ static dictItem DiB_analyzePos( /* look forward */ do { end++; - length = DiB_count(b + pos, b + suffix[end]); + length = ZDICT_count(b + pos, b + suffix[end]); } while (length >=MINMATCHLENGTH); /* look backward */ do { - length = DiB_count(b + pos, b + *(suffix+start-1)); + length = ZDICT_count(b + pos, b + *(suffix+start-1)); if (length >=MINMATCHLENGTH) start--; } while(length >= MINMATCHLENGTH); @@ -400,14 +354,14 @@ static dictItem DiB_analyzePos( /* look forward */ do { end++; - length = DiB_count(b + pos, b + suffix[end]); + length = ZDICT_count(b + pos, b + suffix[end]); if (length >= LLIMIT) length = LLIMIT-1; lengthList[length]++; } while (length >=MINMATCHLENGTH); /* look backward */ do { - length = DiB_count(b + pos, b + suffix[start-1]); + length = ZDICT_count(b + pos, b + suffix[start-1]); if (length >= LLIMIT) length = LLIMIT-1; lengthList[length]++; if (length >=MINMATCHLENGTH) start--; @@ -453,7 +407,7 @@ static dictItem DiB_analyzePos( if (testedPos == pos) length = solution.length; else { - length = DiB_count(b+pos, b+testedPos); + length = ZDICT_count(b+pos, b+testedPos); if (length > solution.length) length = solution.length; } pEnd = (U32)(testedPos + length); @@ -465,11 +419,11 @@ static dictItem DiB_analyzePos( } -/*! DiB_checkMerge +/*! ZDICT_checkMerge check if dictItem can be merged, do it if possible @return : id of destination elt, 0 if not merged */ -static U32 DiB_checkMerge(dictItem* table, dictItem elt, U32 eltNbToSkip) +static U32 ZDICT_checkMerge(dictItem* table, dictItem elt, U32 eltNbToSkip) { const U32 tableSize = table->pos; const U32 max = elt.pos + (elt.length-1); @@ -513,7 +467,7 @@ static U32 DiB_checkMerge(dictItem* table, dictItem elt, U32 eltNbToSkip) } -static void DiB_removeDictItem(dictItem* table, U32 id) +static void ZDICT_removeDictItem(dictItem* table, U32 id) { /* convention : first element is nb of elts */ U32 max = table->pos; @@ -525,15 +479,15 @@ static void DiB_removeDictItem(dictItem* table, U32 id) } -static void DiB_insertDictItem(dictItem* table, U32 maxSize, dictItem elt) +static void ZDICT_insertDictItem(dictItem* table, U32 maxSize, dictItem elt) { /* merge if possible */ - U32 mergeId = DiB_checkMerge(table, elt, 0); + U32 mergeId = ZDICT_checkMerge(table, elt, 0); if (mergeId) { U32 newMerge = 1; while (newMerge) { - newMerge = DiB_checkMerge(table, table[mergeId], mergeId); - if (newMerge) DiB_removeDictItem(table, mergeId); + newMerge = ZDICT_checkMerge(table, table[mergeId], mergeId); + if (newMerge) ZDICT_removeDictItem(table, mergeId); mergeId = newMerge; } return; @@ -555,7 +509,7 @@ static void DiB_insertDictItem(dictItem* table, U32 maxSize, dictItem elt) } -static U32 DiB_dictSize(const dictItem* dictList) +static U32 ZDICT_dictSize(const dictItem* dictList) { U32 u, dictSize = 0; for (u=1; u> shiftRatio; - saint_t errorCode; + int divSuftSortResult; /* init */ DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */ if (!suffix0 || !reverseSuffix || !doneMarks || !filePos) - EXM_THROW(1, "not enough memory for DiB_trainBuffer"); + EXM_THROW(1, "not enough memory for ZDICT_trainBuffer"); if (minRatio < MINRATIO) minRatio = MINRATIO; memset(doneMarks, 0, bufferSize+16); /* sort */ DISPLAYLEVEL(2, "sorting %u files of total size %u MB ...\n", nbFiles, (U32)(bufferSize>>20)); - errorCode = divsufsort((const sauchar_t*)buffer, suffix, (saidx_t)bufferSize); - if (errorCode != 0) EXM_THROW(2, "sort failed"); - suffix[bufferSize] = (saidx_t)bufferSize; /* leads into noise */ - suffix0[0] = (saidx_t)bufferSize; /* leads into noise */ + divSuftSortResult = divsufsort((const unsigned char*)buffer, suffix, (int)bufferSize, 0); + if (divSuftSortResult != 0) EXM_THROW(2, "sort failed"); + suffix[bufferSize] = (int)bufferSize; /* leads into noise */ + suffix0[0] = (int)bufferSize; /* leads into noise */ { /* build reverse suffix sort */ size_t pos; @@ -608,9 +562,9 @@ static void DiB_trainBuffer(dictItem* dictList, U32 dictListSize, U32 cursor; for (cursor=0; cursor < bufferSize; ) { dictItem solution; if (doneMarks[cursor]) { cursor++; continue; } - solution = DiB_analyzePos(doneMarks, suffix, reverseSuffix[cursor], buffer, minRatio); + solution = ZDICT_analyzePos(doneMarks, suffix, reverseSuffix[cursor], buffer, minRatio); if (solution.length==0) { cursor++; continue; } - DiB_insertDictItem(dictList, dictListSize, solution); + ZDICT_insertDictItem(dictList, dictListSize, solution); cursor += solution.length; DISPLAYUPDATE(2, "\r%4.2f %% \r", (double)cursor / bufferSize * 100); } } @@ -633,26 +587,7 @@ static void DiB_trainBuffer(dictItem* dictList, U32 dictListSize, } -static size_t DiB_findMaxMem(unsigned long long requiredMem) -{ - size_t step = 8 MB; - void* testmem = NULL; - - requiredMem = (((requiredMem >> 23) + 1) << 23); - requiredMem += 2 * step; - if (requiredMem > maxMemory) requiredMem = maxMemory; - - while (!testmem) { - requiredMem -= step; - testmem = malloc((size_t)requiredMem); - } - - free(testmem); - return (size_t)(requiredMem - step); -} - - -static void DiB_fillNoise(void* buffer, size_t length) +static void ZDICT_fillNoise(void* buffer, size_t length) { unsigned acc = PRIME1; size_t p=0;; @@ -672,34 +607,36 @@ typedef struct } EStats_ress_t; -static void DiB_countEStats(EStats_ress_t esr, +static void ZDICT_countEStats(EStats_ress_t esr, U32* countLit, U32* offsetcodeCount, U32* matchlengthCount, U32* litlengthCount, const void* src, size_t srcSize) { const BYTE* bytePtr; const U32* u32Ptr; + seqStore_t seqStore; if (srcSize > BLOCKSIZE) srcSize = BLOCKSIZE; /* protection vs large samples */ ZSTD_copyCCtx(esr.zc, esr.ref); ZSTD_compressBlock(esr.zc, esr.workPlace, BLOCKSIZE, src, srcSize); + seqStore = ZSTD_copySeqStore(esr.zc); /* count stats */ - for(bytePtr = esr.zc->seqStore.litStart; bytePtr < esr.zc->seqStore.lit; bytePtr++) + for(bytePtr = seqStore.litStart; bytePtr < seqStore.lit; bytePtr++) countLit[*bytePtr]++; - for(u32Ptr = esr.zc->seqStore.offsetStart; u32Ptr < esr.zc->seqStore.offset; u32Ptr++) { + for(u32Ptr = seqStore.offsetStart; u32Ptr < seqStore.offset; u32Ptr++) { BYTE offcode = (BYTE)ZSTD_highbit(*u32Ptr) + 1; if (*u32Ptr==0) offcode=0; offsetcodeCount[offcode]++; } - for(bytePtr = esr.zc->seqStore.matchLengthStart; bytePtr < esr.zc->seqStore.matchLength; bytePtr++) + for(bytePtr = seqStore.matchLengthStart; bytePtr < seqStore.matchLength; bytePtr++) matchlengthCount[*bytePtr]++; - for(bytePtr = esr.zc->seqStore.litLengthStart; bytePtr < esr.zc->seqStore.litLength; bytePtr++) + for(bytePtr = seqStore.litLengthStart; bytePtr < seqStore.litLength; bytePtr++) litlengthCount[*bytePtr]++; } -#define OFFCODE_MAX 18 -static size_t DiB_analyzeEntropy(void* dstBuffer, size_t maxDstSize, +#define OFFCODE_MAX 18 /* only applicable to first block */ +static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, unsigned compressionLevel, const void* srcBuffer, const size_t* fileSizes, unsigned nbFiles, const void* dictBuffer, size_t dictBufferSize) @@ -734,7 +671,7 @@ static size_t DiB_analyzeEntropy(void* dstBuffer, size_t maxDstSize, /* collect stats on all files */ for (u=0; u1) { - DiB_trainBuffer(dictList, dictListSize, + /* build dictionary */ + if (selectivity>1) { /* selectivity == 1 => fast mode */ + ZDICT_trainBuffer(dictList, dictListSize, samplesBuffer, sBuffSize, sampleSizes, nbSamples, selectivity, (U32)targetDictSize); @@ -885,7 +805,7 @@ static size_t DiB_trainFromBuffer_internal( if (g_displayLevel>= 3) { const U32 nb = 25; U32 u; - U32 dictContentSize = DiB_dictSize(dictList); + U32 dictContentSize = ZDICT_dictSize(dictList); DISPLAYLEVEL(3, "\n %u segments found, of total size %u \n", dictList[0].pos, dictContentSize); DISPLAYLEVEL(3, "list %u best segments \n", nb); for (u=1; u<=nb; u++) { @@ -894,13 +814,13 @@ static size_t DiB_trainFromBuffer_internal( U32 d = MIN(40, l); DISPLAYLEVEL(3, "%3u:%3u bytes at pos %8u, savings %7u bytes |", u, l, p, dictList[u].savings); - DiB_printHex(3, (const char*)samplesBuffer+p, d); + ZDICT_printHex(3, (const char*)samplesBuffer+p, d); DISPLAYLEVEL(3, "| \n"); } } } /* create dictionary */ { - U32 dictContentSize = DiB_dictSize(dictList); + U32 dictContentSize = ZDICT_dictSize(dictList); size_t hSize; BYTE* ptr; U32 u; @@ -918,7 +838,7 @@ static size_t DiB_trainFromBuffer_internal( if (selectivity==1) { /* note could also be used to complete a dictionary, but not necessarily better */ DISPLAYLEVEL(3, "\r%70s\r", ""); /* clean display line */ DISPLAYLEVEL(3, "Adding %u KB with fast sampling \n", (U32)(targetDictSize>>10)); - dictContentSize = (U32)DiB_fastSampling((char*)dictBuffer + g_provision_entropySize, + dictContentSize = (U32)ZDICT_fastSampling((char*)dictBuffer + g_provision_entropySize, targetDictSize, samplesBuffer, sBuffSize); } @@ -929,7 +849,7 @@ static size_t DiB_trainFromBuffer_internal( /* entropic tables */ DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */ DISPLAYLEVEL(2, "statistics ... \n"); - hSize += DiB_analyzeEntropy((char*)dictBuffer+4, maxDictSize-4, + hSize += ZDICT_analyzeEntropy((char*)dictBuffer+4, maxDictSize-4, compressionLevel, samplesBuffer, sampleSizes, nbSamples, (char*)dictBuffer + maxDictSize - dictContentSize, dictContentSize); @@ -945,76 +865,38 @@ static size_t DiB_trainFromBuffer_internal( } -/* issue : samplesBuffer need to be followed by a noisy guard band. -* work around : duplicate the buffer, and add the noise ? */ -size_t DiB_trainFromBuffer(void* dictBuffer, size_t maxDictSize, - const void* samplesBuffer, const size_t* sampleSizes, unsigned nbSamples, - DiB_params_t params) +size_t ZDICT_trainFromBuffer_advanced(void* dictBuffer, size_t dictBufferCapacity, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, + ZDICT_params_t params) { size_t sBuffSize; void* newBuff; size_t result; - { unsigned u; for (u=0, sBuffSize=0; u totalSizeToLoad) benchedSize = (size_t)totalSizeToLoad; - if (benchedSize < totalSizeToLoad) - DISPLAYLEVEL(1, "Not enough memory; training on %u MB only...\n", (unsigned)(benchedSize >> 20)); - - /* Memory allocation & restrictions */ - srcBuffer = malloc(benchedSize+NOISELENGTH); /* + noise */ - if ((!fileSizes) || (!srcBuffer) || (!dictBuffer)) EXM_THROW(12, "not enough memory for DiB_trainFiles"); /* should not happen */ - - /* Load input buffer */ - DiB_loadFiles(srcBuffer, benchedSize, fileSizes, fileNamesTable, nbFiles); - DiB_fillNoise((char*)srcBuffer + benchedSize, NOISELENGTH); /* guard band, for end of buffer condition */ - - /* call buffer version */ - dictSize = DiB_trainFromBuffer_internal(dictBuffer, maxDictSize, - srcBuffer, fileSizes, nbFiles, - params); - if (DiB_isError(dictSize)) - { - DISPLAYLEVEL(1, "dictionary training failed : %s", DiB_getErrorName(dictSize)); /* should not happen */ - result = 1; - goto _cleanup; - } - - /* save dict */ - DISPLAYLEVEL(2, "Save dictionary of size %u into file %s \n", (U32)dictSize, dictFileName); - DiB_saveDict(dictFileName, dictBuffer, dictSize); - - /* clean up */ -_cleanup: - free(srcBuffer); - free(dictBuffer); - free(fileSizes); - return result; + ZDICT_params_t params; + memset(¶ms, 0, sizeof(params)); + return ZDICT_trainFromBuffer_advanced(dictBuffer, dictBufferCapacity, + samplesBuffer, samplesSizes, nbSamples, + params); } + diff --git a/lib/dictBuilder.h b/lib/dictBuilder.h new file mode 100644 index 000000000..2ca190ce3 --- /dev/null +++ b/lib/dictBuilder.h @@ -0,0 +1,67 @@ +/* + dictBuilder header file + Copyright (C) Yann Collet 2016 + + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - Zstd source repository : https://www.zstd.net +*/ + +#ifndef DICTBUILDER_H_001 +#define DICTBUILDER_H_001 + +#if defined (__cplusplus) +extern "C" { +#endif + +/*-************************************* +* Public functions +***************************************/ +/*! ZDICT_trainFromBuffer() : + Train a dictionary from a memory buffer `samplesBuffer`, + where `nbSamples` samples have been stored concatenated. + Each sample size is provided into an orderly table `samplesSizes`. + Resulting dictionary will be saved into `dictBuffer`. + @return : size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + or an error code, which can be tested by ZDICT_isError(). +*/ +size_t ZDICT_trainFromBuffer(void* dictBuffer, size_t dictBufferCapacity, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples); + + +/*-************************************* +* Helper functions +***************************************/ +unsigned ZDICT_isError(size_t errorCode); +const char* ZDICT_getErrorName(size_t errorCode); + + +#if defined (__cplusplus) +} +#endif + +#endif diff --git a/lib/dictBuilder_static.h b/lib/dictBuilder_static.h new file mode 100644 index 000000000..0bddb30df --- /dev/null +++ b/lib/dictBuilder_static.h @@ -0,0 +1,104 @@ +/* + dictBuilder header file + for static linking only + Copyright (C) Yann Collet 2016 + + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - Zstd source repository : https://www.zstd.net +*/ + +/* This library is EXPERIMENTAL, below API is not yet stable */ + +#ifndef DICTBUILDER_STATIC_H_002 +#define DICTBUILDER_STATIC_H_002 + +#if defined (__cplusplus) +extern "C" { +#endif + +/*-************************************* +* Dependencies +***************************************/ +#include "dictBuilder.h" + + +/*-************************************* +* Public type +***************************************/ +typedef struct { + unsigned selectivityLevel; /* 0 means default; larger => bigger selection => larger dictionary */ + unsigned compressionLevel; /* 0 means default; target a specific zstd compression level */ +} ZDICT_params_t; + + +/*-************************************* +* Public functions +***************************************/ +/*! ZDICT_trainFromBuffer_advanced() : + Same as ZDICT_trainFromBuffer() with control over more parameters. + `parameters` is optional and can be provided with values set to 0 to mean "default". + @return : size of dictionary stored into `dictBuffer` (<= `dictBufferSize`) + or an error code, which can be tested by DiB_isError(). + note : ZDICT_trainFromBuffer_advanced() will send notifications into stderr if instructed to, using ZDICT_setNotificationLevel() +*/ +size_t ZDICT_trainFromBuffer_advanced(void* dictBuffer, size_t dictBufferCapacity, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, + ZDICT_params_t parameters); + + +/*-************************************* +* Helper functions +***************************************/ +/*! ZDICT_setNotificationLevel() : + Set amount of notification to be displayed on the console. + default : 0 = no console notification. + 1 = errors; 2 = notifications; 3 = details; 4 = debug; + Note : not thread-safe (uses a global constant) +*/ +void ZDICT_setNotificationLevel(unsigned l); + + +/*-************************************* +* Private functions +***************************************/ +/*! ZDICT_trainFromBuffer_unsafe() : + Same as ZDICT_trainFromBuffer_advanced(), but does not control `samplesBuffer`. + note : `samplesBuffer` must be followed by noisy guard band to avoid out-of-buffer reads. + @return : size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + or an error code. +*/ +size_t ZDICT_trainFromBuffer_unsafe(void* dictBuffer, size_t dictBufferCapacity, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, + ZDICT_params_t parameters); + + +#if defined (__cplusplus) +} +#endif + +#endif /* DICTBUILDER_STATIC_H_002 */ diff --git a/lib/divsufsort.c b/lib/divsufsort.c new file mode 100644 index 000000000..ca790574a --- /dev/null +++ b/lib/divsufsort.c @@ -0,0 +1,1905 @@ +/* + * divsufsort.c for libdivsufsort-lite + * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#if defined(_MSC_VER) + #pragma warning(disable : 4244) +#endif + +#include +#include +#include + +#include "divsufsort.h" + +/*- Constants -*/ +#if defined(INLINE) +# undef INLINE +#endif +#if !defined(INLINE) +# define INLINE __inline +#endif +#if defined(ALPHABET_SIZE) && (ALPHABET_SIZE < 1) +# undef ALPHABET_SIZE +#endif +#if !defined(ALPHABET_SIZE) +# define ALPHABET_SIZE (256) +#endif +#define BUCKET_A_SIZE (ALPHABET_SIZE) +#define BUCKET_B_SIZE (ALPHABET_SIZE * ALPHABET_SIZE) +#if defined(SS_INSERTIONSORT_THRESHOLD) +# if SS_INSERTIONSORT_THRESHOLD < 1 +# undef SS_INSERTIONSORT_THRESHOLD +# define SS_INSERTIONSORT_THRESHOLD (1) +# endif +#else +# define SS_INSERTIONSORT_THRESHOLD (8) +#endif +#if defined(SS_BLOCKSIZE) +# if SS_BLOCKSIZE < 0 +# undef SS_BLOCKSIZE +# define SS_BLOCKSIZE (0) +# elif 32768 <= SS_BLOCKSIZE +# undef SS_BLOCKSIZE +# define SS_BLOCKSIZE (32767) +# endif +#else +# define SS_BLOCKSIZE (1024) +#endif +/* minstacksize = log(SS_BLOCKSIZE) / log(3) * 2 */ +#if SS_BLOCKSIZE == 0 +# define SS_MISORT_STACKSIZE (96) +#elif SS_BLOCKSIZE <= 4096 +# define SS_MISORT_STACKSIZE (16) +#else +# define SS_MISORT_STACKSIZE (24) +#endif +#define SS_SMERGE_STACKSIZE (32) +#define TR_INSERTIONSORT_THRESHOLD (8) +#define TR_STACKSIZE (64) + + +/*- Macros -*/ +#ifndef SWAP +# define SWAP(_a, _b) do { t = (_a); (_a) = (_b); (_b) = t; } while(0) +#endif /* SWAP */ +#ifndef MIN +# define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) +#endif /* MIN */ +#ifndef MAX +# define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) +#endif /* MAX */ +#define STACK_PUSH(_a, _b, _c, _d)\ + do {\ + assert(ssize < STACK_SIZE);\ + stack[ssize].a = (_a), stack[ssize].b = (_b),\ + stack[ssize].c = (_c), stack[ssize++].d = (_d);\ + } while(0) +#define STACK_PUSH5(_a, _b, _c, _d, _e)\ + do {\ + assert(ssize < STACK_SIZE);\ + stack[ssize].a = (_a), stack[ssize].b = (_b),\ + stack[ssize].c = (_c), stack[ssize].d = (_d), stack[ssize++].e = (_e);\ + } while(0) +#define STACK_POP(_a, _b, _c, _d)\ + do {\ + assert(0 <= ssize);\ + if(ssize == 0) { return; }\ + (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\ + (_c) = stack[ssize].c, (_d) = stack[ssize].d;\ + } while(0) +#define STACK_POP5(_a, _b, _c, _d, _e)\ + do {\ + assert(0 <= ssize);\ + if(ssize == 0) { return; }\ + (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\ + (_c) = stack[ssize].c, (_d) = stack[ssize].d, (_e) = stack[ssize].e;\ + } while(0) +#define BUCKET_A(_c0) bucket_A[(_c0)] +#if ALPHABET_SIZE == 256 +#define BUCKET_B(_c0, _c1) (bucket_B[((_c1) << 8) | (_c0)]) +#define BUCKET_BSTAR(_c0, _c1) (bucket_B[((_c0) << 8) | (_c1)]) +#else +#define BUCKET_B(_c0, _c1) (bucket_B[(_c1) * ALPHABET_SIZE + (_c0)]) +#define BUCKET_BSTAR(_c0, _c1) (bucket_B[(_c0) * ALPHABET_SIZE + (_c1)]) +#endif + + +/*- Private Functions -*/ + +static const int lg_table[256]= { + -1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; + +#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) + +static INLINE +int +ss_ilg(int n) { +#if SS_BLOCKSIZE == 0 + return (n & 0xffff0000) ? + ((n & 0xff000000) ? + 24 + lg_table[(n >> 24) & 0xff] : + 16 + lg_table[(n >> 16) & 0xff]) : + ((n & 0x0000ff00) ? + 8 + lg_table[(n >> 8) & 0xff] : + 0 + lg_table[(n >> 0) & 0xff]); +#elif SS_BLOCKSIZE < 256 + return lg_table[n]; +#else + return (n & 0xff00) ? + 8 + lg_table[(n >> 8) & 0xff] : + 0 + lg_table[(n >> 0) & 0xff]; +#endif +} + +#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */ + +#if SS_BLOCKSIZE != 0 + +static const int sqq_table[256] = { + 0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57, 59, 61, + 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81, 83, 84, 86, 87, 89, + 90, 91, 93, 94, 96, 97, 98, 99, 101, 102, 103, 104, 106, 107, 108, 109, +110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, +128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, +143, 144, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155, +156, 157, 158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168, +169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 178, 179, 180, +181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190, 191, +192, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 199, 200, 201, 201, +202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211, +212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 221, +221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230, +230, 231, 231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, +239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, +247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255 +}; + +static INLINE +int +ss_isqrt(int x) { + int y, e; + + if(x >= (SS_BLOCKSIZE * SS_BLOCKSIZE)) { return SS_BLOCKSIZE; } + e = (x & 0xffff0000) ? + ((x & 0xff000000) ? + 24 + lg_table[(x >> 24) & 0xff] : + 16 + lg_table[(x >> 16) & 0xff]) : + ((x & 0x0000ff00) ? + 8 + lg_table[(x >> 8) & 0xff] : + 0 + lg_table[(x >> 0) & 0xff]); + + if(e >= 16) { + y = sqq_table[x >> ((e - 6) - (e & 1))] << ((e >> 1) - 7); + if(e >= 24) { y = (y + 1 + x / y) >> 1; } + y = (y + 1 + x / y) >> 1; + } else if(e >= 8) { + y = (sqq_table[x >> ((e - 6) - (e & 1))] >> (7 - (e >> 1))) + 1; + } else { + return sqq_table[x] >> 4; + } + + return (x < (y * y)) ? y - 1 : y; +} + +#endif /* SS_BLOCKSIZE != 0 */ + + +/*---------------------------------------------------------------------------*/ + +/* Compares two suffixes. */ +static INLINE +int +ss_compare(const unsigned char *T, + const int *p1, const int *p2, + int depth) { + const unsigned char *U1, *U2, *U1n, *U2n; + + for(U1 = T + depth + *p1, + U2 = T + depth + *p2, + U1n = T + *(p1 + 1) + 2, + U2n = T + *(p2 + 1) + 2; + (U1 < U1n) && (U2 < U2n) && (*U1 == *U2); + ++U1, ++U2) { + } + + return U1 < U1n ? + (U2 < U2n ? *U1 - *U2 : 1) : + (U2 < U2n ? -1 : 0); +} + + +/*---------------------------------------------------------------------------*/ + +#if (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1) + +/* Insertionsort for small size groups */ +static +void +ss_insertionsort(const unsigned char *T, const int *PA, + int *first, int *last, int depth) { + int *i, *j; + int t; + int r; + + for(i = last - 2; first <= i; --i) { + for(t = *i, j = i + 1; 0 < (r = ss_compare(T, PA + t, PA + *j, depth));) { + do { *(j - 1) = *j; } while((++j < last) && (*j < 0)); + if(last <= j) { break; } + } + if(r == 0) { *j = ~*j; } + *(j - 1) = t; + } +} + +#endif /* (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1) */ + + +/*---------------------------------------------------------------------------*/ + +#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) + +static INLINE +void +ss_fixdown(const unsigned char *Td, const int *PA, + int *SA, int i, int size) { + int j, k; + int v; + int c, d, e; + + for(v = SA[i], c = Td[PA[v]]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) { + d = Td[PA[SA[k = j++]]]; + if(d < (e = Td[PA[SA[j]]])) { k = j; d = e; } + if(d <= c) { break; } + } + SA[i] = v; +} + +/* Simple top-down heapsort. */ +static +void +ss_heapsort(const unsigned char *Td, const int *PA, int *SA, int size) { + int i, m; + int t; + + m = size; + if((size % 2) == 0) { + m--; + if(Td[PA[SA[m / 2]]] < Td[PA[SA[m]]]) { SWAP(SA[m], SA[m / 2]); } + } + + for(i = m / 2 - 1; 0 <= i; --i) { ss_fixdown(Td, PA, SA, i, m); } + if((size % 2) == 0) { SWAP(SA[0], SA[m]); ss_fixdown(Td, PA, SA, 0, m); } + for(i = m - 1; 0 < i; --i) { + t = SA[0], SA[0] = SA[i]; + ss_fixdown(Td, PA, SA, 0, i); + SA[i] = t; + } +} + + +/*---------------------------------------------------------------------------*/ + +/* Returns the median of three elements. */ +static INLINE +int * +ss_median3(const unsigned char *Td, const int *PA, + int *v1, int *v2, int *v3) { + int *t; + if(Td[PA[*v1]] > Td[PA[*v2]]) { SWAP(v1, v2); } + if(Td[PA[*v2]] > Td[PA[*v3]]) { + if(Td[PA[*v1]] > Td[PA[*v3]]) { return v1; } + else { return v3; } + } + return v2; +} + +/* Returns the median of five elements. */ +static INLINE +int * +ss_median5(const unsigned char *Td, const int *PA, + int *v1, int *v2, int *v3, int *v4, int *v5) { + int *t; + if(Td[PA[*v2]] > Td[PA[*v3]]) { SWAP(v2, v3); } + if(Td[PA[*v4]] > Td[PA[*v5]]) { SWAP(v4, v5); } + if(Td[PA[*v2]] > Td[PA[*v4]]) { SWAP(v2, v4); SWAP(v3, v5); } + if(Td[PA[*v1]] > Td[PA[*v3]]) { SWAP(v1, v3); } + if(Td[PA[*v1]] > Td[PA[*v4]]) { SWAP(v1, v4); SWAP(v3, v5); } + if(Td[PA[*v3]] > Td[PA[*v4]]) { return v4; } + return v3; +} + +/* Returns the pivot element. */ +static INLINE +int * +ss_pivot(const unsigned char *Td, const int *PA, int *first, int *last) { + int *middle; + int t; + + t = last - first; + middle = first + t / 2; + + if(t <= 512) { + if(t <= 32) { + return ss_median3(Td, PA, first, middle, last - 1); + } else { + t >>= 2; + return ss_median5(Td, PA, first, first + t, middle, last - 1 - t, last - 1); + } + } + t >>= 3; + first = ss_median3(Td, PA, first, first + t, first + (t << 1)); + middle = ss_median3(Td, PA, middle - t, middle, middle + t); + last = ss_median3(Td, PA, last - 1 - (t << 1), last - 1 - t, last - 1); + return ss_median3(Td, PA, first, middle, last); +} + + +/*---------------------------------------------------------------------------*/ + +/* Binary partition for substrings. */ +static INLINE +int * +ss_partition(const int *PA, + int *first, int *last, int depth) { + int *a, *b; + int t; + for(a = first - 1, b = last;;) { + for(; (++a < b) && ((PA[*a] + depth) >= (PA[*a + 1] + 1));) { *a = ~*a; } + for(; (a < --b) && ((PA[*b] + depth) < (PA[*b + 1] + 1));) { } + if(b <= a) { break; } + t = ~*b; + *b = *a; + *a = t; + } + if(first < a) { *first = ~*first; } + return a; +} + +/* Multikey introsort for medium size groups. */ +static +void +ss_mintrosort(const unsigned char *T, const int *PA, + int *first, int *last, + int depth) { +#define STACK_SIZE SS_MISORT_STACKSIZE + struct { int *a, *b, c; int d; } stack[STACK_SIZE]; + const unsigned char *Td; + int *a, *b, *c, *d, *e, *f; + int s, t; + int ssize; + int limit; + int v, x = 0; + + for(ssize = 0, limit = ss_ilg(last - first);;) { + + if((last - first) <= SS_INSERTIONSORT_THRESHOLD) { +#if 1 < SS_INSERTIONSORT_THRESHOLD + if(1 < (last - first)) { ss_insertionsort(T, PA, first, last, depth); } +#endif + STACK_POP(first, last, depth, limit); + continue; + } + + Td = T + depth; + if(limit-- == 0) { ss_heapsort(Td, PA, first, last - first); } + if(limit < 0) { + for(a = first + 1, v = Td[PA[*first]]; a < last; ++a) { + if((x = Td[PA[*a]]) != v) { + if(1 < (a - first)) { break; } + v = x; + first = a; + } + } + if(Td[PA[*first] - 1] < v) { + first = ss_partition(PA, first, a, depth); + } + if((a - first) <= (last - a)) { + if(1 < (a - first)) { + STACK_PUSH(a, last, depth, -1); + last = a, depth += 1, limit = ss_ilg(a - first); + } else { + first = a, limit = -1; + } + } else { + if(1 < (last - a)) { + STACK_PUSH(first, a, depth + 1, ss_ilg(a - first)); + first = a, limit = -1; + } else { + last = a, depth += 1, limit = ss_ilg(a - first); + } + } + continue; + } + + /* choose pivot */ + a = ss_pivot(Td, PA, first, last); + v = Td[PA[*a]]; + SWAP(*first, *a); + + /* partition */ + for(b = first; (++b < last) && ((x = Td[PA[*b]]) == v);) { } + if(((a = b) < last) && (x < v)) { + for(; (++b < last) && ((x = Td[PA[*b]]) <= v);) { + if(x == v) { SWAP(*b, *a); ++a; } + } + } + for(c = last; (b < --c) && ((x = Td[PA[*c]]) == v);) { } + if((b < (d = c)) && (x > v)) { + for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) { + if(x == v) { SWAP(*c, *d); --d; } + } + } + for(; b < c;) { + SWAP(*b, *c); + for(; (++b < c) && ((x = Td[PA[*b]]) <= v);) { + if(x == v) { SWAP(*b, *a); ++a; } + } + for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) { + if(x == v) { SWAP(*c, *d); --d; } + } + } + + if(a <= d) { + c = b - 1; + + if((s = a - first) > (t = b - a)) { s = t; } + for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } + if((s = d - c) > (t = last - d - 1)) { s = t; } + for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } + + a = first + (b - a), c = last - (d - c); + b = (v <= Td[PA[*a] - 1]) ? a : ss_partition(PA, a, c, depth); + + if((a - first) <= (last - c)) { + if((last - c) <= (c - b)) { + STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); + STACK_PUSH(c, last, depth, limit); + last = a; + } else if((a - first) <= (c - b)) { + STACK_PUSH(c, last, depth, limit); + STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); + last = a; + } else { + STACK_PUSH(c, last, depth, limit); + STACK_PUSH(first, a, depth, limit); + first = b, last = c, depth += 1, limit = ss_ilg(c - b); + } + } else { + if((a - first) <= (c - b)) { + STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); + STACK_PUSH(first, a, depth, limit); + first = c; + } else if((last - c) <= (c - b)) { + STACK_PUSH(first, a, depth, limit); + STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); + first = c; + } else { + STACK_PUSH(first, a, depth, limit); + STACK_PUSH(c, last, depth, limit); + first = b, last = c, depth += 1, limit = ss_ilg(c - b); + } + } + } else { + limit += 1; + if(Td[PA[*first] - 1] < v) { + first = ss_partition(PA, first, last, depth); + limit = ss_ilg(last - first); + } + depth += 1; + } + } +#undef STACK_SIZE +} + +#endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */ + + +/*---------------------------------------------------------------------------*/ + +#if SS_BLOCKSIZE != 0 + +static INLINE +void +ss_blockswap(int *a, int *b, int n) { + int t; + for(; 0 < n; --n, ++a, ++b) { + t = *a, *a = *b, *b = t; + } +} + +static INLINE +void +ss_rotate(int *first, int *middle, int *last) { + int *a, *b, t; + int l, r; + l = middle - first, r = last - middle; + for(; (0 < l) && (0 < r);) { + if(l == r) { ss_blockswap(first, middle, l); break; } + if(l < r) { + a = last - 1, b = middle - 1; + t = *a; + do { + *a-- = *b, *b-- = *a; + if(b < first) { + *a = t; + last = a; + if((r -= l + 1) <= l) { break; } + a -= 1, b = middle - 1; + t = *a; + } + } while(1); + } else { + a = first, b = middle; + t = *a; + do { + *a++ = *b, *b++ = *a; + if(last <= b) { + *a = t; + first = a + 1; + if((l -= r + 1) <= r) { break; } + a += 1, b = middle; + t = *a; + } + } while(1); + } + } +} + + +/*---------------------------------------------------------------------------*/ + +static +void +ss_inplacemerge(const unsigned char *T, const int *PA, + int *first, int *middle, int *last, + int depth) { + const int *p; + int *a, *b; + int len, half; + int q, r; + int x; + + for(;;) { + if(*(last - 1) < 0) { x = 1; p = PA + ~*(last - 1); } + else { x = 0; p = PA + *(last - 1); } + for(a = first, len = middle - first, half = len >> 1, r = -1; + 0 < len; + len = half, half >>= 1) { + b = a + half; + q = ss_compare(T, PA + ((0 <= *b) ? *b : ~*b), p, depth); + if(q < 0) { + a = b + 1; + half -= (len & 1) ^ 1; + } else { + r = q; + } + } + if(a < middle) { + if(r == 0) { *a = ~*a; } + ss_rotate(a, middle, last); + last -= middle - a; + middle = a; + if(first == middle) { break; } + } + --last; + if(x != 0) { while(*--last < 0) { } } + if(middle == last) { break; } + } +} + + +/*---------------------------------------------------------------------------*/ + +/* Merge-forward with internal buffer. */ +static +void +ss_mergeforward(const unsigned char *T, const int *PA, + int *first, int *middle, int *last, + int *buf, int depth) { + int *a, *b, *c, *bufend; + int t; + int r; + + bufend = buf + (middle - first) - 1; + ss_blockswap(buf, first, middle - first); + + for(t = *(a = first), b = buf, c = middle;;) { + r = ss_compare(T, PA + *b, PA + *c, depth); + if(r < 0) { + do { + *a++ = *b; + if(bufend <= b) { *bufend = t; return; } + *b++ = *a; + } while(*b < 0); + } else if(r > 0) { + do { + *a++ = *c, *c++ = *a; + if(last <= c) { + while(b < bufend) { *a++ = *b, *b++ = *a; } + *a = *b, *b = t; + return; + } + } while(*c < 0); + } else { + *c = ~*c; + do { + *a++ = *b; + if(bufend <= b) { *bufend = t; return; } + *b++ = *a; + } while(*b < 0); + + do { + *a++ = *c, *c++ = *a; + if(last <= c) { + while(b < bufend) { *a++ = *b, *b++ = *a; } + *a = *b, *b = t; + return; + } + } while(*c < 0); + } + } +} + +/* Merge-backward with internal buffer. */ +static +void +ss_mergebackward(const unsigned char *T, const int *PA, + int *first, int *middle, int *last, + int *buf, int depth) { + const int *p1, *p2; + int *a, *b, *c, *bufend; + int t; + int r; + int x; + + bufend = buf + (last - middle) - 1; + ss_blockswap(buf, middle, last - middle); + + x = 0; + if(*bufend < 0) { p1 = PA + ~*bufend; x |= 1; } + else { p1 = PA + *bufend; } + if(*(middle - 1) < 0) { p2 = PA + ~*(middle - 1); x |= 2; } + else { p2 = PA + *(middle - 1); } + for(t = *(a = last - 1), b = bufend, c = middle - 1;;) { + r = ss_compare(T, p1, p2, depth); + if(0 < r) { + if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; } + *a-- = *b; + if(b <= buf) { *buf = t; break; } + *b-- = *a; + if(*b < 0) { p1 = PA + ~*b; x |= 1; } + else { p1 = PA + *b; } + } else if(r < 0) { + if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; } + *a-- = *c, *c-- = *a; + if(c < first) { + while(buf < b) { *a-- = *b, *b-- = *a; } + *a = *b, *b = t; + break; + } + if(*c < 0) { p2 = PA + ~*c; x |= 2; } + else { p2 = PA + *c; } + } else { + if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; } + *a-- = ~*b; + if(b <= buf) { *buf = t; break; } + *b-- = *a; + if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; } + *a-- = *c, *c-- = *a; + if(c < first) { + while(buf < b) { *a-- = *b, *b-- = *a; } + *a = *b, *b = t; + break; + } + if(*b < 0) { p1 = PA + ~*b; x |= 1; } + else { p1 = PA + *b; } + if(*c < 0) { p2 = PA + ~*c; x |= 2; } + else { p2 = PA + *c; } + } + } +} + +/* D&C based merge. */ +static +void +ss_swapmerge(const unsigned char *T, const int *PA, + int *first, int *middle, int *last, + int *buf, int bufsize, int depth) { +#define STACK_SIZE SS_SMERGE_STACKSIZE +#define GETIDX(a) ((0 <= (a)) ? (a) : (~(a))) +#define MERGE_CHECK(a, b, c)\ + do {\ + if(((c) & 1) ||\ + (((c) & 2) && (ss_compare(T, PA + GETIDX(*((a) - 1)), PA + *(a), depth) == 0))) {\ + *(a) = ~*(a);\ + }\ + if(((c) & 4) && ((ss_compare(T, PA + GETIDX(*((b) - 1)), PA + *(b), depth) == 0))) {\ + *(b) = ~*(b);\ + }\ + } while(0) + struct { int *a, *b, *c; int d; } stack[STACK_SIZE]; + int *l, *r, *lm, *rm; + int m, len, half; + int ssize; + int check, next; + + for(check = 0, ssize = 0;;) { + if((last - middle) <= bufsize) { + if((first < middle) && (middle < last)) { + ss_mergebackward(T, PA, first, middle, last, buf, depth); + } + MERGE_CHECK(first, last, check); + STACK_POP(first, middle, last, check); + continue; + } + + if((middle - first) <= bufsize) { + if(first < middle) { + ss_mergeforward(T, PA, first, middle, last, buf, depth); + } + MERGE_CHECK(first, last, check); + STACK_POP(first, middle, last, check); + continue; + } + + for(m = 0, len = MIN(middle - first, last - middle), half = len >> 1; + 0 < len; + len = half, half >>= 1) { + if(ss_compare(T, PA + GETIDX(*(middle + m + half)), + PA + GETIDX(*(middle - m - half - 1)), depth) < 0) { + m += half + 1; + half -= (len & 1) ^ 1; + } + } + + if(0 < m) { + lm = middle - m, rm = middle + m; + ss_blockswap(lm, middle, m); + l = r = middle, next = 0; + if(rm < last) { + if(*rm < 0) { + *rm = ~*rm; + if(first < lm) { for(; *--l < 0;) { } next |= 4; } + next |= 1; + } else if(first < lm) { + for(; *r < 0; ++r) { } + next |= 2; + } + } + + if((l - first) <= (last - r)) { + STACK_PUSH(r, rm, last, (next & 3) | (check & 4)); + middle = lm, last = l, check = (check & 3) | (next & 4); + } else { + if((next & 2) && (r == middle)) { next ^= 6; } + STACK_PUSH(first, lm, l, (check & 3) | (next & 4)); + first = r, middle = rm, check = (next & 3) | (check & 4); + } + } else { + if(ss_compare(T, PA + GETIDX(*(middle - 1)), PA + *middle, depth) == 0) { + *middle = ~*middle; + } + MERGE_CHECK(first, last, check); + STACK_POP(first, middle, last, check); + } + } +#undef STACK_SIZE +} + +#endif /* SS_BLOCKSIZE != 0 */ + + +/*---------------------------------------------------------------------------*/ + +/* Substring sort */ +static +void +sssort(const unsigned char *T, const int *PA, + int *first, int *last, + int *buf, int bufsize, + int depth, int n, int lastsuffix) { + int *a; +#if SS_BLOCKSIZE != 0 + int *b, *middle, *curbuf; + int j, k, curbufsize, limit; +#endif + int i; + + if(lastsuffix != 0) { ++first; } + +#if SS_BLOCKSIZE == 0 + ss_mintrosort(T, PA, first, last, depth); +#else + if((bufsize < SS_BLOCKSIZE) && + (bufsize < (last - first)) && + (bufsize < (limit = ss_isqrt(last - first)))) { + if(SS_BLOCKSIZE < limit) { limit = SS_BLOCKSIZE; } + buf = middle = last - limit, bufsize = limit; + } else { + middle = last, limit = 0; + } + for(a = first, i = 0; SS_BLOCKSIZE < (middle - a); a += SS_BLOCKSIZE, ++i) { +#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE + ss_mintrosort(T, PA, a, a + SS_BLOCKSIZE, depth); +#elif 1 < SS_BLOCKSIZE + ss_insertionsort(T, PA, a, a + SS_BLOCKSIZE, depth); +#endif + curbufsize = last - (a + SS_BLOCKSIZE); + curbuf = a + SS_BLOCKSIZE; + if(curbufsize <= bufsize) { curbufsize = bufsize, curbuf = buf; } + for(b = a, k = SS_BLOCKSIZE, j = i; j & 1; b -= k, k <<= 1, j >>= 1) { + ss_swapmerge(T, PA, b - k, b, b + k, curbuf, curbufsize, depth); + } + } +#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE + ss_mintrosort(T, PA, a, middle, depth); +#elif 1 < SS_BLOCKSIZE + ss_insertionsort(T, PA, a, middle, depth); +#endif + for(k = SS_BLOCKSIZE; i != 0; k <<= 1, i >>= 1) { + if(i & 1) { + ss_swapmerge(T, PA, a - k, a, middle, buf, bufsize, depth); + a -= k; + } + } + if(limit != 0) { +#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE + ss_mintrosort(T, PA, middle, last, depth); +#elif 1 < SS_BLOCKSIZE + ss_insertionsort(T, PA, middle, last, depth); +#endif + ss_inplacemerge(T, PA, first, middle, last, depth); + } +#endif + + if(lastsuffix != 0) { + /* Insert last type B* suffix. */ + int PAi[2]; PAi[0] = PA[*(first - 1)], PAi[1] = n - 2; + for(a = first, i = *(first - 1); + (a < last) && ((*a < 0) || (0 < ss_compare(T, &(PAi[0]), PA + *a, depth))); + ++a) { + *(a - 1) = *a; + } + *(a - 1) = i; + } +} + + +/*---------------------------------------------------------------------------*/ + +static INLINE +int +tr_ilg(int n) { + return (n & 0xffff0000) ? + ((n & 0xff000000) ? + 24 + lg_table[(n >> 24) & 0xff] : + 16 + lg_table[(n >> 16) & 0xff]) : + ((n & 0x0000ff00) ? + 8 + lg_table[(n >> 8) & 0xff] : + 0 + lg_table[(n >> 0) & 0xff]); +} + + +/*---------------------------------------------------------------------------*/ + +/* Simple insertionsort for small size groups. */ +static +void +tr_insertionsort(const int *ISAd, int *first, int *last) { + int *a, *b; + int t, r; + + for(a = first + 1; a < last; ++a) { + for(t = *a, b = a - 1; 0 > (r = ISAd[t] - ISAd[*b]);) { + do { *(b + 1) = *b; } while((first <= --b) && (*b < 0)); + if(b < first) { break; } + } + if(r == 0) { *b = ~*b; } + *(b + 1) = t; + } +} + + +/*---------------------------------------------------------------------------*/ + +static INLINE +void +tr_fixdown(const int *ISAd, int *SA, int i, int size) { + int j, k; + int v; + int c, d, e; + + for(v = SA[i], c = ISAd[v]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) { + d = ISAd[SA[k = j++]]; + if(d < (e = ISAd[SA[j]])) { k = j; d = e; } + if(d <= c) { break; } + } + SA[i] = v; +} + +/* Simple top-down heapsort. */ +static +void +tr_heapsort(const int *ISAd, int *SA, int size) { + int i, m; + int t; + + m = size; + if((size % 2) == 0) { + m--; + if(ISAd[SA[m / 2]] < ISAd[SA[m]]) { SWAP(SA[m], SA[m / 2]); } + } + + for(i = m / 2 - 1; 0 <= i; --i) { tr_fixdown(ISAd, SA, i, m); } + if((size % 2) == 0) { SWAP(SA[0], SA[m]); tr_fixdown(ISAd, SA, 0, m); } + for(i = m - 1; 0 < i; --i) { + t = SA[0], SA[0] = SA[i]; + tr_fixdown(ISAd, SA, 0, i); + SA[i] = t; + } +} + + +/*---------------------------------------------------------------------------*/ + +/* Returns the median of three elements. */ +static INLINE +int * +tr_median3(const int *ISAd, int *v1, int *v2, int *v3) { + int *t; + if(ISAd[*v1] > ISAd[*v2]) { SWAP(v1, v2); } + if(ISAd[*v2] > ISAd[*v3]) { + if(ISAd[*v1] > ISAd[*v3]) { return v1; } + else { return v3; } + } + return v2; +} + +/* Returns the median of five elements. */ +static INLINE +int * +tr_median5(const int *ISAd, + int *v1, int *v2, int *v3, int *v4, int *v5) { + int *t; + if(ISAd[*v2] > ISAd[*v3]) { SWAP(v2, v3); } + if(ISAd[*v4] > ISAd[*v5]) { SWAP(v4, v5); } + if(ISAd[*v2] > ISAd[*v4]) { SWAP(v2, v4); SWAP(v3, v5); } + if(ISAd[*v1] > ISAd[*v3]) { SWAP(v1, v3); } + if(ISAd[*v1] > ISAd[*v4]) { SWAP(v1, v4); SWAP(v3, v5); } + if(ISAd[*v3] > ISAd[*v4]) { return v4; } + return v3; +} + +/* Returns the pivot element. */ +static INLINE +int * +tr_pivot(const int *ISAd, int *first, int *last) { + int *middle; + int t; + + t = last - first; + middle = first + t / 2; + + if(t <= 512) { + if(t <= 32) { + return tr_median3(ISAd, first, middle, last - 1); + } else { + t >>= 2; + return tr_median5(ISAd, first, first + t, middle, last - 1 - t, last - 1); + } + } + t >>= 3; + first = tr_median3(ISAd, first, first + t, first + (t << 1)); + middle = tr_median3(ISAd, middle - t, middle, middle + t); + last = tr_median3(ISAd, last - 1 - (t << 1), last - 1 - t, last - 1); + return tr_median3(ISAd, first, middle, last); +} + + +/*---------------------------------------------------------------------------*/ + +typedef struct _trbudget_t trbudget_t; +struct _trbudget_t { + int chance; + int remain; + int incval; + int count; +}; + +static INLINE +void +trbudget_init(trbudget_t *budget, int chance, int incval) { + budget->chance = chance; + budget->remain = budget->incval = incval; +} + +static INLINE +int +trbudget_check(trbudget_t *budget, int size) { + if(size <= budget->remain) { budget->remain -= size; return 1; } + if(budget->chance == 0) { budget->count += size; return 0; } + budget->remain += budget->incval - size; + budget->chance -= 1; + return 1; +} + + +/*---------------------------------------------------------------------------*/ + +static INLINE +void +tr_partition(const int *ISAd, + int *first, int *middle, int *last, + int **pa, int **pb, int v) { + int *a, *b, *c, *d, *e, *f; + int t, s; + int x = 0; + + for(b = middle - 1; (++b < last) && ((x = ISAd[*b]) == v);) { } + if(((a = b) < last) && (x < v)) { + for(; (++b < last) && ((x = ISAd[*b]) <= v);) { + if(x == v) { SWAP(*b, *a); ++a; } + } + } + for(c = last; (b < --c) && ((x = ISAd[*c]) == v);) { } + if((b < (d = c)) && (x > v)) { + for(; (b < --c) && ((x = ISAd[*c]) >= v);) { + if(x == v) { SWAP(*c, *d); --d; } + } + } + for(; b < c;) { + SWAP(*b, *c); + for(; (++b < c) && ((x = ISAd[*b]) <= v);) { + if(x == v) { SWAP(*b, *a); ++a; } + } + for(; (b < --c) && ((x = ISAd[*c]) >= v);) { + if(x == v) { SWAP(*c, *d); --d; } + } + } + + if(a <= d) { + c = b - 1; + if((s = a - first) > (t = b - a)) { s = t; } + for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } + if((s = d - c) > (t = last - d - 1)) { s = t; } + for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } + first += (b - a), last -= (d - c); + } + *pa = first, *pb = last; +} + +static +void +tr_copy(int *ISA, const int *SA, + int *first, int *a, int *b, int *last, + int depth) { + /* sort suffixes of middle partition + by using sorted order of suffixes of left and right partition. */ + int *c, *d, *e; + int s, v; + + v = b - SA - 1; + for(c = first, d = a - 1; c <= d; ++c) { + if((0 <= (s = *c - depth)) && (ISA[s] == v)) { + *++d = s; + ISA[s] = d - SA; + } + } + for(c = last - 1, e = d + 1, d = b; e < d; --c) { + if((0 <= (s = *c - depth)) && (ISA[s] == v)) { + *--d = s; + ISA[s] = d - SA; + } + } +} + +static +void +tr_partialcopy(int *ISA, const int *SA, + int *first, int *a, int *b, int *last, + int depth) { + int *c, *d, *e; + int s, v; + int rank, lastrank, newrank = -1; + + v = b - SA - 1; + lastrank = -1; + for(c = first, d = a - 1; c <= d; ++c) { + if((0 <= (s = *c - depth)) && (ISA[s] == v)) { + *++d = s; + rank = ISA[s + depth]; + if(lastrank != rank) { lastrank = rank; newrank = d - SA; } + ISA[s] = newrank; + } + } + + lastrank = -1; + for(e = d; first <= e; --e) { + rank = ISA[*e]; + if(lastrank != rank) { lastrank = rank; newrank = e - SA; } + if(newrank != rank) { ISA[*e] = newrank; } + } + + lastrank = -1; + for(c = last - 1, e = d + 1, d = b; e < d; --c) { + if((0 <= (s = *c - depth)) && (ISA[s] == v)) { + *--d = s; + rank = ISA[s + depth]; + if(lastrank != rank) { lastrank = rank; newrank = d - SA; } + ISA[s] = newrank; + } + } +} + +static +void +tr_introsort(int *ISA, const int *ISAd, + int *SA, int *first, int *last, + trbudget_t *budget) { +#define STACK_SIZE TR_STACKSIZE + struct { const int *a; int *b, *c; int d, e; }stack[STACK_SIZE]; + int *a, *b, *c; + int t; + int v, x = 0; + int incr = ISAd - ISA; + int limit, next; + int ssize, trlink = -1; + + for(ssize = 0, limit = tr_ilg(last - first);;) { + + if(limit < 0) { + if(limit == -1) { + /* tandem repeat partition */ + tr_partition(ISAd - incr, first, first, last, &a, &b, last - SA - 1); + + /* update ranks */ + if(a < last) { + for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; } + } + if(b < last) { + for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; } + } + + /* push */ + if(1 < (b - a)) { + STACK_PUSH5(NULL, a, b, 0, 0); + STACK_PUSH5(ISAd - incr, first, last, -2, trlink); + trlink = ssize - 2; + } + if((a - first) <= (last - b)) { + if(1 < (a - first)) { + STACK_PUSH5(ISAd, b, last, tr_ilg(last - b), trlink); + last = a, limit = tr_ilg(a - first); + } else if(1 < (last - b)) { + first = b, limit = tr_ilg(last - b); + } else { + STACK_POP5(ISAd, first, last, limit, trlink); + } + } else { + if(1 < (last - b)) { + STACK_PUSH5(ISAd, first, a, tr_ilg(a - first), trlink); + first = b, limit = tr_ilg(last - b); + } else if(1 < (a - first)) { + last = a, limit = tr_ilg(a - first); + } else { + STACK_POP5(ISAd, first, last, limit, trlink); + } + } + } else if(limit == -2) { + /* tandem repeat copy */ + a = stack[--ssize].b, b = stack[ssize].c; + if(stack[ssize].d == 0) { + tr_copy(ISA, SA, first, a, b, last, ISAd - ISA); + } else { + if(0 <= trlink) { stack[trlink].d = -1; } + tr_partialcopy(ISA, SA, first, a, b, last, ISAd - ISA); + } + STACK_POP5(ISAd, first, last, limit, trlink); + } else { + /* sorted partition */ + if(0 <= *first) { + a = first; + do { ISA[*a] = a - SA; } while((++a < last) && (0 <= *a)); + first = a; + } + if(first < last) { + a = first; do { *a = ~*a; } while(*++a < 0); + next = (ISA[*a] != ISAd[*a]) ? tr_ilg(a - first + 1) : -1; + if(++a < last) { for(b = first, v = a - SA - 1; b < a; ++b) { ISA[*b] = v; } } + + /* push */ + if(trbudget_check(budget, a - first)) { + if((a - first) <= (last - a)) { + STACK_PUSH5(ISAd, a, last, -3, trlink); + ISAd += incr, last = a, limit = next; + } else { + if(1 < (last - a)) { + STACK_PUSH5(ISAd + incr, first, a, next, trlink); + first = a, limit = -3; + } else { + ISAd += incr, last = a, limit = next; + } + } + } else { + if(0 <= trlink) { stack[trlink].d = -1; } + if(1 < (last - a)) { + first = a, limit = -3; + } else { + STACK_POP5(ISAd, first, last, limit, trlink); + } + } + } else { + STACK_POP5(ISAd, first, last, limit, trlink); + } + } + continue; + } + + if((last - first) <= TR_INSERTIONSORT_THRESHOLD) { + tr_insertionsort(ISAd, first, last); + limit = -3; + continue; + } + + if(limit-- == 0) { + tr_heapsort(ISAd, first, last - first); + for(a = last - 1; first < a; a = b) { + for(x = ISAd[*a], b = a - 1; (first <= b) && (ISAd[*b] == x); --b) { *b = ~*b; } + } + limit = -3; + continue; + } + + /* choose pivot */ + a = tr_pivot(ISAd, first, last); + SWAP(*first, *a); + v = ISAd[*first]; + + /* partition */ + tr_partition(ISAd, first, first + 1, last, &a, &b, v); + if((last - first) != (b - a)) { + next = (ISA[*a] != v) ? tr_ilg(b - a) : -1; + + /* update ranks */ + for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; } + if(b < last) { for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; } } + + /* push */ + if((1 < (b - a)) && (trbudget_check(budget, b - a))) { + if((a - first) <= (last - b)) { + if((last - b) <= (b - a)) { + if(1 < (a - first)) { + STACK_PUSH5(ISAd + incr, a, b, next, trlink); + STACK_PUSH5(ISAd, b, last, limit, trlink); + last = a; + } else if(1 < (last - b)) { + STACK_PUSH5(ISAd + incr, a, b, next, trlink); + first = b; + } else { + ISAd += incr, first = a, last = b, limit = next; + } + } else if((a - first) <= (b - a)) { + if(1 < (a - first)) { + STACK_PUSH5(ISAd, b, last, limit, trlink); + STACK_PUSH5(ISAd + incr, a, b, next, trlink); + last = a; + } else { + STACK_PUSH5(ISAd, b, last, limit, trlink); + ISAd += incr, first = a, last = b, limit = next; + } + } else { + STACK_PUSH5(ISAd, b, last, limit, trlink); + STACK_PUSH5(ISAd, first, a, limit, trlink); + ISAd += incr, first = a, last = b, limit = next; + } + } else { + if((a - first) <= (b - a)) { + if(1 < (last - b)) { + STACK_PUSH5(ISAd + incr, a, b, next, trlink); + STACK_PUSH5(ISAd, first, a, limit, trlink); + first = b; + } else if(1 < (a - first)) { + STACK_PUSH5(ISAd + incr, a, b, next, trlink); + last = a; + } else { + ISAd += incr, first = a, last = b, limit = next; + } + } else if((last - b) <= (b - a)) { + if(1 < (last - b)) { + STACK_PUSH5(ISAd, first, a, limit, trlink); + STACK_PUSH5(ISAd + incr, a, b, next, trlink); + first = b; + } else { + STACK_PUSH5(ISAd, first, a, limit, trlink); + ISAd += incr, first = a, last = b, limit = next; + } + } else { + STACK_PUSH5(ISAd, first, a, limit, trlink); + STACK_PUSH5(ISAd, b, last, limit, trlink); + ISAd += incr, first = a, last = b, limit = next; + } + } + } else { + if((1 < (b - a)) && (0 <= trlink)) { stack[trlink].d = -1; } + if((a - first) <= (last - b)) { + if(1 < (a - first)) { + STACK_PUSH5(ISAd, b, last, limit, trlink); + last = a; + } else if(1 < (last - b)) { + first = b; + } else { + STACK_POP5(ISAd, first, last, limit, trlink); + } + } else { + if(1 < (last - b)) { + STACK_PUSH5(ISAd, first, a, limit, trlink); + first = b; + } else if(1 < (a - first)) { + last = a; + } else { + STACK_POP5(ISAd, first, last, limit, trlink); + } + } + } + } else { + if(trbudget_check(budget, last - first)) { + limit = tr_ilg(last - first), ISAd += incr; + } else { + if(0 <= trlink) { stack[trlink].d = -1; } + STACK_POP5(ISAd, first, last, limit, trlink); + } + } + } +#undef STACK_SIZE +} + + + +/*---------------------------------------------------------------------------*/ + +/* Tandem repeat sort */ +static +void +trsort(int *ISA, int *SA, int n, int depth) { + int *ISAd; + int *first, *last; + trbudget_t budget; + int t, skip, unsorted; + + trbudget_init(&budget, tr_ilg(n) * 2 / 3, n); +/* trbudget_init(&budget, tr_ilg(n) * 3 / 4, n); */ + for(ISAd = ISA + depth; -n < *SA; ISAd += ISAd - ISA) { + first = SA; + skip = 0; + unsorted = 0; + do { + if((t = *first) < 0) { first -= t; skip += t; } + else { + if(skip != 0) { *(first + skip) = skip; skip = 0; } + last = SA + ISA[t] + 1; + if(1 < (last - first)) { + budget.count = 0; + tr_introsort(ISA, ISAd, SA, first, last, &budget); + if(budget.count != 0) { unsorted += budget.count; } + else { skip = first - last; } + } else if((last - first) == 1) { + skip = -1; + } + first = last; + } + } while(first < (SA + n)); + if(skip != 0) { *(first + skip) = skip; } + if(unsorted == 0) { break; } + } +} + + +/*---------------------------------------------------------------------------*/ + +/* Sorts suffixes of type B*. */ +static +int +sort_typeBstar(const unsigned char *T, int *SA, + int *bucket_A, int *bucket_B, + int n, int openMP) { + int *PAb, *ISAb, *buf; +#ifdef LIBBSC_OPENMP + int *curbuf; + int l; +#endif + int i, j, k, t, m, bufsize; + int c0, c1; +#ifdef LIBBSC_OPENMP + int d0, d1; +#endif + (void)openMP; + + /* Initialize bucket arrays. */ + for(i = 0; i < BUCKET_A_SIZE; ++i) { bucket_A[i] = 0; } + for(i = 0; i < BUCKET_B_SIZE; ++i) { bucket_B[i] = 0; } + + /* Count the number of occurrences of the first one or two characters of each + type A, B and B* suffix. Moreover, store the beginning position of all + type B* suffixes into the array SA. */ + for(i = n - 1, m = n, c0 = T[n - 1]; 0 <= i;) { + /* type A suffix. */ + do { ++BUCKET_A(c1 = c0); } while((0 <= --i) && ((c0 = T[i]) >= c1)); + if(0 <= i) { + /* type B* suffix. */ + ++BUCKET_BSTAR(c0, c1); + SA[--m] = i; + /* type B suffix. */ + for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) { + ++BUCKET_B(c0, c1); + } + } + } + m = n - m; +/* +note: + A type B* suffix is lexicographically smaller than a type B suffix that + begins with the same first two characters. +*/ + + /* Calculate the index of start/end point of each bucket. */ + for(c0 = 0, i = 0, j = 0; c0 < ALPHABET_SIZE; ++c0) { + t = i + BUCKET_A(c0); + BUCKET_A(c0) = i + j; /* start point */ + i = t + BUCKET_B(c0, c0); + for(c1 = c0 + 1; c1 < ALPHABET_SIZE; ++c1) { + j += BUCKET_BSTAR(c0, c1); + BUCKET_BSTAR(c0, c1) = j; /* end point */ + i += BUCKET_B(c0, c1); + } + } + + if(0 < m) { + /* Sort the type B* suffixes by their first two characters. */ + PAb = SA + n - m; ISAb = SA + m; + for(i = m - 2; 0 <= i; --i) { + t = PAb[i], c0 = T[t], c1 = T[t + 1]; + SA[--BUCKET_BSTAR(c0, c1)] = i; + } + t = PAb[m - 1], c0 = T[t], c1 = T[t + 1]; + SA[--BUCKET_BSTAR(c0, c1)] = m - 1; + + /* Sort the type B* substrings using sssort. */ +#ifdef LIBBSC_OPENMP + if (openMP) + { + buf = SA + m; + c0 = ALPHABET_SIZE - 2, c1 = ALPHABET_SIZE - 1, j = m; +#pragma omp parallel default(shared) private(bufsize, curbuf, k, l, d0, d1) + { + bufsize = (n - (2 * m)) / omp_get_num_threads(); + curbuf = buf + omp_get_thread_num() * bufsize; + k = 0; + for(;;) { + #pragma omp critical(sssort_lock) + { + if(0 < (l = j)) { + d0 = c0, d1 = c1; + do { + k = BUCKET_BSTAR(d0, d1); + if(--d1 <= d0) { + d1 = ALPHABET_SIZE - 1; + if(--d0 < 0) { break; } + } + } while(((l - k) <= 1) && (0 < (l = k))); + c0 = d0, c1 = d1, j = k; + } + } + if(l == 0) { break; } + sssort(T, PAb, SA + k, SA + l, + curbuf, bufsize, 2, n, *(SA + k) == (m - 1)); + } + } + } + else + { + buf = SA + m, bufsize = n - (2 * m); + for(c0 = ALPHABET_SIZE - 2, j = m; 0 < j; --c0) { + for(c1 = ALPHABET_SIZE - 1; c0 < c1; j = i, --c1) { + i = BUCKET_BSTAR(c0, c1); + if(1 < (j - i)) { + sssort(T, PAb, SA + i, SA + j, + buf, bufsize, 2, n, *(SA + i) == (m - 1)); + } + } + } + } +#else + buf = SA + m, bufsize = n - (2 * m); + for(c0 = ALPHABET_SIZE - 2, j = m; 0 < j; --c0) { + for(c1 = ALPHABET_SIZE - 1; c0 < c1; j = i, --c1) { + i = BUCKET_BSTAR(c0, c1); + if(1 < (j - i)) { + sssort(T, PAb, SA + i, SA + j, + buf, bufsize, 2, n, *(SA + i) == (m - 1)); + } + } + } +#endif + + /* Compute ranks of type B* substrings. */ + for(i = m - 1; 0 <= i; --i) { + if(0 <= SA[i]) { + j = i; + do { ISAb[SA[i]] = i; } while((0 <= --i) && (0 <= SA[i])); + SA[i + 1] = i - j; + if(i <= 0) { break; } + } + j = i; + do { ISAb[SA[i] = ~SA[i]] = j; } while(SA[--i] < 0); + ISAb[SA[i]] = j; + } + + /* Construct the inverse suffix array of type B* suffixes using trsort. */ + trsort(ISAb, SA, m, 1); + + /* Set the sorted order of tyoe B* suffixes. */ + for(i = n - 1, j = m, c0 = T[n - 1]; 0 <= i;) { + for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) >= c1); --i, c1 = c0) { } + if(0 <= i) { + t = i; + for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) { } + SA[ISAb[--j]] = ((t == 0) || (1 < (t - i))) ? t : ~t; + } + } + + /* Calculate the index of start/end point of each bucket. */ + BUCKET_B(ALPHABET_SIZE - 1, ALPHABET_SIZE - 1) = n; /* end point */ + for(c0 = ALPHABET_SIZE - 2, k = m - 1; 0 <= c0; --c0) { + i = BUCKET_A(c0 + 1) - 1; + for(c1 = ALPHABET_SIZE - 1; c0 < c1; --c1) { + t = i - BUCKET_B(c0, c1); + BUCKET_B(c0, c1) = i; /* end point */ + + /* Move all type B* suffixes to the correct position. */ + for(i = t, j = BUCKET_BSTAR(c0, c1); + j <= k; + --i, --k) { SA[i] = SA[k]; } + } + BUCKET_BSTAR(c0, c0 + 1) = i - BUCKET_B(c0, c0) + 1; /* start point */ + BUCKET_B(c0, c0) = i; /* end point */ + } + } + + return m; +} + +/* Constructs the suffix array by using the sorted order of type B* suffixes. */ +static +void +construct_SA(const unsigned char *T, int *SA, + int *bucket_A, int *bucket_B, + int n, int m) { + int *i, *j, *k; + int s; + int c0, c1, c2; + + if(0 < m) { + /* Construct the sorted order of type B suffixes by using + the sorted order of type B* suffixes. */ + for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) { + /* Scan the suffix array from right to left. */ + for(i = SA + BUCKET_BSTAR(c1, c1 + 1), + j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1; + i <= j; + --j) { + if(0 < (s = *j)) { + assert(T[s] == c1); + assert(((s + 1) < n) && (T[s] <= T[s + 1])); + assert(T[s - 1] <= T[s]); + *j = ~s; + c0 = T[--s]; + if((0 < s) && (T[s - 1] > c0)) { s = ~s; } + if(c0 != c2) { + if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; } + k = SA + BUCKET_B(c2 = c0, c1); + } + assert(k < j); + *k-- = s; + } else { + assert(((s == 0) && (T[s] == c1)) || (s < 0)); + *j = ~s; + } + } + } + } + + /* Construct the suffix array by using + the sorted order of type B suffixes. */ + k = SA + BUCKET_A(c2 = T[n - 1]); + *k++ = (T[n - 2] < c2) ? ~(n - 1) : (n - 1); + /* Scan the suffix array from left to right. */ + for(i = SA, j = SA + n; i < j; ++i) { + if(0 < (s = *i)) { + assert(T[s - 1] >= T[s]); + c0 = T[--s]; + if((s == 0) || (T[s - 1] < c0)) { s = ~s; } + if(c0 != c2) { + BUCKET_A(c2) = k - SA; + k = SA + BUCKET_A(c2 = c0); + } + assert(i < k); + *k++ = s; + } else { + assert(s < 0); + *i = ~s; + } + } +} + +/* Constructs the burrows-wheeler transformed string directly + by using the sorted order of type B* suffixes. */ +static +int +construct_BWT(const unsigned char *T, int *SA, + int *bucket_A, int *bucket_B, + int n, int m) { + int *i, *j, *k, *orig; + int s; + int c0, c1, c2; + + if(0 < m) { + /* Construct the sorted order of type B suffixes by using + the sorted order of type B* suffixes. */ + for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) { + /* Scan the suffix array from right to left. */ + for(i = SA + BUCKET_BSTAR(c1, c1 + 1), + j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1; + i <= j; + --j) { + if(0 < (s = *j)) { + assert(T[s] == c1); + assert(((s + 1) < n) && (T[s] <= T[s + 1])); + assert(T[s - 1] <= T[s]); + c0 = T[--s]; + *j = ~((int)c0); + if((0 < s) && (T[s - 1] > c0)) { s = ~s; } + if(c0 != c2) { + if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; } + k = SA + BUCKET_B(c2 = c0, c1); + } + assert(k < j); + *k-- = s; + } else if(s != 0) { + *j = ~s; +#ifndef NDEBUG + } else { + assert(T[s] == c1); +#endif + } + } + } + } + + /* Construct the BWTed string by using + the sorted order of type B suffixes. */ + k = SA + BUCKET_A(c2 = T[n - 1]); + *k++ = (T[n - 2] < c2) ? ~((int)T[n - 2]) : (n - 1); + /* Scan the suffix array from left to right. */ + for(i = SA, j = SA + n, orig = SA; i < j; ++i) { + if(0 < (s = *i)) { + assert(T[s - 1] >= T[s]); + c0 = T[--s]; + *i = c0; + if((0 < s) && (T[s - 1] < c0)) { s = ~((int)T[s - 1]); } + if(c0 != c2) { + BUCKET_A(c2) = k - SA; + k = SA + BUCKET_A(c2 = c0); + } + assert(i < k); + *k++ = s; + } else if(s != 0) { + *i = ~s; + } else { + orig = i; + } + } + + return orig - SA; +} + +/* Constructs the burrows-wheeler transformed string directly + by using the sorted order of type B* suffixes. */ +static +int +construct_BWT_indexes(const unsigned char *T, int *SA, + int *bucket_A, int *bucket_B, + int n, int m, + unsigned char * num_indexes, int * indexes) { + int *i, *j, *k, *orig; + int s; + int c0, c1, c2; + + int mod = n / 8; + { + mod |= mod >> 1; mod |= mod >> 2; + mod |= mod >> 4; mod |= mod >> 8; + mod |= mod >> 16; mod >>= 1; + + *num_indexes = (unsigned char)((n - 1) / (mod + 1)); + } + + if(0 < m) { + /* Construct the sorted order of type B suffixes by using + the sorted order of type B* suffixes. */ + for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) { + /* Scan the suffix array from right to left. */ + for(i = SA + BUCKET_BSTAR(c1, c1 + 1), + j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1; + i <= j; + --j) { + if(0 < (s = *j)) { + assert(T[s] == c1); + assert(((s + 1) < n) && (T[s] <= T[s + 1])); + assert(T[s - 1] <= T[s]); + + if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = j - SA; + + c0 = T[--s]; + *j = ~((int)c0); + if((0 < s) && (T[s - 1] > c0)) { s = ~s; } + if(c0 != c2) { + if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; } + k = SA + BUCKET_B(c2 = c0, c1); + } + assert(k < j); + *k-- = s; + } else if(s != 0) { + *j = ~s; +#ifndef NDEBUG + } else { + assert(T[s] == c1); +#endif + } + } + } + } + + /* Construct the BWTed string by using + the sorted order of type B suffixes. */ + k = SA + BUCKET_A(c2 = T[n - 1]); + if (T[n - 2] < c2) { + if (((n - 1) & mod) == 0) indexes[(n - 1) / (mod + 1) - 1] = k - SA; + *k++ = ~((int)T[n - 2]); + } + else { + *k++ = n - 1; + } + + /* Scan the suffix array from left to right. */ + for(i = SA, j = SA + n, orig = SA; i < j; ++i) { + if(0 < (s = *i)) { + assert(T[s - 1] >= T[s]); + + if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = i - SA; + + c0 = T[--s]; + *i = c0; + if(c0 != c2) { + BUCKET_A(c2) = k - SA; + k = SA + BUCKET_A(c2 = c0); + } + assert(i < k); + if((0 < s) && (T[s - 1] < c0)) { + if ((s & mod) == 0) indexes[s / (mod + 1) - 1] = k - SA; + *k++ = ~((int)T[s - 1]); + } else + *k++ = s; + } else if(s != 0) { + *i = ~s; + } else { + orig = i; + } + } + + return orig - SA; +} + + +/*---------------------------------------------------------------------------*/ + +/*- Function -*/ + +int +divsufsort(const unsigned char *T, int *SA, int n, int openMP) { + int *bucket_A, *bucket_B; + int m; + int err = 0; + + /* Check arguments. */ + if((T == NULL) || (SA == NULL) || (n < 0)) { return -1; } + else if(n == 0) { return 0; } + else if(n == 1) { SA[0] = 0; return 0; } + else if(n == 2) { m = (T[0] < T[1]); SA[m ^ 1] = 0, SA[m] = 1; return 0; } + + bucket_A = (int *)malloc(BUCKET_A_SIZE * sizeof(int)); + bucket_B = (int *)malloc(BUCKET_B_SIZE * sizeof(int)); + + /* Suffixsort. */ + if((bucket_A != NULL) && (bucket_B != NULL)) { + m = sort_typeBstar(T, SA, bucket_A, bucket_B, n, openMP); + construct_SA(T, SA, bucket_A, bucket_B, n, m); + } else { + err = -2; + } + + free(bucket_B); + free(bucket_A); + + return err; +} + +int +divbwt(const unsigned char *T, unsigned char *U, int *A, int n, unsigned char * num_indexes, int * indexes, int openMP) { + int *B; + int *bucket_A, *bucket_B; + int m, pidx, i; + + /* Check arguments. */ + if((T == NULL) || (U == NULL) || (n < 0)) { return -1; } + else if(n <= 1) { if(n == 1) { U[0] = T[0]; } return n; } + + if((B = A) == NULL) { B = (int *)malloc((size_t)(n + 1) * sizeof(int)); } + bucket_A = (int *)malloc(BUCKET_A_SIZE * sizeof(int)); + bucket_B = (int *)malloc(BUCKET_B_SIZE * sizeof(int)); + + /* Burrows-Wheeler Transform. */ + if((B != NULL) && (bucket_A != NULL) && (bucket_B != NULL)) { + m = sort_typeBstar(T, B, bucket_A, bucket_B, n, openMP); + + if (num_indexes == NULL || indexes == NULL) { + pidx = construct_BWT(T, B, bucket_A, bucket_B, n, m); + } else { + pidx = construct_BWT_indexes(T, B, bucket_A, bucket_B, n, m, num_indexes, indexes); + } + + /* Copy to output string. */ + U[0] = T[n - 1]; + for(i = 0; i < pidx; ++i) { U[i + 1] = (unsigned char)B[i]; } + for(i += 1; i < n; ++i) { U[i] = (unsigned char)B[i]; } + pidx += 1; + } else { + pidx = -2; + } + + free(bucket_B); + free(bucket_A); + if(A == NULL) { free(B); } + + return pidx; +} diff --git a/dictBuilder/config.h b/lib/divsufsort.h similarity index 52% rename from dictBuilder/config.h rename to lib/divsufsort.h index c2925d335..dac093669 100644 --- a/dictBuilder/config.h +++ b/lib/divsufsort.h @@ -1,5 +1,5 @@ /* - * config.h for libdivsufsort + * divsufsort.h for libdivsufsort-lite * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved. * * Permission is hereby granted, free of charge, to any person @@ -24,60 +24,44 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef _CONFIG_H -#define _CONFIG_H 1 +#ifndef _DIVSUFSORT_H +#define _DIVSUFSORT_H 1 #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -/** Define to the version of this package. **/ -#define PROJECT_VERSION_FULL "2.0.1" -/** Define to 1 if you have the header files. **/ -#define HAVE_INTTYPES_H 1 -#define HAVE_STDDEF_H 1 -#define HAVE_STDINT_H 1 -#define HAVE_STDLIB_H 1 -#define HAVE_STRING_H 1 -#define HAVE_STRINGS_H 1 -#define HAVE_MEMORY_H 1 -#define HAVE_SYS_TYPES_H 1 +/*- Prototypes -*/ -/** for WinIO **/ -/* #undef HAVE_IO_H */ -/* #undef HAVE_FCNTL_H */ -/* #undef HAVE__SETMODE */ -/* #undef HAVE_SETMODE */ -/* #undef HAVE__FILENO */ -/* #undef HAVE_FOPEN_S */ -/* #undef HAVE__O_BINARY */ -/* -#ifndef HAVE__SETMODE -# if HAVE_SETMODE -# define _setmode setmode -# define HAVE__SETMODE 1 -# endif -# if HAVE__SETMODE && !HAVE__O_BINARY -# define _O_BINARY 0 -# define HAVE__O_BINARY 1 -# endif -#endif -*/ +/** + * Constructs the suffix array of a given string. + * @param T[0..n-1] The input string. + * @param SA[0..n-1] The output array of suffixes. + * @param n The length of the given string. + * @param openMP enables OpenMP optimization. + * @return 0 if no error occurred, -1 or -2 otherwise. + */ +int +divsufsort(const unsigned char *T, int *SA, int n, int openMP); -/** for inline **/ -#ifndef INLINE -# define INLINE inline -#endif - -/** for VC++ warning **/ -#ifdef _MSC_VER -#pragma warning(disable: 4127) -#endif +/** + * Constructs the burrows-wheeler transformed string of a given string. + * @param T[0..n-1] The input string. + * @param U[0..n-1] The output string. (can be T) + * @param A[0..n-1] The temporary array. (can be NULL) + * @param n The length of the given string. + * @param num_indexes The length of secondary indexes array. (can be NULL) + * @param indexes The secondary indexes array. (can be NULL) + * @param openMP enables OpenMP optimization. + * @return The primary index if no error occurred, -1 or -2 otherwise. + */ +int +divbwt(const unsigned char *T, unsigned char *U, int *A, int n, unsigned char * num_indexes, int * indexes, int openMP); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ -#endif /* _CONFIG_H */ +#endif /* _DIVSUFSORT_H */ diff --git a/lib/mem.h b/lib/mem.h index a6606e51d..0e357e530 100644 --- a/lib/mem.h +++ b/lib/mem.h @@ -119,11 +119,12 @@ MEM_STATIC unsigned MEM_isLittleEndian(void) #if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2) -/* violates C standard on structure alignment. +/* violates C standard, by lying on structure alignment. Only use if no other choice to achieve best performance on target platform */ MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; } MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; } MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; } +MEM_STATIC U64 MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; } MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; } MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; } @@ -133,11 +134,12 @@ MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; } /* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ /* currently only defined for gcc and icc */ -typedef union { U16 u16; U32 u32; U64 u64; } __attribute__((packed)) unalign; +typedef union { U16 u16; U32 u32; U64 u64; size_t st; } __attribute__((packed)) unalign; MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; } MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; } +MEM_STATIC U64 MEM_readST(const void* ptr) { return ((const unalign*)ptr)->st; } MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; } MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; } @@ -163,6 +165,11 @@ MEM_STATIC U64 MEM_read64(const void* memPtr) U64 val; memcpy(&val, memPtr, sizeof(val)); return val; } +MEM_STATIC size_t MEM_readST(const void* memPtr) +{ + size_t val; memcpy(&val, memPtr, sizeof(val)); return val; +} + MEM_STATIC void MEM_write16(void* memPtr, U16 value) { memcpy(memPtr, &value, sizeof(value)); diff --git a/lib/zstd.h b/lib/zstd.h index ce56c6351..53ed69739 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -61,7 +61,7 @@ extern "C" { ***************************************/ #define ZSTD_VERSION_MAJOR 0 /* for breaking interface changes */ #define ZSTD_VERSION_MINOR 5 /* for new (non-breaking) interface capabilities */ -#define ZSTD_VERSION_RELEASE 0 /* for tweaks, bug-fixes, or development */ +#define ZSTD_VERSION_RELEASE 1 /* for tweaks, bug-fixes, or development */ #define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE) ZSTDLIB_API unsigned ZSTD_versionNumber (void); diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 39e996c2d..83337b901 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -48,7 +48,7 @@ #endif -/* ************************************* +/*-************************************* * Dependencies ***************************************/ #include /* malloc */ @@ -59,46 +59,21 @@ #include "zstd_internal.h" -/* ************************************* +/*-************************************* * Constants ***************************************/ static const U32 g_searchStrength = 8; -/* ************************************* +/*-************************************* * Helper functions ***************************************/ size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; } -/* ************************************* +/*-************************************* * Sequence storage ***************************************/ -typedef struct { - void* buffer; - U32* offsetStart; - U32* offset; - BYTE* offCodeStart; - BYTE* offCode; - BYTE* litStart; - BYTE* lit; - BYTE* litLengthStart; - BYTE* litLength; - BYTE* matchLengthStart; - BYTE* matchLength; - BYTE* dumpsStart; - BYTE* dumps; - /* opt */ - U32* matchLengthFreq; - U32* litLengthFreq; - U32* litFreq; - U32* offCodeFreq; - U32 matchLengthSum; - U32 litLengthSum; - U32 litSum; - U32 offCodeSum; -} seqStore_t; - static void ZSTD_resetFreqs(seqStore_t* ssPtr) { unsigned u; @@ -129,7 +104,7 @@ static void ZSTD_resetSeqStore(seqStore_t* ssPtr) } -/* ************************************* +/*-************************************* * Context memory management ***************************************/ struct ZSTD_CCtx_s @@ -159,7 +134,6 @@ struct ZSTD_CCtx_s FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)]; }; - ZSTD_CCtx* ZSTD_createCCtx(void) { return (ZSTD_CCtx*) calloc(1, sizeof(ZSTD_CCtx)); @@ -172,14 +146,19 @@ size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) return 0; /* reserved as a potential error code in the future */ } +seqStore_t ZSTD_copySeqStore(const ZSTD_CCtx* ctx) +{ + return ctx->seqStore; +} + static unsigned ZSTD_highbit(U32 val); #define CLAMP(val,min,max) { if (valmax) val=max; } -/** ZSTD_validateParams() - correct params value to remain within authorized range - optimize for srcSize if srcSize > 0 */ +/** ZSTD_validateParams() : + correct params value to remain within authorized range, + optimize for `srcSize` if srcSize > 0 */ void ZSTD_validateParams(ZSTD_parameters* params) { const U32 btPlus = (params->strategy == ZSTD_btlazy2) || (params->strategy == ZSTD_opt_bt); @@ -800,33 +779,9 @@ MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const B } -/* ************************************* +/*-************************************* * Match length counter ***************************************/ -static size_t ZSTD_read_ARCH(const void* p) { size_t r; memcpy(&r, p, sizeof(r)); return r; } - -static unsigned ZSTD_highbit(U32 val) -{ -# if defined(_MSC_VER) /* Visual */ - unsigned long r=0; - _BitScanReverse(&r, val); - return (unsigned)r; -# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */ - return 31 - __builtin_clz(val); -# else /* Software version */ - static const int DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; - U32 v = val; - int r; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - r = DeBruijnClz[(U32)(v * 0x07C4ACDDU) >> 27]; - return r; -# endif -} - static unsigned ZSTD_NbCommonBytes (register size_t val) { if (MEM_isLittleEndian()) { @@ -891,12 +846,11 @@ static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLim const BYTE* const pStart = pIn; while ((pIn(b) ? (a) : (b)) -/* ************************************* +/*-************************************* * Common constants ***************************************/ #define ZSTD_MAGICNUMBER 0xFD2FB525 /* v0.5 */ @@ -130,9 +126,58 @@ MEM_STATIC void ZSTD_wildcopy(void* dst, const void* src, size_t length) while (op < oend); } - -#if defined (__cplusplus) +MEM_STATIC unsigned ZSTD_highbit(U32 val) +{ +# if defined(_MSC_VER) /* Visual */ + unsigned long r=0; + _BitScanReverse(&r, val); + return (unsigned)r; +# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */ + return 31 - __builtin_clz(val); +# else /* Software version */ + static const int DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; + U32 v = val; + int r; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + r = DeBruijnClz[(U32)(v * 0x07C4ACDDU) >> 27]; + return r; +# endif } -#endif + + +/*-******************************************* +* Private interfaces +*********************************************/ +typedef struct { + void* buffer; + U32* offsetStart; + U32* offset; + BYTE* offCodeStart; + BYTE* offCode; + BYTE* litStart; + BYTE* lit; + BYTE* litLengthStart; + BYTE* litLength; + BYTE* matchLengthStart; + BYTE* matchLength; + BYTE* dumpsStart; + BYTE* dumps; + /* opt */ + U32* matchLengthFreq; + U32* litLengthFreq; + U32* litFreq; + U32* offCodeFreq; + U32 matchLengthSum; + U32 litLengthSum; + U32 litSum; + U32 offCodeSum; +} seqStore_t; + +seqStore_t ZSTD_copySeqStore(const ZSTD_CCtx* ctx); + #endif /* ZSTD_CCOMMON_H_MODULE */ diff --git a/lib/zstd_static.h b/lib/zstd_static.h index f31e63a28..f695ccc06 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -205,7 +205,7 @@ ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t ds * Block functions ****************************************/ /*! Block functions produce and decode raw zstd blocks, without frame metadata. - User will have to save and regenerate necessary information to regenerate data, such as block sizes. + User will have to take in charge required information to regenerate data, such as block sizes. A few rules to respect : - Uncompressed block size must be <= 128 KB @@ -222,18 +222,17 @@ ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t ds + ZSTD_decompressBlock() doesn't accept uncompressed data as input !! */ - size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); -/* ************************************* +/*-************************************* * Error management ***************************************/ #include "error_public.h" /*! ZSTD_getErrorCode() : convert a `size_t` function result into a `ZSTD_error_code` enum type, - which can be used to compare directly with enum list within "error_public.h" */ + which can be used to compare directly with enum list published into "error_public.h" */ ZSTD_ErrorCode ZSTD_getError(size_t code); From fb92a78ac1d82e5d002d4b69d9d42867d34fa555 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 12 Feb 2016 00:32:38 +0100 Subject: [PATCH 081/113] Fixed clang warnings --- dictBuilder/dibio.c | 6 ------ lib/dictBuilder.c | 2 -- lib/divsufsort.c | 7 +++++++ 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/dictBuilder/dibio.c b/dictBuilder/dibio.c index 679b6504c..a471d5450 100644 --- a/dictBuilder/dibio.c +++ b/dictBuilder/dibio.c @@ -77,12 +77,6 @@ static const size_t maxMemory = (sizeof(size_t) == 4) ? (2 GB - 64 MB) : ((size_ #define PRIME1 2654435761U #define PRIME2 2246822519U -#define MINRATIO 4 -static const U32 g_compressionLevel_default = 5; -static const U32 g_selectivity_default = 9; -static const size_t g_provision_entropySize = 200; -static const size_t g_min_fast_dictContent = 192; - /*-************************************* * Console display diff --git a/lib/dictBuilder.c b/lib/dictBuilder.c index ede3b3d2a..fe40bea46 100644 --- a/lib/dictBuilder.c +++ b/lib/dictBuilder.c @@ -84,8 +84,6 @@ #define GB *(1U<<30) #define DICTLISTSIZE 10000 -#define MEMMULT 11 -static const size_t maxMemory = (sizeof(size_t) == 4) ? (2 GB - 64 MB) : ((size_t)(512 MB) << sizeof(size_t)); #define NOISELENGTH 32 #define PRIME1 2654435761U diff --git a/lib/divsufsort.c b/lib/divsufsort.c index ca790574a..9f45df590 100644 --- a/lib/divsufsort.c +++ b/lib/divsufsort.c @@ -24,10 +24,17 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +/*- Compiler specifics -*/ +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif + #if defined(_MSC_VER) #pragma warning(disable : 4244) #endif + +/*- Dependencies -*/ #include #include #include From 71eafdd23f8fd1f81ef4ea50063da992fe1874ed Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 12 Feb 2016 02:31:57 +0100 Subject: [PATCH 082/113] Integrated dictionary builder into zstd cli --- lib/dictBuilder.c | 94 ++++++++++------ programs/Makefile | 20 ++-- programs/dibio.c | 275 +++++++++++++++++++++++++++++++++++++++++++++ programs/dibio.h | 63 +++++++++++ programs/zstdcli.c | 192 ++++++++++++++++--------------- 5 files changed, 506 insertions(+), 138 deletions(-) create mode 100644 programs/dibio.c create mode 100644 programs/dibio.h diff --git a/lib/dictBuilder.c b/lib/dictBuilder.c index fe40bea46..50b67d58d 100644 --- a/lib/dictBuilder.c +++ b/lib/dictBuilder.c @@ -28,7 +28,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - Zstd source repository : https://www.zstd.net + - Zstd homepage : https://www.zstd.net */ /*-************************************** @@ -124,23 +124,6 @@ void ZDICT_printHex(U32 dlevel, const void* ptr, size_t length) } -/*-************************************* -* Exceptions -***************************************/ -#ifndef DEBUG -# define DEBUG 0 -#endif -#define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__); -#define EXM_THROW(error, ...) \ -{ \ - DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \ - DISPLAYLEVEL(1, "Error %i : ", error); \ - DISPLAYLEVEL(1, __VA_ARGS__); \ - DISPLAYLEVEL(1, "\n"); \ - exit(error); \ -} - - /*-******************************************************** * Helper functions **********************************************************/ @@ -516,7 +499,7 @@ static U32 ZDICT_dictSize(const dictItem* dictList) } -static void ZDICT_trainBuffer(dictItem* dictList, U32 dictListSize, +static size_t ZDICT_trainBuffer(dictItem* dictList, U32 dictListSize, const void* const buffer, const size_t bufferSize, /* buffer must end with noisy guard band */ const size_t* fileSizes, unsigned nbFiles, U32 shiftRatio, unsigned maxDictSize) @@ -528,18 +511,21 @@ static void ZDICT_trainBuffer(dictItem* dictList, U32 dictListSize, U32* filePos = (U32*)malloc(nbFiles * sizeof(*filePos)); U32 minRatio = nbFiles >> shiftRatio; int divSuftSortResult; + size_t result = 0; /* init */ DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */ - if (!suffix0 || !reverseSuffix || !doneMarks || !filePos) - EXM_THROW(1, "not enough memory for ZDICT_trainBuffer"); + if (!suffix0 || !reverseSuffix || !doneMarks || !filePos) { + result = ERROR(memory_allocation); + goto _cleanup; + } if (minRatio < MINRATIO) minRatio = MINRATIO; memset(doneMarks, 0, bufferSize+16); /* sort */ DISPLAYLEVEL(2, "sorting %u files of total size %u MB ...\n", nbFiles, (U32)(bufferSize>>20)); divSuftSortResult = divsufsort((const unsigned char*)buffer, suffix, (int)bufferSize, 0); - if (divSuftSortResult != 0) EXM_THROW(2, "sort failed"); + if (divSuftSortResult != 0) { result = ERROR(GENERIC); goto _cleanup; } suffix[bufferSize] = (int)bufferSize; /* leads into noise */ suffix0[0] = (int)bufferSize; /* leads into noise */ { @@ -578,10 +564,12 @@ static void ZDICT_trainBuffer(dictItem* dictList, U32 dictListSize, dictList->pos = n; } +_cleanup: free(suffix0); free(reverseSuffix); free(doneMarks); free(filePos); + return result; } @@ -661,7 +649,11 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, esr.ref = ZSTD_createCCtx(); esr.zc = ZSTD_createCCtx(); esr.workPlace = malloc(BLOCKSIZE); - if (!esr.ref || !esr.zc || !esr.workPlace) EXM_THROW(30, "Not enough memory"); + if (!esr.ref || !esr.zc || !esr.workPlace) { + eSize = ERROR(memory_allocation); + DISPLAYLEVEL(1, "Not enough memory"); + goto _cleanup; + } if (compressionLevel==0) compressionLevel=g_compressionLevel_default; params = ZSTD_getParams(compressionLevel, dictBufferSize + 15 KB); params.strategy = ZSTD_greedy; @@ -677,50 +669,82 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, /* analyze */ errorCode = HUF_buildCTable (hufTable, countLit, 255, huffLog); - if (HUF_isError(errorCode)) EXM_THROW(31, "HUF_buildCTable error"); + if (HUF_isError(errorCode)) { + eSize = ERROR(GENERIC); + DISPLAYLEVEL(1, "HUF_buildCTable error"); + goto _cleanup; + } huffLog = (U32)errorCode; total=0; for (u=0; u<=OFFCODE_MAX; u++) total+=offcodeCount[u]; errorCode = FSE_normalizeCount(offcodeNCount, Offlog, offcodeCount, total, OFFCODE_MAX); - if (FSE_isError(errorCode)) EXM_THROW(32, "FSE_normalizeCount error with offcodeCount"); + if (FSE_isError(errorCode)) { + eSize = ERROR(GENERIC); + DISPLAYLEVEL(1, "FSE_normalizeCount error with offcodeCount"); + goto _cleanup; + } Offlog = (U32)errorCode; total=0; for (u=0; u<=MaxML; u++) total+=matchLengthCount[u]; errorCode = FSE_normalizeCount(matchLengthNCount, mlLog, matchLengthCount, total, MaxML); - if (FSE_isError(errorCode)) EXM_THROW(33, "FSE_normalizeCount error with matchLengthCount"); + if (FSE_isError(errorCode)) { + eSize = ERROR(GENERIC); + DISPLAYLEVEL(1, "FSE_normalizeCount error with matchLengthCount"); + goto _cleanup; + } mlLog = (U32)errorCode; total=0; for (u=0; u<=MaxLL; u++) total+=litlengthCount[u]; errorCode = FSE_normalizeCount(litlengthNCount, llLog, litlengthCount, total, MaxLL); - if (FSE_isError(errorCode)) EXM_THROW(34, "FSE_normalizeCount error with litlengthCount"); + if (FSE_isError(errorCode)) { + eSize = ERROR(GENERIC); + DISPLAYLEVEL(1, "FSE_normalizeCount error with litlengthCount"); + goto _cleanup; + } llLog = (U32)errorCode; /* write result to buffer */ errorCode = HUF_writeCTable(dstBuffer, maxDstSize, hufTable, 255, huffLog); - if (HUF_isError(errorCode)) EXM_THROW(41, "HUF_writeCTable error"); + if (HUF_isError(errorCode)) { + eSize = ERROR(GENERIC); + DISPLAYLEVEL(1, "HUF_writeCTable error"); + goto _cleanup; + } dstBuffer = (char*)dstBuffer + errorCode; maxDstSize -= errorCode; eSize += errorCode; errorCode = FSE_writeNCount(dstBuffer, maxDstSize, offcodeNCount, OFFCODE_MAX, Offlog); - if (FSE_isError(errorCode)) EXM_THROW(42, "FSE_writeNCount error with offcodeNCount"); + if (FSE_isError(errorCode)) { + eSize = ERROR(GENERIC); + DISPLAYLEVEL(1, "FSE_writeNCount error with offcodeNCount"); + goto _cleanup; + } dstBuffer = (char*)dstBuffer + errorCode; maxDstSize -= errorCode; eSize += errorCode; errorCode = FSE_writeNCount(dstBuffer, maxDstSize, matchLengthNCount, MaxML, mlLog); - if (FSE_isError(errorCode)) EXM_THROW(43, "FSE_writeNCount error with matchLengthNCount"); + if (FSE_isError(errorCode)) { + eSize = ERROR(GENERIC); + DISPLAYLEVEL(1, "FSE_writeNCount error with matchLengthNCount"); + goto _cleanup; + } dstBuffer = (char*)dstBuffer + errorCode; maxDstSize -= errorCode; eSize += errorCode; errorCode = FSE_writeNCount(dstBuffer, maxDstSize, litlengthNCount, MaxLL, llLog); - if (FSE_isError(errorCode)) EXM_THROW(43, "FSE_writeNCount error with litlengthNCount"); + if (FSE_isError(errorCode)) { + eSize = ERROR(GENERIC); + DISPLAYLEVEL(1, "FSE_writeNCount error with litlengthNCount"); + goto _cleanup; + } dstBuffer = (char*)dstBuffer + errorCode; maxDstSize -= errorCode; eSize += errorCode; - /* clean */ +_cleanup: ZSTD_freeCCtx(esr.ref); ZSTD_freeCCtx(esr.zc); free(esr.workPlace); @@ -730,12 +754,12 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, #define DIB_FASTSEGMENTSIZE 64 -/*! ZDICT_fastSampling (based on an idea by Giuseppe Ottaviano) - Fill `dictBuffer` with stripes of size DIB_FASTSEGMENTSIZE from `samplesBuffer` +/*! ZDICT_fastSampling() (based on an idea proposed by Giuseppe Ottaviano) : + Fill `dictBuffer` with stripes of size DIB_FASTSEGMENTSIZE from `samplesBuffer`, up to `dictSize`. Filling starts from the end of `dictBuffer`, down to maximum possible. if `dictSize` is not a multiply of DIB_FASTSEGMENTSIZE, some bytes at beginning of `dictBuffer` won't be used. - @return : amount of data written into `dictBuffer` + @return : amount of data written into `dictBuffer`, or an error code */ static size_t ZDICT_fastSampling(void* dictBuffer, size_t dictSize, diff --git a/programs/Makefile b/programs/Makefile index a23b2f7f1..97da43997 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -53,7 +53,7 @@ BINDIR = $(PREFIX)/bin MANDIR = $(PREFIX)/share/man/man1 ZSTDDIR = ../lib -ZSTD_FILES := $(ZSTDDIR)/zstd_compress.c $(ZSTDDIR)/zstd_decompress.c $(ZSTDDIR)/fse.c $(ZSTDDIR)/huff0.c +ZSTD_FILES := $(ZSTDDIR)/zstd_compress.c $(ZSTDDIR)/zstd_decompress.c $(ZSTDDIR)/fse.c $(ZSTDDIR)/huff0.c ZSTD_LEGACY:= $(ZSTDDIR)/legacy/zstd_v01.c $(ZSTDDIR)/legacy/zstd_v02.c $(ZSTDDIR)/legacy/zstd_v03.c $(ZSTDDIR)/legacy/zstd_v04.c ifeq ($(ZSTD_LEGACY_SUPPORT), 0) @@ -84,12 +84,12 @@ default: zstd all: zstd zstd32 fullbench fullbench32 fuzzer fuzzer32 zbufftest zbufftest32 paramgrill datagen -zstd : $(ZSTD_FILES) $(ZSTDDIR)/zstd_buffered.c \ - zstdcli.c fileio.c $(ZSTD_FILEIO_LEGACY) bench.c xxhash.c datagen.c +zstd : $(ZSTD_FILES) $(ZSTDDIR)/zstd_buffered.c $(ZSTDDIR)/dictBuilder.c $(ZSTDDIR)/divsufsort.c \ + zstdcli.c fileio.c $(ZSTD_FILEIO_LEGACY) bench.c xxhash.c datagen.c dibio.c $(CC) $(FLAGS) $^ -o $@$(EXT) -zstd32: $(ZSTD_FILES) $(ZSTDDIR)/zstd_buffered.c \ - zstdcli.c fileio.c $(ZSTD_FILEIO_LEGACY) bench.c xxhash.c datagen.c +zstd32: $(ZSTD_FILES) $(ZSTDDIR)/zstd_buffered.c $(ZSTDDIR)/dictBuilder.c $(ZSTDDIR)/divsufsort.c \ + zstdcli.c fileio.c $(ZSTD_FILEIO_LEGACY) bench.c xxhash.c datagen.c dibio.c $(CC) -m32 $(FLAGS) $^ -o $@$(EXT) zstd_nolegacy : @@ -101,12 +101,12 @@ zstd-pgo : clean zstd rm zstd $(MAKE) zstd MOREFLAGS=-fprofile-use -zstd-noBench: $(ZSTD_FILES) $(ZSTDDIR)/zstd_buffered.c \ +zstd-frugal: $(ZSTD_FILES) $(ZSTDDIR)/zstd_buffered.c \ zstdcli.c fileio.c $(ZSTD_FILEIO_LEGACY) - $(CC) $(FLAGS) -DZSTD_NOBENCH $^ -o zstd$(EXT) + $(CC) $(FLAGS) -DZSTD_NOBENCH -DZSTD_NODICT $^ -o zstd$(EXT) -zstd-frugal: clean - $(MAKE) zstd-noBench ZSTD_LEGACY_SUPPORT=0 +zstd-small: clean + CFLAGS=-Os $(MAKE) zstd-frugal ZSTD_LEGACY_SUPPORT=0 fullbench : $(ZSTD_FILES) \ datagen.c fullbench.c @@ -140,7 +140,7 @@ datagen : datagen.c datagencli.c $(CC) $(FLAGS) $^ -o $@$(EXT) clean: - @rm -f core *.o tmp* result* *.gcda \ + @rm -f core *.o tmp* result* *.gcda dictionary *.zst \ zstd$(EXT) zstd32$(EXT) \ fullbench$(EXT) fullbench32$(EXT) \ fuzzer$(EXT) fuzzer32$(EXT) zbufftest$(EXT) zbufftest32$(EXT) \ diff --git a/programs/dibio.c b/programs/dibio.c new file mode 100644 index 000000000..a471d5450 --- /dev/null +++ b/programs/dibio.c @@ -0,0 +1,275 @@ +/* + dibio - I/O API for dictionary builder + Copyright (C) Yann Collet 2016 + + GPL v2 License + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + You can contact the author at : + - zstd homepage : http://www.zstd.net/ +*/ + +/*-************************************** +* Compiler Options +****************************************/ +/* Disable some Visual warning messages */ +#ifdef _MSC_VER +# define _CRT_SECURE_NO_WARNINGS /* fopen */ +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +#endif + +/* Unix Large Files support (>4GB) */ +#define _FILE_OFFSET_BITS 64 +#if (defined(__sun__) && (!defined(__LP64__))) /* Sun Solaris 32-bits requires specific definitions */ +# define _LARGEFILE_SOURCE +#elif ! defined(__LP64__) /* No point defining Large file for 64 bit */ +# define _LARGEFILE64_SOURCE +#endif + + +/*-************************************* +* Includes +***************************************/ +#include /* malloc, free */ +#include /* memset */ +#include /* fprintf, fopen, ftello64 */ +#include /* stat64 */ +#include /* stat64 */ +#include /* clock */ + +#include "mem.h" /* read */ +#include "error_private.h" +#include "dictBuilder_static.h" + +/*-************************************* +* Compiler specifics +***************************************/ +#if !defined(S_ISREG) +# define S_ISREG(x) (((x) & S_IFMT) == S_IFREG) +#endif + + +/*-************************************* +* Constants +***************************************/ +#define KB *(1 <<10) +#define MB *(1 <<20) +#define GB *(1U<<30) + +#define DICTLISTSIZE 10000 +#define MEMMULT 11 +static const size_t maxMemory = (sizeof(size_t) == 4) ? (2 GB - 64 MB) : ((size_t)(512 MB) << sizeof(size_t)); + +#define NOISELENGTH 32 +#define PRIME1 2654435761U +#define PRIME2 2246822519U + + +/*-************************************* +* Console display +***************************************/ +#define DISPLAY(...) fprintf(stderr, __VA_ARGS__) +#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } +static unsigned g_displayLevel = 0; /* 0 : no display; 1: errors; 2: default; 4: full information */ +void DiB_setNotificationLevel(unsigned l) { g_displayLevel=l; ZDICT_setNotificationLevel(l); } + +void DiB_printHex(U32 dlevel, const void* ptr, size_t length) +{ + const BYTE* const b = (const BYTE*)ptr; + size_t u; + for (u=0; u126) c = '.'; /* non-printable char */ + DISPLAYLEVEL(dlevel, "%c", c); + } +} + + +/*-************************************* +* Exceptions +***************************************/ +#ifndef DEBUG +# define DEBUG 0 +#endif +#define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__); +#define EXM_THROW(error, ...) \ +{ \ + DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \ + DISPLAYLEVEL(1, "Error %i : ", error); \ + DISPLAYLEVEL(1, __VA_ARGS__); \ + DISPLAYLEVEL(1, "\n"); \ + exit(error); \ +} + + +/* ******************************************************** +* Helper functions +**********************************************************/ +unsigned DiB_isError(size_t errorCode) { return ERR_isError(errorCode); } + +const char* DiB_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); } + + +/* ******************************************************** +* File related operations +**********************************************************/ +static unsigned long long DiB_getFileSize(const char* infilename) +{ + int r; +#if defined(_MSC_VER) + struct _stat64 statbuf; + r = _stat64(infilename, &statbuf); +#else + struct stat statbuf; + r = stat(infilename, &statbuf); +#endif + if (r || !S_ISREG(statbuf.st_mode)) return 0; /* No good... */ + return (unsigned long long)statbuf.st_size; +} + + +static unsigned long long DiB_getTotalFileSize(const char** fileNamesTable, unsigned nbFiles) +{ + unsigned long long total = 0; + unsigned n; + for (n=0; n bufferSize-pos) fileSize = 0; /* stop there, not enough memory to load all files */ + readSize = fread(buff+pos, 1, (size_t)fileSize, f); + if (readSize != (size_t)fileSize) EXM_THROW(11, "could not read %s", fileNamesTable[n]); + pos += readSize; + fileSizes[n] = (size_t)fileSize; + fclose(f); + } +} + + +/*-******************************************************** +* Dictionary training functions +**********************************************************/ +static size_t DiB_findMaxMem(unsigned long long requiredMem) +{ + size_t step = 8 MB; + void* testmem = NULL; + + requiredMem = (((requiredMem >> 23) + 1) << 23); + requiredMem += 2 * step; + if (requiredMem > maxMemory) requiredMem = maxMemory; + + while (!testmem) { + requiredMem -= step; + testmem = malloc((size_t)requiredMem); + } + + free(testmem); + return (size_t)(requiredMem - step); +} + + +static void DiB_fillNoise(void* buffer, size_t length) +{ + unsigned acc = PRIME1; + size_t p=0;; + + for (p=0; p> 21); + } +} + + +static void DiB_saveDict(const char* dictFileName, + const void* buff, size_t buffSize) +{ + FILE* f; + size_t n; + + f = fopen(dictFileName, "wb"); + if (f==NULL) EXM_THROW(3, "cannot open %s ", dictFileName); + + n = fwrite(buff, 1, buffSize, f); + if (n!=buffSize) EXM_THROW(4, "%s : write error", dictFileName) + + n = (size_t)fclose(f); + if (n!=0) EXM_THROW(5, "%s : flush error", dictFileName) +} + + +int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, + const char** fileNamesTable, unsigned nbFiles, + ZDICT_params_t params) +{ + void* srcBuffer; + size_t benchedSize; + size_t* fileSizes = (size_t*)malloc(nbFiles * sizeof(size_t)); + unsigned long long totalSizeToLoad = DiB_getTotalFileSize(fileNamesTable, nbFiles); + void* dictBuffer = malloc(maxDictSize); + size_t dictSize; + int result = 0; + + /* init */ + benchedSize = DiB_findMaxMem(totalSizeToLoad * MEMMULT) / MEMMULT; + if ((unsigned long long)benchedSize > totalSizeToLoad) benchedSize = (size_t)totalSizeToLoad; + if (benchedSize < totalSizeToLoad) + DISPLAYLEVEL(1, "Not enough memory; training on %u MB only...\n", (unsigned)(benchedSize >> 20)); + + /* Memory allocation & restrictions */ + srcBuffer = malloc(benchedSize+NOISELENGTH); /* + noise */ + if ((!fileSizes) || (!srcBuffer) || (!dictBuffer)) EXM_THROW(12, "not enough memory for DiB_trainFiles"); /* should not happen */ + + /* Load input buffer */ + DiB_loadFiles(srcBuffer, benchedSize, fileSizes, fileNamesTable, nbFiles); + DiB_fillNoise((char*)srcBuffer + benchedSize, NOISELENGTH); /* guard band, for end of buffer condition */ + + /* call buffer version */ + dictSize = ZDICT_trainFromBuffer_unsafe(dictBuffer, maxDictSize, + srcBuffer, fileSizes, nbFiles, + params); + if (ZDICT_isError(dictSize)) { + DISPLAYLEVEL(1, "dictionary training failed : %s", ZDICT_getErrorName(dictSize)); /* should not happen */ + result = 1; + goto _cleanup; + } + + /* save dict */ + DISPLAYLEVEL(2, "Save dictionary of size %u into file %s \n", (U32)dictSize, dictFileName); + DiB_saveDict(dictFileName, dictBuffer, dictSize); + + /* clean up */ +_cleanup: + free(srcBuffer); + free(dictBuffer); + free(fileSizes); + return result; +} diff --git a/programs/dibio.h b/programs/dibio.h new file mode 100644 index 000000000..9b8deb54b --- /dev/null +++ b/programs/dibio.h @@ -0,0 +1,63 @@ +/* + dibio.h - I/O API for dictionary builder + Copyright (C) Yann Collet 2016 + + GPL v2 License + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + You can contact the author at : + - zstd homepage : http://www.zstd.net/ +*/ + +/* This library is designed for a single-threaded console application. +* It exit() and printf() into stderr when it encounters an error condition. */ + +#ifndef DIBIO_H_003 +#define DIBIO_H_003 + + +/*-************************************* +* Dependencies +***************************************/ +#include "dictBuilder_static.h" /* ZDICT_params_t */ + + +/*-************************************* +* Public functions +***************************************/ +/*! DiB_trainFromFiles() : + Train a dictionary from a set of files provided by `fileNamesTable`. + Resulting dictionary is written into file `dictFileName`. + `parameters` is optional and can be provided with values set to 0, meaning "default". + @return : 0 == ok. Any other : error. +*/ +int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, + const char** fileNamesTable, unsigned nbFiles, + ZDICT_params_t parameters); + + +/*-************************************* +* Helper functions +***************************************/ +/*! DiB_setNotificationLevel + Set amount of notification to be displayed on the console. + default initial value : 0 = no console notification. + Note : not thread-safe (use a global constant) +*/ +void DiB_setNotificationLevel(unsigned l); + + +#endif diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 3f3c5cd51..21ec9ecd9 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -22,10 +22,9 @@ - zstd homepage : http://www.zstd.net/ */ /* - Note : this is user program. - It is not part of zstd compression library. - The license of this compression CLI program is GPLv2. - The license of zstd library is BSD. + Note : this is user program, not part of libzstd. + The license of this command line program is GPLv2. + The license of libzstd is BSD. */ @@ -46,7 +45,10 @@ #ifndef ZSTD_NOBENCH # include "bench.h" /* BMK_benchFiles, BMK_SetNbIterations */ #endif -#include "zstd.h" /* ZSTD version numbers */ +#include "zstd_static.h" /* ZSTD_maxCLevel, ZSTD version numbers */ +#ifndef ZSTD_NODICT +# include "dibio.h" /* BMK_benchFiles, BMK_SetNbIterations */ +#endif /*-************************************ @@ -55,9 +57,6 @@ #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) # include /* _O_BINARY */ # include /* _setmode, _isatty */ -# ifdef __MINGW32__ - /* int _fileno(FILE *stream); // seems no longer useful // MINGW somehow forgets to include this windows declaration into */ -# endif # define SET_BINARY_MODE(file) _setmode(_fileno(file), _O_BINARY) # define IS_CONSOLE(stdStream) _isatty(_fileno(stdStream)) #else @@ -78,6 +77,7 @@ #endif #define AUTHOR "Yann Collet" #define WELCOME_MESSAGE "*** %s %i-bits %s, by %s ***\n", COMPRESSOR_NAME, (int)(sizeof(void*)*8), ZSTD_VERSION, AUTHOR + #define ZSTD_EXTENSION ".zst" #define ZSTD_CAT "zstdcat" #define ZSTD_UNZSTD "unzstd" @@ -86,6 +86,11 @@ #define MB *(1 <<20) #define GB *(1U<<30) +static const char* g_defaultDictName = "dictionary"; +static const unsigned g_defaultMaxDictSize = 110 KB; +static const unsigned g_defaultDictCLevel = 5; +static const unsigned g_defaultSelectivityLevel = 9; + /*-************************************ * Display Macros @@ -96,35 +101,21 @@ static FILE* displayOut; static unsigned displayLevel = 2; /* 0 : no display, 1: errors, 2 : + result + interaction + warnings, 3 : + progression, 4 : + information */ -/*-************************************ -* Exceptions -**************************************/ -#define DEBUG 0 -#define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__); -#define EXM_THROW(error, ...) \ -{ \ - DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \ - DISPLAYLEVEL(1, "Error %i : ", error); \ - DISPLAYLEVEL(1, __VA_ARGS__); \ - DISPLAYLEVEL(1, "\n"); \ - exit(error); \ -} - - /*-************************************ * Command Line **************************************/ static int usage(const char* programName) { DISPLAY( "Usage :\n"); - DISPLAY( " %s [arg] [input] [output]\n", programName); + DISPLAY( " %s [args] [FILE(s)] [-o file]\n", programName); DISPLAY( "\n"); - DISPLAY( "input : a filename\n"); + DISPLAY( "FILE : a filename\n"); DISPLAY( " with no FILE, or when FILE is - , read standard input\n"); DISPLAY( "Arguments :\n"); - DISPLAY( " -# : # compression level (1-19, default:1) \n"); + DISPLAY( " -# : # compression level (1-%u, default:1) \n", ZSTD_maxCLevel()); DISPLAY( " -d : decompression \n"); DISPLAY( " -D file: use `file` as Dictionary \n"); + DISPLAY( " -o file: result stored into `file` (only possible if 1 input file) \n"); DISPLAY( " -f : overwrite output without prompting \n"); DISPLAY( " -h/-H : display help/long help and exit\n"); return 0; @@ -139,14 +130,20 @@ static int usage_advanced(const char* programName) DISPLAY( " -V : display Version number and exit\n"); DISPLAY( " -v : verbose mode\n"); DISPLAY( " -q : suppress warnings; specify twice to suppress errors too\n"); - DISPLAY( " -m : multiple input filenames mode \n"); DISPLAY( " -c : force write to standard output, even if it is the console\n"); +#ifndef ZSTD_NODICT + DISPLAY( "Dictionary builder :\n"); + DISPLAY( "--train : Create a dictionary from a set of files \n"); + DISPLAY( " -o file: `file` is dictionary name (default: %s) \n", g_defaultDictName); + DISPLAY( "--maxdict:limit dictionary to specified size (default : %u) \n", g_defaultMaxDictSize); + DISPLAY( " -s# : dictionary selectivity level (default: %u)\n", g_defaultSelectivityLevel); +#endif #ifndef ZSTD_NOBENCH DISPLAY( "Benchmark arguments :\n"); DISPLAY( " -b# : benchmark file(s), using # compression level (default : 1) \n"); - DISPLAY( " -B# : cut file into independent blocks of size # (default : no block)\n"); + DISPLAY( " -B# : cut file into independent blocks of size # (default: no block)\n"); DISPLAY( " -i# : iteration loops [1-9](default : 3)\n"); - DISPLAY( " -r# : test all compression levels from 1 to # (default : disabled)\n"); + DISPLAY( " -r# : test all compression levels from 1 to # (default: disabled)\n"); #endif return 0; } @@ -176,8 +173,10 @@ int main(int argCount, const char** argv) forceStdout=0, main_pause=0, nextEntryIsDictionary=0, - multiple=0, - operationResult=0; + operationResult=0, + dictBuild=0, + nextArgumentIsOutFileName=0, + nextArgumentIsMaxDict=0; unsigned cLevel = 1; const char** filenameTable = (const char**)malloc(argCount * sizeof(const char*)); /* argCount >= 1 */ unsigned filenameIdx = 0; @@ -185,11 +184,13 @@ int main(int argCount, const char** argv) const char* outFileName = NULL; const char* dictFileName = NULL; char* dynNameSpace = NULL; - const char extension[] = ZSTD_EXTENSION; int rangeBench = 1; + unsigned maxDictSize = g_defaultMaxDictSize; + unsigned dictCLevel = g_defaultDictCLevel; + unsigned dictSelect = g_defaultSelectivityLevel; /* init */ - (void)rangeBench; /* not used when ZSTD_NOBENCH set */ + (void)rangeBench; (void)dictCLevel; /* not used when ZSTD_NOBENCH / ZSTD_NODICT set */ if (filenameTable==NULL) { DISPLAY("not enough memory\n"); exit(1); } displayOut = stderr; /* Pick out program name from path. Don't rely on stdlib because of conflicting behavior */ @@ -208,32 +209,32 @@ int main(int argCount, const char** argv) /* long commands (--long-word) */ if (!strcmp(argument, "--version")) { displayOut=stdout; DISPLAY(WELCOME_MESSAGE); return 0; } if (!strcmp(argument, "--help")) { displayOut=stdout; return usage_advanced(programName); } - if (!strcmp(argument, "--multiple")) { multiple=1; continue; } if (!strcmp(argument, "--verbose")) { displayLevel=4; continue; } if (!strcmp(argument, "--quiet")) { displayLevel--; continue; } + if (!strcmp(argument, "--train")) { dictBuild=1; outFileName=g_defaultDictName; continue; } + if (!strcmp(argument, "--maxdict")) { nextArgumentIsMaxDict=1; continue; } + + /* '-' means stdin/stdout */ + if (!strcmp(argument, "-")){ + if (!filenameIdx) { filenameIdx=1, filenameTable[0]=stdinmark; continue; } + outFileName=stdoutmark; continue; + } /* Decode commands (note : aggregated commands are allowed) */ if (argument[0]=='-') { - /* '-' means stdin/stdout */ - if (argument[1]==0) { - if (!filenameIdx) { filenameIdx=1, filenameTable[0]=stdinmark; continue; } - outFileName=stdoutmark; continue; - } - argument++; - while (argument[0]!=0) - { + while (argument[0]!=0) { + /* compression Level */ - if ((*argument>='0') && (*argument<='9')) - { + if ((*argument>='0') && (*argument<='9')) { cLevel = 0; - while ((*argument >= '0') && (*argument <= '9')) - { + while ((*argument >= '0') && (*argument <= '9')) { cLevel *= 10; cLevel += *argument - '0'; argument++; } + dictCLevel = cLevel; continue; } @@ -247,9 +248,6 @@ int main(int argCount, const char** argv) /* Decoding */ case 'd': decode=1; argument++; break; - /* Multiple input files */ - case 'm': multiple=1; argument++; break; - /* Force stdout, even if stdout==console */ case 'c': forceStdout=1; outFileName=stdoutmark; displayLevel=1; argument++; break; @@ -268,6 +266,9 @@ int main(int argCount, const char** argv) /* keep source file (default anyway, so useless; for gzip/xz compatibility) */ case 'k': argument++; break; + /* dictionary name */ + case 'o': nextArgumentIsOutFileName=1; argument++; break; + #ifndef ZSTD_NOBENCH /* Benchmark */ case 'b': bench=1; argument++; break; @@ -304,6 +305,13 @@ int main(int argCount, const char** argv) break; #endif /* ZSTD_NOBENCH */ + /* Selection level */ + case 's': argument++; + dictSelect = 0; + while ((*argument >= '0') && (*argument <= '9')) + dictSelect *= 10, dictSelect += *argument++ - '0'; + break; + /* Pause at the end (hidden option) */ case 'p': main_pause=1; argument++; break; @@ -314,13 +322,29 @@ int main(int argCount, const char** argv) continue; } - /* dictionary */ if (nextEntryIsDictionary) { nextEntryIsDictionary = 0; dictFileName = argument; continue; } + if (nextArgumentIsOutFileName) { + nextArgumentIsOutFileName = 0; + outFileName = argument; + if (!strcmp(outFileName, "-")) outFileName = stdoutmark; + continue; + } + + if (nextArgumentIsMaxDict) { + nextArgumentIsMaxDict = 0; + maxDictSize = 0; + while ((*argument>='0') && (*argument<='9')) + maxDictSize = maxDictSize * 10 + (*argument - '0'), argument++; + if (*argument=='k' || *argument=='K') + maxDictSize <<= 10; + continue; + } + /* add filename to list */ filenameTable[filenameIdx++] = argument; } @@ -336,65 +360,47 @@ int main(int argCount, const char** argv) goto _end; } + /* Check if dictionary builder is selected */ + if (dictBuild) { +#ifndef ZSTD_NODICT + ZDICT_params_t dictParams; + dictParams.compressionLevel = dictCLevel; + dictParams.selectivityLevel = dictSelect; + DiB_setNotificationLevel(displayLevel); + DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, dictParams); +#endif + goto _end; + } + /* No input filename ==> use stdin */ if(!filenameIdx) filenameIdx=1, filenameTable[0]=stdinmark; - /* Check if input defined as console; trigger an error in this case */ + /* Check if input/output defined as console; trigger an error in this case */ if (!strcmp(filenameTable[0], stdinmark) && IS_CONSOLE(stdin) ) return badusage(programName); + if (outFileName && !strcmp(outFileName, stdoutmark) && IS_CONSOLE(stdout) && !forceStdout) return badusage(programName); - /* No output filename ==> try to select one automatically (when possible) */ - if (filenameIdx>=2) outFileName = filenameTable[1]; - while (!outFileName) { /* while : just to allow break statement */ - if (!IS_CONSOLE(stdout)) { outFileName=stdoutmark; break; } /* Default to stdout whenever possible (i.e. not a console) */ - if (!decode) { /* compression to file */ - size_t l = strlen(filenameTable[0]); - dynNameSpace = (char*)calloc(1,l+5); - if (dynNameSpace==NULL) { DISPLAY("not enough memory\n"); exit(1); } - strcpy(dynNameSpace, filenameTable[0]); - strcpy(dynNameSpace+l, ZSTD_EXTENSION); - outFileName = dynNameSpace; - DISPLAYLEVEL(2, "Compressed filename will be : %s \n", outFileName); - break; - } - /* decompression to file (automatic name will work only if input filename has correct format extension) */ - { - size_t filenameSize = strlen(filenameTable[0]); - if (strcmp(filenameTable[0] + (filenameSize-4), extension)) { - DISPLAYLEVEL(1, "unknown suffix - cannot determine destination filename\n"); - return badusage(programName); - } - dynNameSpace = (char*)calloc(1,filenameSize+1); - if (dynNameSpace==NULL) { DISPLAY("not enough memory\n"); exit(1); } - outFileName = dynNameSpace; - strcpy(dynNameSpace, filenameTable[0]); - dynNameSpace[filenameSize-4]=0; - DISPLAYLEVEL(2, "Decoding file %s \n", outFileName); - } } - - /* Check if output is defined as console; trigger an error in this case */ - if (!strcmp(outFileName,stdoutmark) && IS_CONSOLE(stdout) && !forceStdout) return badusage(programName); - - /* No warning message in pure pipe mode (stdin + stdout) or multiple mode */ + /* No warning message in pipe mode (stdin + stdout) or multiple mode */ if (!strcmp(filenameTable[0], stdinmark) && !strcmp(outFileName,stdoutmark) && (displayLevel==2)) displayLevel=1; - if (multiple && (displayLevel==2)) displayLevel=1; + if ((filenameIdx>1) && (displayLevel==2)) displayLevel=1; - if ((!multiple) && (filenameIdx>2)) { - DISPLAY("Too many files on the command line (%u > 2). Do you mean -m ? \n", filenameIdx); + /* user-selected output filename only possible with a single file */ + if ((outFileName) && (filenameIdx>1)) { + DISPLAY("Too many files (%u) on the command line. \n", filenameIdx); return filenameIdx; } /* IO Stream/File */ FIO_setNotificationLevel(displayLevel); if (decode) { - if (multiple) - operationResult = FIO_decompressMultipleFilenames(filenameTable, filenameIdx, ZSTD_EXTENSION, dictFileName); - else + if (outFileName) operationResult = FIO_decompressFilename(outFileName, filenameTable[0], dictFileName); + else + operationResult = FIO_decompressMultipleFilenames(filenameTable, filenameIdx, ZSTD_EXTENSION, dictFileName); } else { /* compression */ - if (multiple) - operationResult = FIO_compressMultipleFilenames(filenameTable, filenameIdx, ZSTD_EXTENSION, dictFileName, cLevel); - else + if (outFileName) operationResult = FIO_compressFilename(outFileName, filenameTable[0], dictFileName, cLevel); + else + operationResult = FIO_compressMultipleFilenames(filenameTable, filenameIdx, ZSTD_EXTENSION, dictFileName, cLevel); } _end: From c8da2c9f8f7ed6efeed7f21ea27cfe63a6bf164d Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 12 Feb 2016 02:56:27 +0100 Subject: [PATCH 083/113] updated tests --- programs/Makefile | 27 +++++++++++++-------------- programs/fileio.h | 4 ++-- programs/playTests.sh | 12 ++++++------ programs/zstdcli.c | 4 ++-- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/programs/Makefile b/programs/Makefile index 97da43997..2f67bb309 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -54,14 +54,14 @@ MANDIR = $(PREFIX)/share/man/man1 ZSTDDIR = ../lib ZSTD_FILES := $(ZSTDDIR)/zstd_compress.c $(ZSTDDIR)/zstd_decompress.c $(ZSTDDIR)/fse.c $(ZSTDDIR)/huff0.c -ZSTD_LEGACY:= $(ZSTDDIR)/legacy/zstd_v01.c $(ZSTDDIR)/legacy/zstd_v02.c $(ZSTDDIR)/legacy/zstd_v03.c $(ZSTDDIR)/legacy/zstd_v04.c ifeq ($(ZSTD_LEGACY_SUPPORT), 0) CPPFLAGS += -DZSTD_LEGACY_SUPPORT=0 +ZSTD_FILES_LEGACY:= else -ZSTD_FILES+= $(ZSTD_LEGACY) -CPPFLAGS += -I../lib/legacy -I./legacy -DZSTD_LEGACY_SUPPORT=1 -ZSTD_FILEIO_LEGACY = legacy/fileio_legacy.c +ZSTD_LEGACY_SUPPORT:=1 +CPPFLAGS += -I../lib/legacy -I./legacy +ZSTD_FILES_LEGACY:= $(ZSTDDIR)/legacy/zstd_v01.c $(ZSTDDIR)/legacy/zstd_v02.c $(ZSTDDIR)/legacy/zstd_v03.c $(ZSTDDIR)/legacy/zstd_v04.c legacy/fileio_legacy.c endif @@ -84,13 +84,13 @@ default: zstd all: zstd zstd32 fullbench fullbench32 fuzzer fuzzer32 zbufftest zbufftest32 paramgrill datagen -zstd : $(ZSTD_FILES) $(ZSTDDIR)/zstd_buffered.c $(ZSTDDIR)/dictBuilder.c $(ZSTDDIR)/divsufsort.c \ - zstdcli.c fileio.c $(ZSTD_FILEIO_LEGACY) bench.c xxhash.c datagen.c dibio.c - $(CC) $(FLAGS) $^ -o $@$(EXT) +zstd : $(ZSTD_FILES) $(ZSTD_FILES_LEGACY) $(ZSTDDIR)/zstd_buffered.c $(ZSTDDIR)/dictBuilder.c $(ZSTDDIR)/divsufsort.c \ + zstdcli.c fileio.c bench.c xxhash.c datagen.c dibio.c + $(CC) $(FLAGS) -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT) $^ -o $@$(EXT) -zstd32: $(ZSTD_FILES) $(ZSTDDIR)/zstd_buffered.c $(ZSTDDIR)/dictBuilder.c $(ZSTDDIR)/divsufsort.c \ - zstdcli.c fileio.c $(ZSTD_FILEIO_LEGACY) bench.c xxhash.c datagen.c dibio.c - $(CC) -m32 $(FLAGS) $^ -o $@$(EXT) +zstd32: $(ZSTD_FILES) $(ZSTD_FILES_LEGACY) $(ZSTDDIR)/zstd_buffered.c $(ZSTDDIR)/dictBuilder.c $(ZSTDDIR)/divsufsort.c \ + zstdcli.c fileio.c bench.c xxhash.c datagen.c dibio.c + $(CC) -m32 $(FLAGS) -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT) $^ -o $@$(EXT) zstd_nolegacy : $(MAKE) zstd ZSTD_LEGACY_SUPPORT=0 @@ -101,12 +101,11 @@ zstd-pgo : clean zstd rm zstd $(MAKE) zstd MOREFLAGS=-fprofile-use -zstd-frugal: $(ZSTD_FILES) $(ZSTDDIR)/zstd_buffered.c \ - zstdcli.c fileio.c $(ZSTD_FILEIO_LEGACY) - $(CC) $(FLAGS) -DZSTD_NOBENCH -DZSTD_NODICT $^ -o zstd$(EXT) +zstd-frugal: $(ZSTD_FILES) $(ZSTDDIR)/zstd_buffered.c zstdcli.c fileio.c + $(CC) $(FLAGS) -DZSTD_NOBENCH -DZSTD_NODICT -DZSTD_LEGACY_SUPPORT=0 $^ -o zstd$(EXT) zstd-small: clean - CFLAGS=-Os $(MAKE) zstd-frugal ZSTD_LEGACY_SUPPORT=0 + CFLAGS=-Os $(MAKE) zstd-frugal fullbench : $(ZSTD_FILES) \ datagen.c fullbench.c diff --git a/programs/fileio.h b/programs/fileio.h index 0e25d842f..7e58817c7 100644 --- a/programs/fileio.h +++ b/programs/fileio.h @@ -33,8 +33,8 @@ extern "C" { * Special i/o constants **************************************/ #define nullString "null" -#define stdinmark "-" -#define stdoutmark "-" +#define stdinmark "stdin" +#define stdoutmark "stdout" #ifdef _WIN32 # define nulmark "nul" #else diff --git a/programs/playTests.sh b/programs/playTests.sh index af5215701..4950e95be 100755 --- a/programs/playTests.sh +++ b/programs/playTests.sh @@ -27,10 +27,10 @@ printf "\n**** frame concatenation **** " echo "hello " > hello.tmp echo "world!" > world.tmp cat hello.tmp world.tmp > helloworld.tmp -$ZSTD hello.tmp > hello.zstd -$ZSTD world.tmp > world.zstd +$ZSTD -c hello.tmp > hello.zstd +$ZSTD -c world.tmp > world.zstd cat hello.zstd world.zstd > helloworld.zstd -$ZSTD -df helloworld.zstd > result.tmp +$ZSTD -dc helloworld.zstd > result.tmp cat result.tmp sdiff helloworld.tmp result.tmp rm ./*.tmp ./*.zstd @@ -57,12 +57,12 @@ echo "*** multiple files tests *** " ./datagen -s1 > tmp1 2> /dev/null ./datagen -s2 -g100K > tmp2 2> /dev/null ./datagen -s3 -g1M > tmp3 2> /dev/null -$ZSTD -f -m tmp* +$ZSTD -f tmp* ls -ls tmp* rm tmp1 tmp2 tmp3 -$ZSTD -df -m *.zst +$ZSTD -df *.zst ls -ls tmp* -$ZSTD -f -m tmp1 notHere tmp2 && die "missing file not detected!" +$ZSTD -f tmp1 notHere tmp2 && die "missing file not detected!" rm tmp* echo "**** zstd round-trip tests **** " diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 21ec9ecd9..41083eb63 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -372,8 +372,8 @@ int main(int argCount, const char** argv) goto _end; } - /* No input filename ==> use stdin */ - if(!filenameIdx) filenameIdx=1, filenameTable[0]=stdinmark; + /* No input filename ==> use stdin and stdout */ + if(!filenameIdx) filenameIdx=1, filenameTable[0]=stdinmark, outFileName=stdoutmark; /* Check if input/output defined as console; trigger an error in this case */ if (!strcmp(filenameTable[0], stdinmark) && IS_CONSOLE(stdin) ) return badusage(programName); From 883a67eee2051a3bb2386da54f23b6222f642f08 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 12 Feb 2016 03:50:05 +0100 Subject: [PATCH 084/113] fixed cmake --- contrib/cmake/CMakeLists.txt | 2 +- contrib/cmake/lib/CMakeLists.txt | 16 +++++++++------ contrib/cmake/programs/CMakeLists.txt | 13 ++++++------- programs/fileio.h | 28 ++++++++++++--------------- 4 files changed, 29 insertions(+), 30 deletions(-) diff --git a/contrib/cmake/CMakeLists.txt b/contrib/cmake/CMakeLists.txt index 3687c9ec2..418833735 100644 --- a/contrib/cmake/CMakeLists.txt +++ b/contrib/cmake/CMakeLists.txt @@ -1,6 +1,6 @@ # ################################################################ # zstd - Makefile -# Copyright (C) Yann Collet 2014-2015 +# Copyright (C) Yann Collet 2014-2016 # All rights reserved. # # BSD license diff --git a/contrib/cmake/lib/CMakeLists.txt b/contrib/cmake/lib/CMakeLists.txt index a8247ddca..910e5060d 100644 --- a/contrib/cmake/lib/CMakeLists.txt +++ b/contrib/cmake/lib/CMakeLists.txt @@ -1,6 +1,6 @@ # ################################################################ # zstd - Makefile -# Copyright (C) Yann Collet 2014-2015 +# Copyright (C) Yann Collet 2014-2016 # All rights reserved. # # BSD license @@ -27,8 +27,7 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # You can contact the author at : -# - zstd source repository : https://github.com/Cyan4973/zstd -# - Public forum : https://groups.google.com/forum/#!forum/lz4c +# - zstd homepage : http://www.zstd.net/ # ################################################################ # Get library version based on information from input content (use regular exp) @@ -58,6 +57,8 @@ GetLibraryVersion("${HEADER_CONTENT}" LIBVER_MAJOR LIBVER_MINOR LIBVER_RELEASE) MESSAGE("ZSTD VERSION ${LIBVER_MAJOR}.${LIBVER_MINOR}.${LIBVER_RELEASE}") SET(Sources + ${LIBRARY_DIR}/dictBuilder.c + ${LIBRARY_DIR}/divsufsort.c ${LIBRARY_DIR}/fse.c ${LIBRARY_DIR}/huff0.c ${LIBRARY_DIR}/zstd_buffered.c @@ -66,6 +67,7 @@ SET(Sources SET(Headers ${LIBRARY_DIR}/bitstream.h + ${LIBRARY_DIR}/dictBuilder.h ${LIBRARY_DIR}/error_private.h ${LIBRARY_DIR}/error_public.h ${LIBRARY_DIR}/fse.h @@ -86,13 +88,15 @@ IF (ZSTD_LEGACY_SUPPORT) SET(Sources ${Sources} ${LIBRARY_LEGACY_DIR}/zstd_v01.c ${LIBRARY_LEGACY_DIR}/zstd_v02.c - ${LIBRARY_LEGACY_DIR}/zstd_v03.c) + ${LIBRARY_LEGACY_DIR}/zstd_v03.c + ${LIBRARY_LEGACY_DIR}/zstd_v04.c) SET(Headers ${Headers} ${LIBRARY_LEGACY_DIR}/zstd_legacy.h ${LIBRARY_LEGACY_DIR}/zstd_v01.h ${LIBRARY_LEGACY_DIR}/zstd_v02.h - ${LIBRARY_LEGACY_DIR}/zstd_v03.h) + ${LIBRARY_LEGACY_DIR}/zstd_v03.h + ${LIBRARY_LEGACY_DIR}/zstd_v04.h) ENDIF (ZSTD_LEGACY_SUPPORT) IF (MSVC) @@ -161,7 +165,7 @@ IF (UNIX) SET(INSTALL_INCLUDE_DIR ${PREFIX}/include) # install target - INSTALL(FILES ${LIBRARY_DIR}/zstd.h DESTINATION ${INSTALL_INCLUDE_DIR}) + INSTALL(FILES ${LIBRARY_DIR}/zstd.h ${LIBRARY_DIR}/zstd_buffered.h ${LIBRARY_DIR}/dictBuilder.h DESTINATION ${INSTALL_INCLUDE_DIR}) INSTALL(TARGETS libzstd_static DESTINATION ${INSTALL_LIBRARY_DIR}) INSTALL(TARGETS libzstd_shared LIBRARY DESTINATION ${INSTALL_LIBRARY_DIR}) diff --git a/contrib/cmake/programs/CMakeLists.txt b/contrib/cmake/programs/CMakeLists.txt index af9a05725..ebee7c210 100644 --- a/contrib/cmake/programs/CMakeLists.txt +++ b/contrib/cmake/programs/CMakeLists.txt @@ -1,6 +1,6 @@ # ################################################################ # zstd - Makefile -# Copyright (C) Yann Collet 2014-2015 +# Copyright (C) Yann Collet 2014-2016 # All rights reserved. # # BSD license @@ -27,8 +27,7 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # You can contact the author at : -# - zstd source repository : https://github.com/Cyan4973/zstd -# - Public forum : https://groups.google.com/forum/#!forum/lz4c +# - zstd homepage : http://www.zstd.net/ # ################################################################ PROJECT(programs) @@ -59,7 +58,7 @@ IF (ZSTD_LEGACY_SUPPORT) SET(ZSTD_FILEIO_LEGACY ${PROGRAMS_LEGACY_DIR}/fileio_legacy.c) ENDIF (ZSTD_LEGACY_SUPPORT) -ADD_EXECUTABLE(zstd ${PROGRAMS_DIR}/zstdcli.c ${PROGRAMS_DIR}/fileio.c ${PROGRAMS_DIR}/bench.c ${PROGRAMS_DIR}/xxhash.c ${PROGRAMS_DIR}/datagen.c ${ZSTD_FILEIO_LEGACY}) +ADD_EXECUTABLE(zstd ${PROGRAMS_DIR}/zstdcli.c ${PROGRAMS_DIR}/fileio.c ${PROGRAMS_DIR}/bench.c ${PROGRAMS_DIR}/xxhash.c ${PROGRAMS_DIR}/datagen.c ${PROGRAMS_DIR}/dibio.c ${ZSTD_FILEIO_LEGACY}) TARGET_LINK_LIBRARIES(zstd libzstd_static) ADD_EXECUTABLE(fullbench ${PROGRAMS_DIR}/datagen.c ${PROGRAMS_DIR}/fullbench.c) @@ -69,9 +68,9 @@ ADD_EXECUTABLE(fuzzer ${PROGRAMS_DIR}/datagen.c ${PROGRAMS_DIR}/xxhash.c ${PROGR TARGET_LINK_LIBRARIES(fuzzer libzstd_static) IF (UNIX) - ADD_EXECUTABLE(zstd-noBench ${PROGRAMS_DIR}/zstdcli.c ${PROGRAMS_DIR}/fileio.c ${ZSTD_FILEIO_LEGACY}) - TARGET_LINK_LIBRARIES(zstd-noBench libzstd_static) - SET_TARGET_PROPERTIES(zstd-noBench PROPERTIES COMPILE_DEFINITIONS "ZSTD_NOBENCH") + ADD_EXECUTABLE(zstd-frugal ${PROGRAMS_DIR}/zstdcli.c ${PROGRAMS_DIR}/fileio.c) + TARGET_LINK_LIBRARIES(zstd-frugal libzstd_static) + SET_TARGET_PROPERTIES(zstd-frugal PROPERTIES COMPILE_DEFINITIONS "ZSTD_NOBENCH;ZSTD_NODICT") ADD_EXECUTABLE(zbufftest ${PROGRAMS_DIR}/datagen.c ${PROGRAMS_DIR}/xxhash.c ${PROGRAMS_DIR}/zbufftest.c) TARGET_LINK_LIBRARIES(zbufftest libzstd_static) diff --git a/programs/fileio.h b/programs/fileio.h index 7e58817c7..15a2c3221 100644 --- a/programs/fileio.h +++ b/programs/fileio.h @@ -1,6 +1,6 @@ /* fileio.h - file i/o handler - Copyright (C) Yann Collet 2013-2015 + Copyright (C) Yann Collet 2013-2016 GPL v2 License @@ -19,8 +19,7 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. You can contact the author at : - - ZSTD source repository : https://github.com/Cyan4973/zstd - - Public forum : https://groups.google.com/forum/#!forum/lz4c + - ZSTD homepage : http://www.zstd.net/ */ #pragma once @@ -52,32 +51,29 @@ void FIO_setNotificationLevel(unsigned level); /* ************************************* * Single File functions ***************************************/ +/** FIO_compressFilename() : + @return : 0 == ok; 1 == pb with src file. */ int FIO_compressFilename (const char* outfilename, const char* infilename, const char* dictFileName, int compressionLevel); -int FIO_decompressFilename (const char* outfilename, const char* infilename, const char* dictFileName); -/** -FIO_compressFilename : - @result : 0 == ok; 1 == pb with src file. -FIO_decompressFilename : - @result : 0 == ok; 1 == pb with src file. -*/ +/** FIO_decompressFilename() : + @return : 0 == ok; 1 == pb with src file. */ +int FIO_decompressFilename (const char* outfilename, const char* infilename, const char* dictFileName); /* ************************************* * Multiple File functions ***************************************/ +/** FIO_compressMultipleFilenames() : + @return : nb of missing files */ int FIO_compressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles, const char* suffix, const char* dictFileName, int compressionLevel); + +/** FIO_decompressMultipleFilenames() : + @result : nb of missing or skipped files */ int FIO_decompressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles, const char* suffix, const char* dictFileName); -/** -FIO_compressMultipleFilenames : - @result : nb of missing files -FIO_decompressMultipleFilenames : - @result : nb of missing or skipped files -*/ #if defined (__cplusplus) From 492a9bb88e74b3e1426083af826942310f968957 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 12 Feb 2016 03:52:37 +0100 Subject: [PATCH 085/113] fixed Valgrind tests --- programs/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/programs/Makefile b/programs/Makefile index 2f67bb309..b107b72d6 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -214,12 +214,12 @@ valgrindTest: zstd datagen fuzzer fullbench zbufftest @echo "\n ---- valgrind tests : memory analyzer ----" valgrind --leak-check=yes --error-exitcode=1 ./datagen -g50M > $(VOID) ./datagen -g16KB > tmp - valgrind --leak-check=yes --error-exitcode=1 ./zstd -vf tmp $(VOID) + valgrind --leak-check=yes --error-exitcode=1 ./zstd -vf tmp -o $(VOID) ./datagen -g2930KB > tmp - valgrind --leak-check=yes --error-exitcode=1 ./zstd -5 -vf tmp tmp2 - valgrind --leak-check=yes --error-exitcode=1 ./zstd -vdf tmp2 $(VOID) + valgrind --leak-check=yes --error-exitcode=1 ./zstd -5 -vf tmp -o tmp2 + valgrind --leak-check=yes --error-exitcode=1 ./zstd -vdf tmp2 -o $(VOID) ./datagen -g64MB > tmp - valgrind --leak-check=yes --error-exitcode=1 ./zstd -vf tmp $(VOID) + valgrind --leak-check=yes --error-exitcode=1 ./zstd -vf tmp -o $(VOID) @rm tmp valgrind --leak-check=yes --error-exitcode=1 ./fuzzer -T1mn -t1 valgrind --leak-check=yes --error-exitcode=1 ./fullbench -i1 From f062436fa6e9cf32f2d7a681673077c2babb2cbf Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 12 Feb 2016 15:56:46 +0100 Subject: [PATCH 086/113] cli : added ability to compress multiple files into stdout (-c) --- lib/zstd_buffered.h | 29 +++---- lib/zstd_buffered_static.h | 5 +- programs/fileio.c | 160 ++++++++++++++++++++++++------------- programs/fileio.h | 3 +- programs/playTests.sh | 19 +++-- programs/zstdcli.c | 18 ++--- 6 files changed, 144 insertions(+), 90 deletions(-) diff --git a/lib/zstd_buffered.h b/lib/zstd_buffered.h index 8aa37650e..d3275b7df 100644 --- a/lib/zstd_buffered.h +++ b/lib/zstd_buffered.h @@ -1,6 +1,6 @@ /* Buffered version of Zstd compression library - Copyright (C) 2015, Yann Collet. + Copyright (C) 2015-2016, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -26,14 +26,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - zstd source repository : https://github.com/Cyan4973/zstd - - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c + - zstd homepage : http://www.zstd.net/ */ #ifndef ZSTD_BUFFERED_H #define ZSTD_BUFFERED_H /* The objects defined into this file should be considered experimental. - * They are not labelled stable, as their prototype may change in the future. + * They are not considered stable, as their prototype may change in the future. * You can use them for tests, provide feedback, or if you can endure risk of future changes. */ @@ -42,7 +41,7 @@ extern "C" { #endif /* ************************************* -* Includes +* Dependencies ***************************************/ #include /* size_t */ @@ -75,7 +74,7 @@ ZSTDLIB_API size_t ZBUFF_compressContinue(ZBUFF_CCtx* cctx, void* dst, size_t* d ZSTDLIB_API size_t ZBUFF_compressFlush(ZBUFF_CCtx* cctx, void* dst, size_t* dstCapacityPtr); ZSTDLIB_API size_t ZBUFF_compressEnd(ZBUFF_CCtx* cctx, void* dst, size_t* dstCapacityPtr); -/** ************************************************ +/*-************************************************* * Streaming compression * * A ZBUFF_CCtx object is required to track streaming operation. @@ -123,12 +122,14 @@ ZSTDLIB_API size_t ZBUFF_freeDCtx(ZBUFF_DCtx* dctx); ZSTDLIB_API size_t ZBUFF_decompressInit(ZBUFF_DCtx* dctx); ZSTDLIB_API size_t ZBUFF_decompressInitDictionary(ZBUFF_DCtx* dctx, const void* dict, size_t dictSize); -ZSTDLIB_API size_t ZBUFF_decompressContinue(ZBUFF_DCtx* dctx, void* dst, size_t* dstCapacityPtr, const void* src, size_t* srcSizePtr); +ZSTDLIB_API size_t ZBUFF_decompressContinue(ZBUFF_DCtx* dctx, + void* dst, size_t* dstCapacityPtr, + const void* src, size_t* srcSizePtr); -/** ************************************************ +/*-*************************************************************************** * Streaming decompression * -* A ZBUFF_DCtx object is required to track streaming operation. +* A ZBUFF_DCtx object is required to track streaming operations. * Use ZBUFF_createDCtx() and ZBUFF_freeDCtx() to create/release resources. * Use ZBUFF_decompressInit() to start a new decompression operation, * or ZBUFF_decompressInitDictionary() if decompression requires a dictionary. @@ -143,10 +144,10 @@ ZSTDLIB_API size_t ZBUFF_decompressContinue(ZBUFF_DCtx* dctx, void* dst, size_t* * or 0 when a frame is completely decoded * or an error code, which can be tested using ZBUFF_isError(). * -* Hint : recommended buffer sizes (not compulsory) : ZBUFF_recommendedDInSize / ZBUFF_recommendedDOutSize -* output : ZBUFF_recommendedDOutSize==128 KB block size is the internal unit, it ensures it's always possible to write a full block when it's decoded. -* input : ZBUFF_recommendedDInSize==128Kb+3; just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 . -* **************************************************/ +* Hint : recommended buffer sizes (not compulsory) : ZBUFF_recommendedDInSize() / ZBUFF_recommendedDOutSize() +* output : ZBUFF_recommendedDOutSize==128 KB block size is the internal unit, it ensures it's always possible to write a full block when decoded. +* input : ZBUFF_recommendedDInSize==128Kb+3; just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 . +* *******************************************************************************/ /* ************************************* @@ -155,7 +156,7 @@ ZSTDLIB_API size_t ZBUFF_decompressContinue(ZBUFF_DCtx* dctx, void* dst, size_t* ZSTDLIB_API unsigned ZBUFF_isError(size_t errorCode); ZSTDLIB_API const char* ZBUFF_getErrorName(size_t errorCode); -/** The below functions provide recommended buffer sizes for Compression or Decompression operations. +/** Functions below provide recommended buffer sizes for Compression or Decompression operations. * These sizes are just hints, and tend to offer better latency */ ZSTDLIB_API size_t ZBUFF_recommendedCInSize(void); ZSTDLIB_API size_t ZBUFF_recommendedCOutSize(void); diff --git a/lib/zstd_buffered_static.h b/lib/zstd_buffered_static.h index 5052f4c3e..a15745c09 100644 --- a/lib/zstd_buffered_static.h +++ b/lib/zstd_buffered_static.h @@ -1,7 +1,7 @@ /* zstd - buffered version of compression library experimental complementary API, for static linking only - Copyright (C) 2015, Yann Collet. + Copyright (C) 2015-2016, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -27,8 +27,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - zstd source repository : https://github.com/Cyan4973/zstd - - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c + - zstd homepage : http://www.zstd.net */ #ifndef ZSTD_BUFFERED_STATIC_H #define ZSTD_BUFFERED_STATIC_H diff --git a/programs/fileio.c b/programs/fileio.c index a5739ab4d..3e467fe29 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -186,54 +186,73 @@ static U64 FIO_getFileSize(const char* infilename) } +static FILE* FIO_openSrcFile(const char* srcFileName) +{ + FILE* f; + + if (!strcmp (srcFileName, stdinmark)) { + DISPLAYLEVEL(4,"Using stdin for input\n"); + f = stdin; + SET_BINARY_MODE(stdin); + } else { + f = fopen(srcFileName, "rb"); + } + + if ( f==NULL ) DISPLAYLEVEL(1, "zstd: %s: No such file\n", srcFileName); + + return f; +} + + +static FILE* FIO_openDstFile(const char* dstFileName) +{ + FILE* f; + + if (!strcmp (dstFileName, stdoutmark)) { + DISPLAYLEVEL(4,"Using stdout for output\n"); + f = stdout; + SET_BINARY_MODE(stdout); + } else { + if (!g_overwrite) { /* Check if destination file already exists */ + f = fopen( dstFileName, "rb" ); + if (f != 0) { /* dest file exists, prompt for overwrite authorization */ + fclose(f); + if (g_displayLevel <= 1) { + /* No interaction possible */ + DISPLAY("zstd: %s already exists; not overwritten \n", dstFileName); + return 0; + } + DISPLAY("zstd: %s already exists; do you wish to overwrite (y/N) ? ", dstFileName); + { + int ch = getchar(); + if ((ch!='Y') && (ch!='y')) { + DISPLAY(" not overwritten \n"); + return 0; + } + while ((ch!=EOF) && (ch!='\n')) ch = getchar(); /* flush rest of input line */ + } } } + f = fopen( dstFileName, "wb" ); + } + return f; +} + + static int FIO_getFiles(FILE** fileOutPtr, FILE** fileInPtr, const char* dstFileName, const char* srcFileName) { - if (!strcmp (srcFileName, stdinmark)) { - DISPLAYLEVEL(4,"Using stdin for input\n"); - *fileInPtr = stdin; - SET_BINARY_MODE(stdin); - } else { - *fileInPtr = fopen(srcFileName, "rb"); - } - + *fileInPtr = FIO_openSrcFile(srcFileName); if ( *fileInPtr==0 ) { DISPLAYLEVEL(1, "Unable to access file for processing: %s\n", srcFileName); return 1; } - if (!strcmp (dstFileName, stdoutmark)) { - DISPLAYLEVEL(4,"Using stdout for output\n"); - *fileOutPtr = stdout; - SET_BINARY_MODE(stdout); - } else { - if (!g_overwrite) { /* Check if destination file already exists */ - *fileOutPtr = fopen( dstFileName, "rb" ); - if (*fileOutPtr != 0) { /* dest file exists, prompt for overwrite authorization */ - fclose(*fileOutPtr); - DISPLAY("Warning : %s already exists \n", dstFileName); - if ((g_displayLevel <= 1) || (*fileInPtr == stdin)) { - /* No interaction possible */ - DISPLAY("Operation aborted : %s already exists \n", dstFileName); - return 1; - } - DISPLAY("Overwrite ? (y/N) : "); - { - int ch = getchar(); - if ((ch!='Y') && (ch!='y')) { - DISPLAY("No. Operation aborted : %s already exists \n", dstFileName); - return 1; - } - while ((ch!=EOF) && (ch!='\n')) ch = getchar(); /* flush rest of input line */ - } } } - *fileOutPtr = fopen( dstFileName, "wb" ); - } - - if (*fileOutPtr==0) EXM_THROW(13, "Pb opening %s", dstFileName); + *fileOutPtr = FIO_openDstFile(dstFileName); + if (*fileOutPtr==0) return 1; return 0; } + /*!FIO_loadFile * creates a buffer, pointed by *bufferPtr, * loads "filename" content into it @@ -280,6 +299,7 @@ typedef struct { void* dictBuffer; size_t dictBufferSize; ZBUFF_CCtx* ctx; + FILE* dstFile; } cRess_t; static cRess_t FIO_createCResources(const char* dictFileName) @@ -313,24 +333,25 @@ static void FIO_freeCResources(cRess_t ress) } -/*! - * FIO_compressFilename_extRess() : - * @result : 0 : compression completed correctly, - * 1 : missing or pb opening srcFileName +/*! FIO_compressFilename_internal() : + * same as FIO_compressFilename_extRess(), with ress.desFile already opened + * @return : 0 : compression completed correctly, + * 1 : missing or pb opening srcFileName */ -static int FIO_compressFilename_extRess(cRess_t ress, - const char* dstFileName, const char* srcFileName, - int cLevel) +static int FIO_compressFilename_internal(cRess_t ress, + const char* dstFileName, const char* srcFileName, + int cLevel) { FILE* srcFile; - FILE* dstFile; + FILE* dstFile = ress.dstFile; U64 filesize = 0; U64 compressedfilesize = 0; size_t dictSize = ress.dictBufferSize; size_t sizeCheck, errorCode; /* File check */ - if (FIO_getFiles(&dstFile, &srcFile, dstFileName, srcFileName)) return 1; + srcFile = FIO_openSrcFile(srcFileName); + if (!srcFile) return 1; /* srcFile could not be opened */ /* init */ filesize = FIO_getFileSize(srcFileName) + dictSize; @@ -346,8 +367,7 @@ static int FIO_compressFilename_extRess(cRess_t ress, filesize += inSize; DISPLAYUPDATE(2, "\rRead : %u MB ", (U32)(filesize>>20)); - { - /* Compress (buffered streaming ensures appropriate formatting) */ + { /* Compress using buffered streaming */ size_t usedInSize = inSize; size_t cSize = ress.dstBufferSize; size_t result = ZBUFF_compressContinue(ress.ctx, ress.dstBuffer, &cSize, ress.srcBuffer, &usedInSize); @@ -362,7 +382,6 @@ static int FIO_compressFilename_extRess(cRess_t ress, if (sizeCheck!=cSize) EXM_THROW(25, "Write error : cannot write compressed block into %s", dstFileName); compressedfilesize += cSize; } - DISPLAYUPDATE(2, "\rRead : %u MB ==> %.2f%% ", (U32)(filesize>>20), (double)compressedfilesize/filesize*100); } @@ -384,12 +403,31 @@ static int FIO_compressFilename_extRess(cRess_t ress, /* clean */ fclose(srcFile); - if (fclose(dstFile)) EXM_THROW(28, "Write error : cannot properly close %s", dstFileName); return 0; } +/*! FIO_compressFilename_extRess() : + * @return : 0 : compression completed correctly, + * 1 : missing or pb opening srcFileName + */ +static int FIO_compressFilename_extRess(cRess_t ress, + const char* dstFileName, const char* srcFileName, + int cLevel) +{ + int result; + + ress.dstFile = FIO_openDstFile(dstFileName); + if (ress.dstFile==0) return 1; + + result = FIO_compressFilename_internal(ress, dstFileName, srcFileName, cLevel); + + if (fclose(ress.dstFile)) EXM_THROW(28, "Write error : cannot properly close %s", dstFileName); + return result; +} + + int FIO_compressFilename(const char* dstFileName, const char* srcFileName, const char* dictFileName, int compressionLevel) { @@ -427,20 +465,28 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile int missed_files = 0; char* dstFileName = (char*)malloc(FNSPACE); size_t dfnSize = FNSPACE; - const size_t suffixSize = strlen(suffix); + const size_t suffixSize = suffix ? strlen(suffix) : 0; cRess_t ress; /* init */ ress = FIO_createCResources(dictFileName); /* loop on each file */ - for (u=0; u hello.tmp echo "world!" > world.tmp @@ -37,7 +38,8 @@ rm ./*.tmp ./*.zstd echo frame concatenation test completed -echo "**** flush write error test **** " + +echo "\n**** flush write error test **** " echo "echo foo | $ZSTD > /dev/full" echo foo | $ZSTD > /dev/full && die "write error not detected!" @@ -45,27 +47,32 @@ echo "echo foo | $ZSTD | $ZSTD -d > /dev/full" echo foo | $ZSTD | $ZSTD -d > /dev/full && die "write error not detected!" -echo "*** dictionary tests *** " +echo "\n**** dictionary tests **** " ./datagen > tmpDict ./datagen -g1M | md5sum > tmp1 -./datagen -g1M | $ZSTD -D tmpDict | $ZSTD -D tmpDict -dv | md5sum > tmp2 +./datagen -g1M | $ZSTD -D tmpDict | $ZSTD -D tmpDict -dvq | md5sum > tmp2 diff -q tmp1 tmp2 -echo "*** multiple files tests *** " +echo "\n**** multiple files tests **** " ./datagen -s1 > tmp1 2> /dev/null ./datagen -s2 -g100K > tmp2 2> /dev/null ./datagen -s3 -g1M > tmp3 2> /dev/null $ZSTD -f tmp* +echo "compress tmp* : " ls -ls tmp* rm tmp1 tmp2 tmp3 +echo "decompress tmp* : " $ZSTD -df *.zst ls -ls tmp* +echo "compress tmp* into stdout : " +$ZSTD -c tmp1 tmp2 tmp3 > tmpall +ls -ls tmp* $ZSTD -f tmp1 notHere tmp2 && die "missing file not detected!" rm tmp* -echo "**** zstd round-trip tests **** " +echo "\n**** zstd round-trip tests **** " roundTripTest roundTripTest '' 6 diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 41083eb63..f481b7d8f 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -379,28 +379,28 @@ int main(int argCount, const char** argv) if (!strcmp(filenameTable[0], stdinmark) && IS_CONSOLE(stdin) ) return badusage(programName); if (outFileName && !strcmp(outFileName, stdoutmark) && IS_CONSOLE(stdout) && !forceStdout) return badusage(programName); - /* No warning message in pipe mode (stdin + stdout) or multiple mode */ - if (!strcmp(filenameTable[0], stdinmark) && !strcmp(outFileName,stdoutmark) && (displayLevel==2)) displayLevel=1; - if ((filenameIdx>1) && (displayLevel==2)) displayLevel=1; - - /* user-selected output filename only possible with a single file */ - if ((outFileName) && (filenameIdx>1)) { + /* user-selected output filename, only possible with a single file */ + if (outFileName && strcmp(outFileName,stdoutmark) && (filenameIdx>1)) { DISPLAY("Too many files (%u) on the command line. \n", filenameIdx); return filenameIdx; } + /* No warning message in pipe mode (stdin + stdout) or multiple mode */ + if (!strcmp(filenameTable[0], stdinmark) && !strcmp(outFileName,stdoutmark) && (displayLevel==2)) displayLevel=1; + if ((filenameIdx>1) && (displayLevel==2)) displayLevel=1; + /* IO Stream/File */ FIO_setNotificationLevel(displayLevel); if (decode) { - if (outFileName) + if (filenameIdx==1) operationResult = FIO_decompressFilename(outFileName, filenameTable[0], dictFileName); else operationResult = FIO_decompressMultipleFilenames(filenameTable, filenameIdx, ZSTD_EXTENSION, dictFileName); } else { /* compression */ - if (outFileName) + if (filenameIdx==1) operationResult = FIO_compressFilename(outFileName, filenameTable[0], dictFileName, cLevel); else - operationResult = FIO_compressMultipleFilenames(filenameTable, filenameIdx, ZSTD_EXTENSION, dictFileName, cLevel); + operationResult = FIO_compressMultipleFilenames(filenameTable, filenameIdx, forceStdout ? NULL : ZSTD_EXTENSION, dictFileName, cLevel); } _end: From 1f1f239ed9178238feea4d40bcec885f7d982ffe Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 12 Feb 2016 18:33:26 +0100 Subject: [PATCH 087/113] zstd cli can decompress multiple files with no specific suffix condition into stdout --- programs/fileio.c | 88 ++++++++++++++++++++++++------------------- programs/playTests.sh | 6 ++- programs/zstdcli.c | 2 +- 3 files changed, 55 insertions(+), 41 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 3e467fe29..ea6e866cf 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -237,22 +237,6 @@ static FILE* FIO_openDstFile(const char* dstFileName) } -static int FIO_getFiles(FILE** fileOutPtr, FILE** fileInPtr, - const char* dstFileName, const char* srcFileName) -{ - *fileInPtr = FIO_openSrcFile(srcFileName); - if ( *fileInPtr==0 ) { - DISPLAYLEVEL(1, "Unable to access file for processing: %s\n", srcFileName); - return 1; - } - - *fileOutPtr = FIO_openDstFile(dstFileName); - if (*fileOutPtr==0) return 1; - - return 0; -} - - /*!FIO_loadFile * creates a buffer, pointed by *bufferPtr, * loads "filename" content into it @@ -508,6 +492,7 @@ typedef struct { void* dictBuffer; size_t dictBufferSize; ZBUFF_DCtx* dctx; + FILE* dstFile; } dRess_t; static dRess_t FIO_createDResources(const char* dictFileName) @@ -576,15 +561,17 @@ unsigned long long FIO_decompressFrame(dRess_t ress, } -static int FIO_decompressFile_extRess(dRess_t ress, - const char* dstFileName, const char* srcFileName) +/** FIO_decompressSrcFile() : + Decompression `srcFileName` into `ress.dstFile` + @return : 0 : OK + 1 : operation not started +*/ +static int FIO_decompressSrcFile(dRess_t ress, const char* srcFileName) { unsigned long long filesize = 0; - FILE* srcFile; - FILE* dstFile; - - /* Init */ - if (FIO_getFiles(&dstFile, &srcFile, dstFileName, srcFileName)) return 1; + FILE* dstFile = ress.dstFile; + FILE* srcFile = FIO_openSrcFile(srcFileName); + if (srcFile==0) return 1; /* for each frame */ for ( ; ; ) { @@ -593,7 +580,7 @@ static int FIO_decompressFile_extRess(dRess_t ress, size_t toRead = 4; sizeCheck = fread(ress.srcBuffer, (size_t)1, toRead, srcFile); if (sizeCheck==0) break; /* no more input */ - if (sizeCheck != toRead) EXM_THROW(31, "Read error : cannot read header"); + if (sizeCheck != toRead) EXM_THROW(31, "zstd: %s read error : cannot read header", srcFileName); #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1) if (ZSTD_isLegacy(MEM_readLE32(ress.srcBuffer))) { filesize += FIO_decompressLegacyFrame(dstFile, srcFile, MEM_readLE32(ress.srcBuffer)); @@ -610,8 +597,24 @@ static int FIO_decompressFile_extRess(dRess_t ress, /* Close */ fclose(srcFile); - if (fclose(dstFile)) EXM_THROW(38, "Write error : cannot properly close %s", dstFileName); + return 0; +} + +/** FIO_decompressFile_extRess() : + decompress `srcFileName` into `dstFileName` + @return : 0 : OK + 1 : operation aborted (src not available, dst already taken, etc.) +*/ +static int FIO_decompressFile_extRess(dRess_t ress, + const char* dstFileName, const char* srcFileName) +{ + ress.dstFile = FIO_openDstFile(dstFileName); + if (ress.dstFile==0) return 1; + + FIO_decompressSrcFile(ress, srcFileName); + + if (fclose(ress.dstFile)) EXM_THROW(38, "Write error : cannot properly close %s", dstFileName); return 0; } @@ -639,26 +642,33 @@ int FIO_decompressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles int missingFiles = 0; char* dstFileName = (char*)malloc(FNSPACE); size_t dfnSize = FNSPACE; - const size_t suffixSize = strlen(suffix); + const size_t suffixSize = suffix ? strlen(suffix) : 0; dRess_t ress; if (dstFileName==NULL) EXM_THROW(70, "not enough memory for dstFileName"); ress = FIO_createDResources(dictFileName); - for (u=0; u tmpall : " $ZSTD -c tmp1 tmp2 tmp3 > tmpall ls -ls tmp* +echo "decompress tmpall* into stdout > tmpdec : " +cp tmpall tmpall2 +$ZSTD -dc tmpall* > tmpdec +ls -ls tmp* $ZSTD -f tmp1 notHere tmp2 && die "missing file not detected!" rm tmp* diff --git a/programs/zstdcli.c b/programs/zstdcli.c index f481b7d8f..22c8c8182 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -395,7 +395,7 @@ int main(int argCount, const char** argv) if (filenameIdx==1) operationResult = FIO_decompressFilename(outFileName, filenameTable[0], dictFileName); else - operationResult = FIO_decompressMultipleFilenames(filenameTable, filenameIdx, ZSTD_EXTENSION, dictFileName); + operationResult = FIO_decompressMultipleFilenames(filenameTable, filenameIdx, forceStdout ? NULL : ZSTD_EXTENSION, dictFileName); } else { /* compression */ if (filenameIdx==1) operationResult = FIO_compressFilename(outFileName, filenameTable[0], dictFileName, cLevel); From f4c9d753701c3cf1bab135ff5dc606e6fbd46fa3 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 12 Feb 2016 18:45:02 +0100 Subject: [PATCH 088/113] dictBuilder => zdict --- Makefile | 4 - dictBuilder/COPYING | 339 ------------------- dictBuilder/Makefile | 68 ---- dictBuilder/dibcli.c | 263 -------------- dictBuilder/dibio.c | 275 --------------- dictBuilder/dibio.h | 64 ---- dictBuilder/dictionary | Bin 112640 -> 0 bytes lib/Makefile | 5 +- lib/{dictBuilder.c => zdict.c} | 4 +- lib/{dictBuilder.h => zdict.h} | 0 lib/{dictBuilder_static.h => zdict_static.h} | 2 +- programs/Makefile | 4 +- programs/dibio.c | 14 +- programs/dibio.h | 2 +- 14 files changed, 12 insertions(+), 1032 deletions(-) delete mode 100644 dictBuilder/COPYING delete mode 100644 dictBuilder/Makefile delete mode 100644 dictBuilder/dibcli.c delete mode 100644 dictBuilder/dibio.c delete mode 100644 dictBuilder/dibio.h delete mode 100644 dictBuilder/dictionary rename lib/{dictBuilder.c => zdict.c} (99%) rename lib/{dictBuilder.h => zdict.h} (100%) rename lib/{dictBuilder_static.h => zdict_static.h} (99%) diff --git a/Makefile b/Makefile index c80b20f39..93d5e0528 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,6 @@ PRGDIR = programs ZSTDDIR = lib -DICTDIR = dictBuilder # Define nul output ifneq (,$(filter Windows%,$(OS))) @@ -51,7 +50,6 @@ default: zstdprogram all: $(MAKE) -C $(ZSTDDIR) $@ $(MAKE) -C $(PRGDIR) $@ - $(MAKE) -C $(DICTDIR) $@ zstdprogram: $(MAKE) -C $(PRGDIR) @@ -59,7 +57,6 @@ zstdprogram: clean: @$(MAKE) -C $(ZSTDDIR) $@ > $(VOID) @$(MAKE) -C $(PRGDIR) $@ > $(VOID) - @$(MAKE) -C $(DICTDIR) $@ > $(VOID) @echo Cleaning completed @@ -80,7 +77,6 @@ travis-install: test: $(MAKE) -C $(PRGDIR) $@ - $(MAKE) -C $(DICTDIR) $@ cmaketest: cd contrib/cmake ; cmake . ; $(MAKE) diff --git a/dictBuilder/COPYING b/dictBuilder/COPYING deleted file mode 100644 index d159169d1..000000000 --- a/dictBuilder/COPYING +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/dictBuilder/Makefile b/dictBuilder/Makefile deleted file mode 100644 index 949995253..000000000 --- a/dictBuilder/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# ########################################################################## -# Dict Builder - Makefile -# Copyright (C) Yann Collet 2016 -# -# GPL v2 License -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# You can contact the author at : -# - ZSTD homepage : http://www.zstd.net/ -# ########################################################################## - -CPPFLAGS= -I../lib -CFLAGS ?= -O3 -CFLAGS += -std=c99 -Wall -Wextra -Wshadow -Wcast-qual -Wcast-align -Wundef -Wstrict-prototypes -Wstrict-aliasing=1 -FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(MOREFLAGS) - -ZSTDDIR = ../lib - - -# Define *.exe as extension for Windows systems -ifneq (,$(filter Windows%,$(OS))) -EXT =.exe -VOID = nul -else -EXT = -VOID = /dev/null -endif - - -.PHONY: default all test - -default: dictBuilder - -all: dictBuilder - -dictBuilder: dibio.c dibcli.c $(ZSTDDIR)/dictBuilder.c $(ZSTDDIR)/huff0.c $(ZSTDDIR)/fse.c $(ZSTDDIR)/zstd_decompress.c $(ZSTDDIR)/zstd_compress.c $(ZSTDDIR)/divsufsort.c - $(CC) $(FLAGS) $^ -o $@$(EXT) - -clean: - @rm -f core *.o tmp* result* *.gcda \ - dictBuilder$(EXT) - @echo Cleaning completed - -test: dictBuilder - ./dictBuilder * - @rm dictionary - -clangtest: CC = clang -clangtest: CFLAGS += -Werror -clangtest: clean dictBuilder - -gpptest: CC = g++ -gpptest: CFLAGS=-O3 -Wall -Wextra -Wshadow -Wcast-align -Wcast-qual -Wundef -Werror -gpptest: clean dictBuilder - diff --git a/dictBuilder/dibcli.c b/dictBuilder/dibcli.c deleted file mode 100644 index a8009ae63..000000000 --- a/dictBuilder/dibcli.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - dibcli - Command Line Interface (cli) for Dictionary Builder - Copyright (C) Yann Collet 2016 - - GPL v2 License - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - - You can contact the author at : - - zstd source repository : https://github.com/Cyan4973/zstd -*/ - -/* ************************************** -* Compiler Specifics -****************************************/ -/* Disable some Visual warning messages */ -#ifdef _MSC_VER -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#endif - - -/*-************************************ -* Includes -**************************************/ -#include /* exit, calloc, free */ -#include /* strcmp, strlen */ -#include /* fprintf, getchar */ -#include "dibio.h" -#include "zstd.h" /* version numbers */ - - -/*-************************************ -* Constants -**************************************/ -#define PROGRAM_DESCRIPTION "Dictionary builder" -#ifndef PROGRAM_VERSION -# define QUOTE(str) #str -# define EXP_Q(str) QUOTE(str) -# define PROGRAM_VERSION "v" EXP_Q(ZSTD_VERSION_MAJOR) "." EXP_Q(ZSTD_VERSION_MINOR) "." EXP_Q(ZSTD_VERSION_RELEASE) -#endif -#define AUTHOR "Yann Collet" -#define WELCOME_MESSAGE "*** %s %s %i-bits, by %s ***\n", PROGRAM_DESCRIPTION, PROGRAM_VERSION, (int)(sizeof(void*)*8), AUTHOR - -#define KB *(1 <<10) -#define MB *(1 <<20) -#define GB *(1U<<30) - -static const unsigned compressionLevelDefault = 5; -static const unsigned selectionLevelDefault = 9; /* determined experimentally */ -static const unsigned maxDictSizeDefault = 110 KB; -static const char* dictFileNameDefault = "dictionary"; - - -/*-************************************ -* Display Macros -**************************************/ -#define DISPLAY(...) fprintf(g_displayOut, __VA_ARGS__) -#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } -static FILE* g_displayOut; -static unsigned g_displayLevel = 2; // 0 : no display // 1: errors // 2 : + result + interaction + warnings ; // 3 : + progression; // 4 : + information - - -/*-************************************ -* Exceptions -**************************************/ -#define DEBUG 0 -#define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__); -#define EXM_THROW(error, ...) \ -{ \ - DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \ - DISPLAYLEVEL(1, "Error %i : ", error); \ - DISPLAYLEVEL(1, __VA_ARGS__); \ - DISPLAYLEVEL(1, "\n"); \ - exit(error); \ -} - - -/*-************************************ -* Command Line -**************************************/ -static int usage(const char* programName) -{ - DISPLAY( "Usage :\n"); - DISPLAY( " %s [arg] [filenames]\n", programName); - DISPLAY( "\n"); - DISPLAY( "Arguments :\n"); - DISPLAY( " -o : name of dictionary file (default: %s) \n", dictFileNameDefault); - DISPLAY( "--maxdict : limit dictionary to specified size (default : %u) \n", maxDictSizeDefault); - DISPLAY( " -h/-H : display help/long help and exit\n"); - return 0; -} - -static int usage_advanced(const char* programName) -{ - DISPLAY(WELCOME_MESSAGE); - usage(programName); - DISPLAY( "\n"); - DISPLAY( "Advanced arguments :\n"); - DISPLAY( " -V : display Version number and exit\n"); - DISPLAY( "--fast : fast sampling mode\n"); - DISPLAY( " -L# : target compression level (default: %u)\n", compressionLevelDefault); - DISPLAY( " -S# : dictionary selectivity level (default: %u)\n", selectionLevelDefault); - DISPLAY( " -v : verbose mode\n"); - DISPLAY( " -q : suppress notifications; specify twice to suppress errors too\n"); - return 0; -} - -static int badusage(const char* programName) -{ - DISPLAYLEVEL(1, "Incorrect parameters\n"); - if (g_displayLevel >= 1) usage(programName); - return 1; -} - - -static void waitEnter(void) -{ - int unused; - DISPLAY("Press enter to continue...\n"); - unused = getchar(); - (void)unused; -} - - -int main(int argCount, const char** argv) -{ - int i, - main_pause=0, - operationResult=0, - nextArgumentIsMaxDict=0, - nextArgumentIsDictFileName=0; - unsigned cLevel = compressionLevelDefault; - unsigned maxDictSize = maxDictSizeDefault; - unsigned selectionLevel = selectionLevelDefault; - const char** filenameTable = (const char**)malloc(argCount * sizeof(const char*)); /* argCount >= 1 */ - unsigned filenameIdx = 0; - const char* programName = argv[0]; - const char* dictFileName = dictFileNameDefault; - - /* init */ - g_displayOut = stderr; /* unfortunately, cannot be set at declaration */ - if (filenameTable==NULL) EXM_THROW(1, "not enough memory\n"); - /* Pick out program name from path. Don't rely on stdlib because of conflicting behavior */ - for (i = (int)strlen(programName); i > 0; i--) { if ((programName[i] == '/') || (programName[i] == '\\')) { i++; break; } } - programName += i; - - /* command switches */ - for(i=1; i='0') && (*argument<='9')) - maxDictSize = maxDictSize * 10 + (*argument - '0'), argument++; - if (*argument=='k' || *argument=='K') - maxDictSize <<= 10; - continue; - } - - /* long commands (--long-word) */ - if (!strcmp(argument, "--version")) { g_displayOut=stdout; DISPLAY(WELCOME_MESSAGE); return 0; } - if (!strcmp(argument, "--help")) { g_displayOut=stdout; return usage_advanced(programName); } - if (!strcmp(argument, "--verbose")) { g_displayLevel++; if (g_displayLevel<3) g_displayLevel=3; continue; } - if (!strcmp(argument, "--quiet")) { g_displayLevel--; continue; } - if (!strcmp(argument, "--maxdict")) { nextArgumentIsMaxDict=1; continue; } - if (!strcmp(argument, "--fast")) { selectionLevel=1; cLevel=1; continue; } - - /* Decode commands (note : aggregated commands are allowed) */ - if (argument[0]=='-') { - argument++; - - while (argument[0]!=0) { - switch(argument[0]) - { - /* Display help */ - case 'V': g_displayOut=stdout; DISPLAY(WELCOME_MESSAGE); return 0; /* Version Only */ - case 'H': - case 'h': g_displayOut=stdout; return usage_advanced(programName); - - /* Selection level */ - case 'S': argument++; - selectionLevel = 0; - while ((*argument >= '0') && (*argument <= '9')) - selectionLevel *= 10, selectionLevel += *argument++ - '0'; - break; - - /* Selection level */ - case 'L': argument++; - cLevel = 0; - while ((*argument >= '0') && (*argument <= '9')) - cLevel *= 10, cLevel += *argument++ - '0'; - break; - - /* Verbose mode */ - case 'v': g_displayLevel++; if (g_displayLevel<3) g_displayLevel=3; argument++; break; - - /* Quiet mode */ - case 'q': g_displayLevel--; argument++; break; - - /* dictionary name */ - case 'o': nextArgumentIsDictFileName=1; argument++; break; - - /* Pause at the end (hidden option) */ - case 'p': main_pause=1; argument++; break; - - /* unknown command */ - default : return badusage(programName); - } } - continue; - } - - /* add filename to list */ - filenameTable[filenameIdx++] = argument; - } - - /* Welcome message (if verbose) */ - DISPLAYLEVEL(3, WELCOME_MESSAGE); - - /* check nb files */ - if (filenameIdx==0) return badusage(programName); - if (filenameIdx < 100) - { - DISPLAYLEVEL(2, "Warning : set contains only %u files ... \n", filenameIdx); - DISPLAYLEVEL(3, "!! For better results, consider providing > 1.000 samples !!\n"); - DISPLAYLEVEL(3, "!! Each sample should preferably be stored as a separate file !!\n"); - } - - /* building ... */ - { - ZDICT_params_t param; - param.selectivityLevel = selectionLevel; - param.compressionLevel = cLevel; - DiB_setNotificationLevel(g_displayLevel); - operationResult = DiB_trainFromFiles(dictFileName, maxDictSize, - filenameTable, filenameIdx, - param); - } - - if (main_pause) waitEnter(); - free((void*)filenameTable); - return operationResult; -} diff --git a/dictBuilder/dibio.c b/dictBuilder/dibio.c deleted file mode 100644 index a471d5450..000000000 --- a/dictBuilder/dibio.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - dibio - I/O API for dictionary builder - Copyright (C) Yann Collet 2016 - - GPL v2 License - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - - You can contact the author at : - - zstd homepage : http://www.zstd.net/ -*/ - -/*-************************************** -* Compiler Options -****************************************/ -/* Disable some Visual warning messages */ -#ifdef _MSC_VER -# define _CRT_SECURE_NO_WARNINGS /* fopen */ -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#endif - -/* Unix Large Files support (>4GB) */ -#define _FILE_OFFSET_BITS 64 -#if (defined(__sun__) && (!defined(__LP64__))) /* Sun Solaris 32-bits requires specific definitions */ -# define _LARGEFILE_SOURCE -#elif ! defined(__LP64__) /* No point defining Large file for 64 bit */ -# define _LARGEFILE64_SOURCE -#endif - - -/*-************************************* -* Includes -***************************************/ -#include /* malloc, free */ -#include /* memset */ -#include /* fprintf, fopen, ftello64 */ -#include /* stat64 */ -#include /* stat64 */ -#include /* clock */ - -#include "mem.h" /* read */ -#include "error_private.h" -#include "dictBuilder_static.h" - -/*-************************************* -* Compiler specifics -***************************************/ -#if !defined(S_ISREG) -# define S_ISREG(x) (((x) & S_IFMT) == S_IFREG) -#endif - - -/*-************************************* -* Constants -***************************************/ -#define KB *(1 <<10) -#define MB *(1 <<20) -#define GB *(1U<<30) - -#define DICTLISTSIZE 10000 -#define MEMMULT 11 -static const size_t maxMemory = (sizeof(size_t) == 4) ? (2 GB - 64 MB) : ((size_t)(512 MB) << sizeof(size_t)); - -#define NOISELENGTH 32 -#define PRIME1 2654435761U -#define PRIME2 2246822519U - - -/*-************************************* -* Console display -***************************************/ -#define DISPLAY(...) fprintf(stderr, __VA_ARGS__) -#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } -static unsigned g_displayLevel = 0; /* 0 : no display; 1: errors; 2: default; 4: full information */ -void DiB_setNotificationLevel(unsigned l) { g_displayLevel=l; ZDICT_setNotificationLevel(l); } - -void DiB_printHex(U32 dlevel, const void* ptr, size_t length) -{ - const BYTE* const b = (const BYTE*)ptr; - size_t u; - for (u=0; u126) c = '.'; /* non-printable char */ - DISPLAYLEVEL(dlevel, "%c", c); - } -} - - -/*-************************************* -* Exceptions -***************************************/ -#ifndef DEBUG -# define DEBUG 0 -#endif -#define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__); -#define EXM_THROW(error, ...) \ -{ \ - DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \ - DISPLAYLEVEL(1, "Error %i : ", error); \ - DISPLAYLEVEL(1, __VA_ARGS__); \ - DISPLAYLEVEL(1, "\n"); \ - exit(error); \ -} - - -/* ******************************************************** -* Helper functions -**********************************************************/ -unsigned DiB_isError(size_t errorCode) { return ERR_isError(errorCode); } - -const char* DiB_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); } - - -/* ******************************************************** -* File related operations -**********************************************************/ -static unsigned long long DiB_getFileSize(const char* infilename) -{ - int r; -#if defined(_MSC_VER) - struct _stat64 statbuf; - r = _stat64(infilename, &statbuf); -#else - struct stat statbuf; - r = stat(infilename, &statbuf); -#endif - if (r || !S_ISREG(statbuf.st_mode)) return 0; /* No good... */ - return (unsigned long long)statbuf.st_size; -} - - -static unsigned long long DiB_getTotalFileSize(const char** fileNamesTable, unsigned nbFiles) -{ - unsigned long long total = 0; - unsigned n; - for (n=0; n bufferSize-pos) fileSize = 0; /* stop there, not enough memory to load all files */ - readSize = fread(buff+pos, 1, (size_t)fileSize, f); - if (readSize != (size_t)fileSize) EXM_THROW(11, "could not read %s", fileNamesTable[n]); - pos += readSize; - fileSizes[n] = (size_t)fileSize; - fclose(f); - } -} - - -/*-******************************************************** -* Dictionary training functions -**********************************************************/ -static size_t DiB_findMaxMem(unsigned long long requiredMem) -{ - size_t step = 8 MB; - void* testmem = NULL; - - requiredMem = (((requiredMem >> 23) + 1) << 23); - requiredMem += 2 * step; - if (requiredMem > maxMemory) requiredMem = maxMemory; - - while (!testmem) { - requiredMem -= step; - testmem = malloc((size_t)requiredMem); - } - - free(testmem); - return (size_t)(requiredMem - step); -} - - -static void DiB_fillNoise(void* buffer, size_t length) -{ - unsigned acc = PRIME1; - size_t p=0;; - - for (p=0; p> 21); - } -} - - -static void DiB_saveDict(const char* dictFileName, - const void* buff, size_t buffSize) -{ - FILE* f; - size_t n; - - f = fopen(dictFileName, "wb"); - if (f==NULL) EXM_THROW(3, "cannot open %s ", dictFileName); - - n = fwrite(buff, 1, buffSize, f); - if (n!=buffSize) EXM_THROW(4, "%s : write error", dictFileName) - - n = (size_t)fclose(f); - if (n!=0) EXM_THROW(5, "%s : flush error", dictFileName) -} - - -int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, - const char** fileNamesTable, unsigned nbFiles, - ZDICT_params_t params) -{ - void* srcBuffer; - size_t benchedSize; - size_t* fileSizes = (size_t*)malloc(nbFiles * sizeof(size_t)); - unsigned long long totalSizeToLoad = DiB_getTotalFileSize(fileNamesTable, nbFiles); - void* dictBuffer = malloc(maxDictSize); - size_t dictSize; - int result = 0; - - /* init */ - benchedSize = DiB_findMaxMem(totalSizeToLoad * MEMMULT) / MEMMULT; - if ((unsigned long long)benchedSize > totalSizeToLoad) benchedSize = (size_t)totalSizeToLoad; - if (benchedSize < totalSizeToLoad) - DISPLAYLEVEL(1, "Not enough memory; training on %u MB only...\n", (unsigned)(benchedSize >> 20)); - - /* Memory allocation & restrictions */ - srcBuffer = malloc(benchedSize+NOISELENGTH); /* + noise */ - if ((!fileSizes) || (!srcBuffer) || (!dictBuffer)) EXM_THROW(12, "not enough memory for DiB_trainFiles"); /* should not happen */ - - /* Load input buffer */ - DiB_loadFiles(srcBuffer, benchedSize, fileSizes, fileNamesTable, nbFiles); - DiB_fillNoise((char*)srcBuffer + benchedSize, NOISELENGTH); /* guard band, for end of buffer condition */ - - /* call buffer version */ - dictSize = ZDICT_trainFromBuffer_unsafe(dictBuffer, maxDictSize, - srcBuffer, fileSizes, nbFiles, - params); - if (ZDICT_isError(dictSize)) { - DISPLAYLEVEL(1, "dictionary training failed : %s", ZDICT_getErrorName(dictSize)); /* should not happen */ - result = 1; - goto _cleanup; - } - - /* save dict */ - DISPLAYLEVEL(2, "Save dictionary of size %u into file %s \n", (U32)dictSize, dictFileName); - DiB_saveDict(dictFileName, dictBuffer, dictSize); - - /* clean up */ -_cleanup: - free(srcBuffer); - free(dictBuffer); - free(fileSizes); - return result; -} diff --git a/dictBuilder/dibio.h b/dictBuilder/dibio.h deleted file mode 100644 index c9aee1fcd..000000000 --- a/dictBuilder/dibio.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - dibio.h - I/O API for dictionary builder - Copyright (C) Yann Collet 2016 - - GPL v2 License - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - - You can contact the author at : - - zstd source repository : https://github.com/Cyan4973/zstd - - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c -*/ - -/* This library is designed for a single-threaded console application. -* It exit() and printf() into stderr when it encounters an error condition. */ - -#ifndef DIBIO_H_003 -#define DIBIO_H_003 - - -/*-************************************* -* Dependencies -***************************************/ -#include "dictBuilder_static.h" /* ZDICT_params_t */ - - -/*-************************************* -* Public functions -***************************************/ -/*! DiB_trainFromFiles() : - Train a dictionary from a set of files provided by `fileNamesTable`. - Resulting dictionary is written into file `dictFileName`. - `parameters` is optional and can be provided with values set to 0, meaning "default". - @return : 0 == ok. Any other : error. -*/ -int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, - const char** fileNamesTable, unsigned nbFiles, - ZDICT_params_t parameters); - - -/*-************************************* -* Helper functions -***************************************/ -/*! DiB_setNotificationLevel - Set amount of notification to be displayed on the console. - default initial value : 0 = no console notification. - Note : not thread-safe (use a global constant) -*/ -void DiB_setNotificationLevel(unsigned l); - - -#endif diff --git a/dictBuilder/dictionary b/dictBuilder/dictionary deleted file mode 100644 index d6bf575c61f3b366de2c0aadadb0b484deaf377d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112640 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≀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 c = '.'; /* non-printable char */ - DISPLAYLEVEL(dlevel, "%c", c); - } -} - /*-************************************* * Exceptions diff --git a/programs/dibio.h b/programs/dibio.h index 9b8deb54b..4d24cc16a 100644 --- a/programs/dibio.h +++ b/programs/dibio.h @@ -32,7 +32,7 @@ /*-************************************* * Dependencies ***************************************/ -#include "dictBuilder_static.h" /* ZDICT_params_t */ +#include "zdict_static.h" /* ZDICT_params_t */ /*-************************************* From e0a3084d30bc0cc129ee897e90bab7262c62cefb Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 12 Feb 2016 18:48:07 +0100 Subject: [PATCH 089/113] fixed cmake --- contrib/cmake/lib/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/cmake/lib/CMakeLists.txt b/contrib/cmake/lib/CMakeLists.txt index 910e5060d..4294a59e6 100644 --- a/contrib/cmake/lib/CMakeLists.txt +++ b/contrib/cmake/lib/CMakeLists.txt @@ -57,17 +57,17 @@ GetLibraryVersion("${HEADER_CONTENT}" LIBVER_MAJOR LIBVER_MINOR LIBVER_RELEASE) MESSAGE("ZSTD VERSION ${LIBVER_MAJOR}.${LIBVER_MINOR}.${LIBVER_RELEASE}") SET(Sources - ${LIBRARY_DIR}/dictBuilder.c ${LIBRARY_DIR}/divsufsort.c ${LIBRARY_DIR}/fse.c ${LIBRARY_DIR}/huff0.c + ${LIBRARY_DIR}/zdict.c ${LIBRARY_DIR}/zstd_buffered.c ${LIBRARY_DIR}/zstd_compress.c ${LIBRARY_DIR}/zstd_decompress.c) SET(Headers ${LIBRARY_DIR}/bitstream.h - ${LIBRARY_DIR}/dictBuilder.h + ${LIBRARY_DIR}/zdict.h ${LIBRARY_DIR}/error_private.h ${LIBRARY_DIR}/error_public.h ${LIBRARY_DIR}/fse.h From 62ae5fb0d285c33e6c69f159572dd4e95576a115 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 12 Feb 2016 18:59:11 +0100 Subject: [PATCH 090/113] zstd_buffered => zbuff --- contrib/cmake/lib/CMakeLists.txt | 9 +++++---- lib/{zstd_buffered.c => zbuff.c} | 2 +- lib/{zstd_buffered.h => zbuff.h} | 0 lib/{zstd_buffered_static.h => zbuff_static.h} | 2 +- programs/Makefile | 8 ++++---- programs/fileio.c | 2 +- programs/zbufftest.c | 2 +- 7 files changed, 13 insertions(+), 12 deletions(-) rename lib/{zstd_buffered.c => zbuff.c} (99%) rename lib/{zstd_buffered.h => zbuff.h} (100%) rename lib/{zstd_buffered_static.h => zbuff_static.h} (98%) diff --git a/contrib/cmake/lib/CMakeLists.txt b/contrib/cmake/lib/CMakeLists.txt index 4294a59e6..bb2c05755 100644 --- a/contrib/cmake/lib/CMakeLists.txt +++ b/contrib/cmake/lib/CMakeLists.txt @@ -60,14 +60,13 @@ SET(Sources ${LIBRARY_DIR}/divsufsort.c ${LIBRARY_DIR}/fse.c ${LIBRARY_DIR}/huff0.c + ${LIBRARY_DIR}/zbuff.c ${LIBRARY_DIR}/zdict.c - ${LIBRARY_DIR}/zstd_buffered.c ${LIBRARY_DIR}/zstd_compress.c ${LIBRARY_DIR}/zstd_decompress.c) SET(Headers ${LIBRARY_DIR}/bitstream.h - ${LIBRARY_DIR}/zdict.h ${LIBRARY_DIR}/error_private.h ${LIBRARY_DIR}/error_public.h ${LIBRARY_DIR}/fse.h @@ -75,8 +74,10 @@ SET(Headers ${LIBRARY_DIR}/huff0.h ${LIBRARY_DIR}/huff0_static.h ${LIBRARY_DIR}/mem.h - ${LIBRARY_DIR}/zstd_buffered_static.h - ${LIBRARY_DIR}/zstd_buffered.h + ${LIBRARY_DIR}/zbuff.h + ${LIBRARY_DIR}/zbuff_static.h + ${LIBRARY_DIR}/zdict.h + ${LIBRARY_DIR}/zdict_static.h ${LIBRARY_DIR}/zstd_internal.h ${LIBRARY_DIR}/zstd_static.h ${LIBRARY_DIR}/zstd.h) diff --git a/lib/zstd_buffered.c b/lib/zbuff.c similarity index 99% rename from lib/zstd_buffered.c rename to lib/zbuff.c index 133c54e14..4c1eb2cf2 100644 --- a/lib/zstd_buffered.c +++ b/lib/zbuff.c @@ -41,7 +41,7 @@ #include #include "error_private.h" #include "zstd_static.h" -#include "zstd_buffered_static.h" +#include "zbuff_static.h" /* ************************************* diff --git a/lib/zstd_buffered.h b/lib/zbuff.h similarity index 100% rename from lib/zstd_buffered.h rename to lib/zbuff.h diff --git a/lib/zstd_buffered_static.h b/lib/zbuff_static.h similarity index 98% rename from lib/zstd_buffered_static.h rename to lib/zbuff_static.h index a15745c09..405508900 100644 --- a/lib/zstd_buffered_static.h +++ b/lib/zbuff_static.h @@ -45,7 +45,7 @@ extern "C" { * Includes ***************************************/ #include "zstd_static.h" /* ZSTD_parameters */ -#include "zstd_buffered.h" +#include "zbuff.h" /* ************************************* diff --git a/programs/Makefile b/programs/Makefile index e96a0dd20..7da0cc61d 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -84,11 +84,11 @@ default: zstd all: zstd zstd32 fullbench fullbench32 fuzzer fuzzer32 zbufftest zbufftest32 paramgrill datagen -zstd : $(ZSTD_FILES) $(ZSTD_FILES_LEGACY) $(ZSTDDIR)/zstd_buffered.c $(ZSTDDIR)/zdict.c $(ZSTDDIR)/divsufsort.c \ +zstd : $(ZSTD_FILES) $(ZSTD_FILES_LEGACY) $(ZSTDDIR)/zbuff.c $(ZSTDDIR)/zdict.c $(ZSTDDIR)/divsufsort.c \ zstdcli.c fileio.c bench.c xxhash.c datagen.c dibio.c $(CC) $(FLAGS) -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT) $^ -o $@$(EXT) -zstd32: $(ZSTD_FILES) $(ZSTD_FILES_LEGACY) $(ZSTDDIR)/zstd_buffered.c $(ZSTDDIR)/zdict.c $(ZSTDDIR)/divsufsort.c \ +zstd32: $(ZSTD_FILES) $(ZSTD_FILES_LEGACY) $(ZSTDDIR)/zbuff.c $(ZSTDDIR)/zdict.c $(ZSTDDIR)/divsufsort.c \ zstdcli.c fileio.c bench.c xxhash.c datagen.c dibio.c $(CC) -m32 $(FLAGS) -DZSTD_LEGACY_SUPPORT=$(ZSTD_LEGACY_SUPPORT) $^ -o $@$(EXT) @@ -123,11 +123,11 @@ fuzzer32: $(ZSTD_FILES) \ datagen.c xxhash.c fuzzer.c $(CC) -m32 $(FLAGS) $^ -o $@$(EXT) -zbufftest : $(ZSTD_FILES) $(ZSTDDIR)/zstd_buffered.c \ +zbufftest : $(ZSTD_FILES) $(ZSTDDIR)/zbuff.c \ datagen.c xxhash.c zbufftest.c $(CC) $(FLAGS) $^ -o $@$(EXT) -zbufftest32: $(ZSTD_FILES) $(ZSTDDIR)/zstd_buffered.c \ +zbufftest32: $(ZSTD_FILES) $(ZSTDDIR)/zbuff.c \ datagen.c xxhash.c zbufftest.c $(CC) -m32 $(FLAGS) $^ -o $@$(EXT) diff --git a/programs/fileio.c b/programs/fileio.c index ea6e866cf..898f47202 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -65,7 +65,7 @@ #include "mem.h" #include "fileio.h" #include "zstd_static.h" /* ZSTD_magicNumber */ -#include "zstd_buffered_static.h" +#include "zbuff_static.h" #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1) # include "zstd_legacy.h" /* legacy */ diff --git a/programs/zbufftest.c b/programs/zbufftest.c index a8257dfc0..aa57b576a 100644 --- a/programs/zbufftest.c +++ b/programs/zbufftest.c @@ -41,7 +41,7 @@ #include /* timeb */ #include /* strcmp */ #include "mem.h" -#include "zstd_buffered.h" +#include "zbuff.h" #include "zstd.h" /* ZSTD_compressBound() */ #include "datagen.h" /* RDG_genBuffer */ #include "xxhash.h" /* XXH64 */ From 09ab681328ff814f06073f6c0d5321c0f27c0dce Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 12 Feb 2016 19:00:30 +0100 Subject: [PATCH 091/113] fixed libzstd install --- lib/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index 2b724b7b7..6bdf2f876 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -118,7 +118,7 @@ install: libzstd libzstd.pc @cp -a libzstd.pc $(DESTDIR)$(LIBDIR)/pkgconfig/ @install -m 644 libzstd.a $(DESTDIR)$(LIBDIR)/libzstd.a @install -m 644 zstd.h $(DESTDIR)$(INCLUDEDIR)/zstd.h - @install -m 644 zstd.h $(DESTDIR)$(INCLUDEDIR)/zstd_buffered.h + @install -m 644 zstd.h $(DESTDIR)$(INCLUDEDIR)/zbuff.h @install -m 644 zstd.h $(DESTDIR)$(INCLUDEDIR)/zdict.h @echo zstd static and shared library installed @@ -129,7 +129,7 @@ uninstall: @[ -x $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_VER) ] && rm -f $(DESTDIR)$(LIBDIR)/libzstd.$(SHARED_EXT_VER) @[ -f $(DESTDIR)$(LIBDIR)/libzstd.a ] && rm -f $(DESTDIR)$(LIBDIR)/libzstd.a @[ -f $(DESTDIR)$(INCLUDEDIR)/zstd.h ] && rm -f $(DESTDIR)$(INCLUDEDIR)/zstd.h - @[ -f $(DESTDIR)$(INCLUDEDIR)/zstd.h ] && rm -f $(DESTDIR)$(INCLUDEDIR)/zstd_buffered.h + @[ -f $(DESTDIR)$(INCLUDEDIR)/zstd.h ] && rm -f $(DESTDIR)$(INCLUDEDIR)/zbuff.h @[ -f $(DESTDIR)$(INCLUDEDIR)/zstd.h ] && rm -f $(DESTDIR)$(INCLUDEDIR)/zdict.h @echo zstd libraries successfully uninstalled From 6f3acbac0d4de2ea45f6f980500f42eaad3bcf00 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 12 Feb 2016 20:19:48 +0100 Subject: [PATCH 092/113] notificationLevel into ZDICT_param_t --- lib/zdict.c | 4 ++-- lib/zdict_static.h | 28 ++-------------------------- programs/dibio.c | 14 +++++++++++++- programs/dibio.h | 11 ----------- programs/fileio.c | 18 +++++++++--------- programs/zstdcli.c | 4 ++-- 6 files changed, 28 insertions(+), 51 deletions(-) diff --git a/lib/zdict.c b/lib/zdict.c index ec2ffbb70..cd58ab8a9 100644 --- a/lib/zdict.c +++ b/lib/zdict.c @@ -102,7 +102,6 @@ static const size_t g_min_fast_dictContent = 192; #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) #define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } static unsigned g_displayLevel = 0; /* 0 : no display; 1: errors; 2: default; 4: full information */ -void ZDICT_setNotificationLevel(unsigned l) { g_displayLevel=l; } #define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ if (ZDICT_GetMilliSpan(g_time) > refreshRate) \ @@ -111,7 +110,7 @@ void ZDICT_setNotificationLevel(unsigned l) { g_displayLevel=l; } static const unsigned refreshRate = 300; static clock_t g_time = 0; -void ZDICT_printHex(U32 dlevel, const void* ptr, size_t length) +static void ZDICT_printHex(U32 dlevel, const void* ptr, size_t length) { const BYTE* const b = (const BYTE*)ptr; size_t u; @@ -813,6 +812,7 @@ size_t ZDICT_trainFromBuffer_unsafe( { unsigned u; for (u=0, sBuffSize=0; u bigger selection => larger dictionary */ unsigned compressionLevel; /* 0 means default; target a specific zstd compression level */ + unsigned notificationLevel; /* Write to stderr; 0 = none (default); 1 = errors; 2 = progression; 3 = details; 4 = debug; */ + unsigned reserved[3]; /* space for future parameters */ } ZDICT_params_t; @@ -71,32 +73,6 @@ size_t ZDICT_trainFromBuffer_advanced(void* dictBuffer, size_t dictBufferCapacit ZDICT_params_t parameters); -/*-************************************* -* Helper functions -***************************************/ -/*! ZDICT_setNotificationLevel() : - Set amount of notification to be displayed on the console. - default : 0 = no console notification. - 1 = errors; 2 = notifications; 3 = details; 4 = debug; - Note : not thread-safe (uses a global constant) -*/ -void ZDICT_setNotificationLevel(unsigned l); - - -/*-************************************* -* Private functions -***************************************/ -/*! ZDICT_trainFromBuffer_unsafe() : - Same as ZDICT_trainFromBuffer_advanced(), but does not control `samplesBuffer`. - note : `samplesBuffer` must be followed by noisy guard band to avoid out-of-buffer reads. - @return : size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) - or an error code. -*/ -size_t ZDICT_trainFromBuffer_unsafe(void* dictBuffer, size_t dictBufferCapacity, - const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, - ZDICT_params_t parameters); - - #if defined (__cplusplus) } #endif diff --git a/programs/dibio.c b/programs/dibio.c index 7b6611536..646fe2c60 100644 --- a/programs/dibio.c +++ b/programs/dibio.c @@ -85,7 +85,6 @@ static const size_t maxMemory = (sizeof(size_t) == 4) ? (2 GB - 64 MB) : ((size_ #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) #define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } static unsigned g_displayLevel = 0; /* 0 : no display; 1: errors; 2: default; 4: full information */ -void DiB_setNotificationLevel(unsigned l) { g_displayLevel=l; ZDICT_setNotificationLevel(l); } /*-************************************* @@ -216,6 +215,18 @@ static void DiB_saveDict(const char* dictFileName, } +/*! ZDICT_trainFromBuffer_unsafe() : + Strictly Internal use only !! + Same as ZDICT_trainFromBuffer_advanced(), but does not control `samplesBuffer`. + `samplesBuffer` must be followed by noisy guard band to avoid out-of-buffer reads. + @return : size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`) + or an error code. +*/ +size_t ZDICT_trainFromBuffer_unsafe(void* dictBuffer, size_t dictBufferCapacity, + const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples, + ZDICT_params_t parameters); + + int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, const char** fileNamesTable, unsigned nbFiles, ZDICT_params_t params) @@ -229,6 +240,7 @@ int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, int result = 0; /* init */ + g_displayLevel = params.notificationLevel; benchedSize = DiB_findMaxMem(totalSizeToLoad * MEMMULT) / MEMMULT; if ((unsigned long long)benchedSize > totalSizeToLoad) benchedSize = (size_t)totalSizeToLoad; if (benchedSize < totalSizeToLoad) diff --git a/programs/dibio.h b/programs/dibio.h index 4d24cc16a..0ccec4135 100644 --- a/programs/dibio.h +++ b/programs/dibio.h @@ -49,15 +49,4 @@ int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize, ZDICT_params_t parameters); -/*-************************************* -* Helper functions -***************************************/ -/*! DiB_setNotificationLevel - Set amount of notification to be displayed on the console. - default initial value : 0 = no console notification. - Note : not thread-safe (use a global constant) -*/ -void DiB_setNotificationLevel(unsigned l); - - #endif diff --git a/programs/fileio.c b/programs/fileio.c index 898f47202..003e1bd51 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -52,7 +52,7 @@ #define _POSIX_SOURCE 1 /* enable fileno() within on unix */ -/* ************************************* +/*-************************************* * Includes ***************************************/ #include /* fprintf, fopen, fread, _fileno, stdin, stdout */ @@ -68,12 +68,12 @@ #include "zbuff_static.h" #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1) -# include "zstd_legacy.h" /* legacy */ -# include "fileio_legacy.h" /* legacy */ +# include "zstd_legacy.h" /* ZSTD_isLegacy */ +# include "fileio_legacy.h" /* FIO_decompressLegacyFrame */ #endif -/* ************************************* +/*-************************************* * OS-specific Includes ***************************************/ #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) @@ -92,7 +92,7 @@ #endif -/* ************************************* +/*-************************************* * Constants ***************************************/ #define KB *(1U<<10) @@ -112,12 +112,13 @@ #define BLOCKSIZE (128 KB) #define ROLLBUFFERSIZE (BLOCKSIZE*8*64) -#define FIO_FRAMEHEADERSIZE 5 /* as a define, because needed to allocated table on stack */ -#define FSE_CHECKSUM_SEED 0 +#define FIO_FRAMEHEADERSIZE 5 /* as a define, because needed to allocated table on stack */ +#define FSE_CHECKSUM_SEED 0 #define CACHELINE 64 -#define MAX_DICT_SIZE (512 KB) +#define MAX_DICT_SIZE (1 MB) /* protection against large input (attack scenario) ; can be changed */ + /* ************************************* * Macros @@ -138,7 +139,6 @@ static clock_t g_time = 0; * Local Parameters ***************************************/ static U32 g_overwrite = 0; - void FIO_overwriteMode(void) { g_overwrite=1; } void FIO_setNotificationLevel(unsigned level) { g_displayLevel=level; } diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 22c8c8182..c8a372828 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -133,7 +133,7 @@ static int usage_advanced(const char* programName) DISPLAY( " -c : force write to standard output, even if it is the console\n"); #ifndef ZSTD_NODICT DISPLAY( "Dictionary builder :\n"); - DISPLAY( "--train : Create a dictionary from a set of files \n"); + DISPLAY( "--train : create a dictionary from a training set of files \n"); DISPLAY( " -o file: `file` is dictionary name (default: %s) \n", g_defaultDictName); DISPLAY( "--maxdict:limit dictionary to specified size (default : %u) \n", g_defaultMaxDictSize); DISPLAY( " -s# : dictionary selectivity level (default: %u)\n", g_defaultSelectivityLevel); @@ -366,7 +366,7 @@ int main(int argCount, const char** argv) ZDICT_params_t dictParams; dictParams.compressionLevel = dictCLevel; dictParams.selectivityLevel = dictSelect; - DiB_setNotificationLevel(displayLevel); + dictParams.notificationLevel = displayLevel; DiB_trainFromFiles(outFileName, maxDictSize, filenameTable, filenameIdx, dictParams); #endif goto _end; From 82f4d7da03c516a08c32f0220e3132b92574ac59 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 12 Feb 2016 22:04:49 +0100 Subject: [PATCH 093/113] Fixed Visual solution --- lib/divsufsort.c | 3 +- lib/zdict.c | 1 - lib/zstd_opt.h | 4 +- visual/2013/dictBuilder/dictBuilder.vcxproj | 183 ------------------ .../dictBuilder/dictBuilder.vcxproj.filters | 75 ------- visual/2013/fullbench/fullbench.vcxproj | 3 - .../2013/fullbench/fullbench.vcxproj.filters | 9 - visual/2013/zstd.sln | 14 +- visual/2013/zstd/zstd.vcxproj | 11 +- visual/2013/zstd/zstd.vcxproj.filters | 33 +++- visual/2013/zstdlib/zstdlib.vcxproj | 6 +- visual/2013/zstdlib/zstdlib.vcxproj.filters | 18 +- 12 files changed, 58 insertions(+), 302 deletions(-) delete mode 100644 visual/2013/dictBuilder/dictBuilder.vcxproj delete mode 100644 visual/2013/dictBuilder/dictBuilder.vcxproj.filters diff --git a/lib/divsufsort.c b/lib/divsufsort.c index 9f45df590..60cceb088 100644 --- a/lib/divsufsort.c +++ b/lib/divsufsort.c @@ -30,7 +30,8 @@ #endif #if defined(_MSC_VER) - #pragma warning(disable : 4244) +# pragma warning(disable : 4244) +# pragma warning(disable : 4127) /* C4127 : Condition expression is constant */ #endif diff --git a/lib/zdict.c b/lib/zdict.c index cd58ab8a9..d3d5784dd 100644 --- a/lib/zdict.c +++ b/lib/zdict.c @@ -36,7 +36,6 @@ ****************************************/ /* Disable some Visual warning messages */ #ifdef _MSC_VER -# define _CRT_SECURE_NO_WARNINGS /* fopen */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ #endif diff --git a/lib/zstd_opt.h b/lib/zstd_opt.h index 1ea88f103..f3e9bd225 100644 --- a/lib/zstd_opt.h +++ b/lib/zstd_opt.h @@ -416,8 +416,8 @@ static U32 ZSTD_HcGetAllMatches_selectMLS_extDict ( *********************************/ FORCE_INLINE void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, - const void* src, size_t srcSize, - const U32 searchMethod, const U32 depth) + const void* src, size_t srcSize, + const U32 searchMethod, const U32 depth) { seqStore_t* seqStorePtr = &(ctx->seqStore); const BYTE* const istart = (const BYTE*)src; diff --git a/visual/2013/dictBuilder/dictBuilder.vcxproj b/visual/2013/dictBuilder/dictBuilder.vcxproj deleted file mode 100644 index 0260102b5..000000000 --- a/visual/2013/dictBuilder/dictBuilder.vcxproj +++ /dev/null @@ -1,183 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {D4C01A3D-F609-4DA6-B53F-88D063CCE993} - Win32Proj - fuzzer - - - - Application - true - v120 - Unicode - - - Application - true - v120 - Unicode - - - Application - false - v120 - true - Unicode - - - Application - false - v120 - true - Unicode - - - - - - - - - - - - - - - - - - - true - $(SolutionDir)..\..\lib;$(SolutionDir)..\..\lib\legacy;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath); - true - - - true - $(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath); - true - - - false - $(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath); - true - - - false - $(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath); - true - - - - - - Level4 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - /analyze:stacksize25000 %(AdditionalOptions) - - - Console - true - setargv.obj;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - - - Level4 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - /analyze:stacksize25000 %(AdditionalOptions) - - - Console - true - - - - - Level4 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - /analyze:stacksize25000 %(AdditionalOptions) - - - Console - true - true - true - - - - - Level4 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - /analyze:stacksize25000 %(AdditionalOptions) - - - Console - true - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/visual/2013/dictBuilder/dictBuilder.vcxproj.filters b/visual/2013/dictBuilder/dictBuilder.vcxproj.filters deleted file mode 100644 index a38cc30e9..000000000 --- a/visual/2013/dictBuilder/dictBuilder.vcxproj.filters +++ /dev/null @@ -1,75 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Fichiers sources - - - Fichiers sources - - - Fichiers sources - - - Fichiers sources - - - Fichiers sources - - - Fichiers sources - - - Fichiers sources - - - Fichiers sources - - - Fichiers sources - - - - - Fichiers d%27en-tête - - - Fichiers d%27en-tête - - - Fichiers d%27en-tête - - - Fichiers d%27en-tête - - - Fichiers d%27en-tête - - - Fichiers d%27en-tête - - - Fichiers d%27en-tête - - - Fichiers d%27en-tête - - - Fichiers d%27en-tête - - - \ No newline at end of file diff --git a/visual/2013/fullbench/fullbench.vcxproj b/visual/2013/fullbench/fullbench.vcxproj index c0d737682..3797960f4 100644 --- a/visual/2013/fullbench/fullbench.vcxproj +++ b/visual/2013/fullbench/fullbench.vcxproj @@ -161,9 +161,6 @@ - - - diff --git a/visual/2013/fullbench/fullbench.vcxproj.filters b/visual/2013/fullbench/fullbench.vcxproj.filters index c3db19768..3a82000fb 100644 --- a/visual/2013/fullbench/fullbench.vcxproj.filters +++ b/visual/2013/fullbench/fullbench.vcxproj.filters @@ -24,24 +24,15 @@ Fichiers sources - - Fichiers sources - Fichiers sources - - Fichiers sources - Fichiers sources Fichiers sources - - Fichiers sources - diff --git a/visual/2013/zstd.sln b/visual/2013/zstd.sln index c132ddda6..3186fc670 100644 --- a/visual/2013/zstd.sln +++ b/visual/2013/zstd.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +# Visual Studio 2013 +VisualStudioVersion = 12.0.40629.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zstd", "zstd\zstd.vcxproj", "{4E52A41A-F33B-4C7A-8C36-A1A6B4F4277C}" EndProject @@ -11,8 +11,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fullbench", "fullbench\full EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zstdlib", "zstdlib\zstdlib.vcxproj", "{8BFD8150-94D5-4BF9-8A50-7BD9929A0850}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dictBuilder", "dictBuilder\dictBuilder.vcxproj", "{D4C01A3D-F609-4DA6-B53F-88D063CCE993}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -53,14 +51,6 @@ Global {8BFD8150-94D5-4BF9-8A50-7BD9929A0850}.Release|Win32.Build.0 = Release|Win32 {8BFD8150-94D5-4BF9-8A50-7BD9929A0850}.Release|x64.ActiveCfg = Release|x64 {8BFD8150-94D5-4BF9-8A50-7BD9929A0850}.Release|x64.Build.0 = Release|x64 - {D4C01A3D-F609-4DA6-B53F-88D063CCE993}.Debug|Win32.ActiveCfg = Debug|Win32 - {D4C01A3D-F609-4DA6-B53F-88D063CCE993}.Debug|Win32.Build.0 = Debug|Win32 - {D4C01A3D-F609-4DA6-B53F-88D063CCE993}.Debug|x64.ActiveCfg = Debug|x64 - {D4C01A3D-F609-4DA6-B53F-88D063CCE993}.Debug|x64.Build.0 = Debug|x64 - {D4C01A3D-F609-4DA6-B53F-88D063CCE993}.Release|Win32.ActiveCfg = Release|Win32 - {D4C01A3D-F609-4DA6-B53F-88D063CCE993}.Release|Win32.Build.0 = Release|Win32 - {D4C01A3D-F609-4DA6-B53F-88D063CCE993}.Release|x64.ActiveCfg = Release|x64 - {D4C01A3D-F609-4DA6-B53F-88D063CCE993}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/visual/2013/zstd/zstd.vcxproj b/visual/2013/zstd/zstd.vcxproj index 1c3f0d1f2..453197690 100644 --- a/visual/2013/zstd/zstd.vcxproj +++ b/visual/2013/zstd/zstd.vcxproj @@ -19,23 +19,27 @@ + - + + + + @@ -45,6 +49,10 @@ + + + + @@ -52,6 +60,7 @@ + diff --git a/visual/2013/zstd/zstd.vcxproj.filters b/visual/2013/zstd/zstd.vcxproj.filters index e8ab9fe58..31a978019 100644 --- a/visual/2013/zstd/zstd.vcxproj.filters +++ b/visual/2013/zstd/zstd.vcxproj.filters @@ -48,9 +48,6 @@ Fichiers sources - - Fichiers sources - Fichiers sources @@ -60,6 +57,18 @@ Fichiers sources + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + @@ -119,5 +128,23 @@ Fichiers d%27en-tête + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers sources + + + Fichiers d%27en-tête + \ No newline at end of file diff --git a/visual/2013/zstdlib/zstdlib.vcxproj b/visual/2013/zstdlib/zstdlib.vcxproj index 05a03ab8d..b13bc98ff 100644 --- a/visual/2013/zstdlib/zstdlib.vcxproj +++ b/visual/2013/zstdlib/zstdlib.vcxproj @@ -21,7 +21,7 @@ - + @@ -34,9 +34,9 @@ + + - - diff --git a/visual/2013/zstdlib/zstdlib.vcxproj.filters b/visual/2013/zstdlib/zstdlib.vcxproj.filters index e4bdf7dbf..ffb457b0b 100644 --- a/visual/2013/zstdlib/zstdlib.vcxproj.filters +++ b/visual/2013/zstdlib/zstdlib.vcxproj.filters @@ -21,15 +21,15 @@ Source Files - - Source Files - Source Files Source Files + + Source Files + @@ -59,12 +59,6 @@ Header Files - - Header Files - - - Header Files - Header Files @@ -74,6 +68,12 @@ Header Files + + Header Files + + + Header Files + From 23e8aee224ac02500c6ad98ed3a5d4f6ff6efc6f Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 13 Feb 2016 02:07:24 +0100 Subject: [PATCH 094/113] Introduced new compression level settings Changed position of parameter TargetLength --- lib/zstd_compress.c | 196 ++++++++++++++++++++---------------------- lib/zstd_opt.h | 21 ++--- lib/zstd_static.h | 4 +- programs/paramgrill.c | 2 +- 4 files changed, 103 insertions(+), 120 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 83337b901..ed42de61f 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -74,6 +74,7 @@ size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + /*-************************************* * Sequence storage ***************************************/ +/** ZSTD_resetFreqs() : for opt variants */ static void ZSTD_resetFreqs(seqStore_t* ssPtr) { unsigned u; @@ -99,8 +100,6 @@ static void ZSTD_resetSeqStore(seqStore_t* ssPtr) ssPtr->litLength = ssPtr->litLengthStart; ssPtr->matchLength = ssPtr->matchLengthStart; ssPtr->dumps = ssPtr->dumpsStart; - - ZSTD_resetFreqs(ssPtr); } @@ -2261,122 +2260,109 @@ size_t ZSTD_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSi /*-===== Pre-defined compression levels =====-*/ -#define ZSTD_MAX_CLEVEL 25 +#define ZSTD_MAX_CLEVEL 21 unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { /* "default" */ - /* SL, W, C, H, S, L, strat */ - { 0, 0, 18, 12, 12, 1, 4, ZSTD_fast }, /* level 0 - never used */ - { 0, 0, 19, 13, 14, 1, 7, ZSTD_fast }, /* level 1 */ - { 0, 0, 19, 15, 16, 1, 6, ZSTD_fast }, /* level 2 */ - { 0, 0, 20, 18, 20, 1, 6, ZSTD_fast }, /* level 3 */ - { 0, 0, 21, 19, 21, 1, 6, ZSTD_fast }, /* level 4 */ - { 0, 0, 20, 14, 18, 3, 5, ZSTD_greedy }, /* level 5 */ - { 0, 0, 20, 18, 19, 3, 5, ZSTD_greedy }, /* level 6 */ - { 0, 0, 21, 17, 20, 3, 5, ZSTD_lazy }, /* level 7 */ - { 0, 0, 21, 19, 20, 3, 5, ZSTD_lazy }, /* level 8 */ - { 0, 0, 21, 20, 20, 3, 5, ZSTD_lazy2 }, /* level 9 */ - { 0, 0, 21, 19, 21, 4, 5, ZSTD_lazy2 }, /* level 10 */ - { 0, 0, 22, 20, 22, 4, 5, ZSTD_lazy2 }, /* level 11 */ // 42498419 - { 0, 0, 22, 20, 22, 5, 5, ZSTD_lazy2 }, /* level 12 */ - { 0, 0, 22, 21, 22, 5, 5, ZSTD_lazy2 }, /* level 13 */ - { 0, 0, 22, 22, 23, 5, 5, ZSTD_lazy2 }, /* level 14 */ - { 0, 0, 23, 23, 23, 5, 5, ZSTD_lazy2 }, /* level 15 */ - { 0, 0, 23, 21, 22, 5, 5, ZSTD_btlazy2 }, /* level 16 */ // 42113689 - { 0, 0, 23, 24, 23, 4, 5, ZSTD_btlazy2 }, /* level 17 */ - { 0, 0, 25, 24, 23, 5, 5, ZSTD_btlazy2 }, /* level 18 */ - { 0, 0, 25, 26, 23, 5, 5, ZSTD_btlazy2 }, /* level 19 */ - { 0, 12, 22, 20, 21, 3, 5, ZSTD_opt }, /* level 20 */ - { 0, 16, 23, 21, 22, 4, 4, ZSTD_opt }, /* level 21 */ - { 0, 32, 25, 25, 24, 5, 4, ZSTD_opt_bt }, /* level 22 */ - { 0, 64, 25, 26, 24, 6, 4, ZSTD_opt_bt }, /* level 23 */ - { 0,128, 26, 26, 25, 8, 4, ZSTD_opt_bt }, /* level 24 */ - { 0,256, 26, 27, 25, 10, 4, ZSTD_opt_bt }, /* level 25 */ + /* l, W, C, H, S, L, SL, strat */ + { 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */ + { 0, 19, 13, 14, 1, 7, 4, ZSTD_fast }, /* level 1 */ + { 0, 19, 15, 16, 1, 6, 4, ZSTD_fast }, /* level 2 */ + { 0, 20, 18, 20, 1, 6, 4, ZSTD_fast }, /* level 3 */ + { 0, 21, 19, 21, 1, 6, 4, ZSTD_fast }, /* level 4 */ + { 0, 20, 14, 18, 3, 5, 4, ZSTD_greedy }, /* level 5 */ + { 0, 20, 18, 19, 3, 5, 4, ZSTD_greedy }, /* level 6 */ + { 0, 21, 17, 20, 3, 5, 4, ZSTD_lazy }, /* level 7 */ + { 0, 21, 19, 20, 3, 5, 4, ZSTD_lazy }, /* level 8 */ + { 0, 21, 20, 20, 3, 5, 4, ZSTD_lazy2 }, /* level 9 */ + { 0, 21, 19, 21, 4, 5, 4, ZSTD_lazy2 }, /* level 10 */ + { 0, 22, 20, 22, 4, 5, 4, ZSTD_lazy2 }, /* level 11 */ + { 0, 22, 20, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 12 */ + { 0, 22, 21, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 13 */ + { 0, 22, 22, 23, 5, 5, 4, ZSTD_lazy2 }, /* level 14 */ + { 0, 23, 23, 23, 5, 5, 4, ZSTD_lazy2 }, /* level 15 */ + { 0, 23, 21, 22, 5, 5, 4, ZSTD_btlazy2 }, /* level 16 */ + { 0, 23, 24, 23, 4, 5, 4, ZSTD_btlazy2 }, /* level 17 */ + { 0, 24, 25, 24, 4, 4, 24, ZSTD_opt_bt }, /* level 18 */ + { 0, 25, 25, 24, 5, 4, 40, ZSTD_opt_bt }, /* level 19 */ + { 0, 26, 26, 25, 8, 4,256, ZSTD_opt_bt }, /* level 20 */ + { 0, 26, 27, 25, 10, 4,256, ZSTD_opt_bt }, /* level 21 */ }, { /* for srcSize <= 256 KB */ /* SL, W, C, H, S, L, strat */ - { 0, 0, 18, 13, 14, 1, 7, ZSTD_fast }, /* level 0 - never used */ - { 0, 0, 18, 14, 15, 1, 6, ZSTD_fast }, /* level 1 */ - { 0, 0, 18, 14, 15, 1, 5, ZSTD_fast }, /* level 2 */ - { 0, 0, 18, 12, 15, 3, 4, ZSTD_greedy }, /* level 3 */ - { 0, 0, 18, 13, 15, 4, 4, ZSTD_greedy }, /* level 4 */ - { 0, 0, 18, 14, 15, 5, 4, ZSTD_greedy }, /* level 5 */ - { 0, 0, 18, 13, 15, 4, 4, ZSTD_lazy }, /* level 6 */ - { 0, 0, 18, 14, 16, 5, 4, ZSTD_lazy }, /* level 7 */ - { 0, 0, 18, 15, 16, 6, 4, ZSTD_lazy }, /* level 8 */ - { 0, 0, 18, 15, 15, 7, 4, ZSTD_lazy }, /* level 9 */ - { 0, 0, 18, 16, 16, 7, 4, ZSTD_lazy }, /* level 10 */ - { 0, 0, 18, 16, 16, 8, 4, ZSTD_lazy }, /* level 11 */ - { 0, 0, 18, 17, 16, 8, 4, ZSTD_lazy }, /* level 12 */ - { 0, 0, 18, 17, 16, 9, 4, ZSTD_lazy }, /* level 13 */ - { 0, 0, 18, 18, 16, 9, 4, ZSTD_lazy }, /* level 14 */ - { 0, 0, 18, 17, 17, 9, 4, ZSTD_lazy2 }, /* level 15 */ - { 0, 0, 18, 18, 18, 9, 4, ZSTD_lazy2 }, /* level 16 */ - { 0, 0, 18, 18, 18, 10, 4, ZSTD_lazy2 }, /* level 17 */ - { 0, 0, 18, 18, 18, 11, 4, ZSTD_lazy2 }, /* level 18 */ - { 0, 0, 18, 18, 18, 12, 4, ZSTD_lazy2 }, /* level 19 */ - { 0, 0, 18, 18, 18, 13, 4, ZSTD_lazy2 }, /* level 20 */ - { 0, 0, 18, 18, 18, 10, 4, ZSTD_lazy2 }, /* level ??? */ - { 0, 0, 18, 18, 18, 11, 4, ZSTD_lazy2 }, /* level ??? */ - { 0, 0, 18, 18, 18, 12, 4, ZSTD_lazy2 }, /* level ??? */ - { 0, 0, 18, 18, 18, 13, 4, ZSTD_lazy2 }, /* level ??? */ + { 0, 18, 13, 14, 1, 7, 4, ZSTD_fast }, /* level 0 - never used */ + { 0, 18, 14, 15, 1, 6, 4, ZSTD_fast }, /* level 1 */ + { 0, 18, 14, 15, 1, 5, 4, ZSTD_fast }, /* level 2 */ + { 0, 18, 12, 15, 3, 4, 4, ZSTD_greedy }, /* level 3 */ + { 0, 18, 13, 15, 4, 4, 4, ZSTD_greedy }, /* level 4 */ + { 0, 18, 14, 15, 5, 4, 4, ZSTD_greedy }, /* level 5 */ + { 0, 18, 13, 15, 4, 4, 4, ZSTD_lazy }, /* level 6 */ + { 0, 18, 14, 16, 5, 4, 4, ZSTD_lazy }, /* level 7 */ + { 0, 18, 15, 16, 6, 4, 4, ZSTD_lazy }, /* level 8 */ + { 0, 18, 15, 15, 7, 4, 4, ZSTD_lazy }, /* level 9 */ + { 0, 18, 16, 16, 7, 4, 4, ZSTD_lazy }, /* level 10 */ + { 0, 18, 16, 16, 8, 4, 4, ZSTD_lazy }, /* level 11 */ + { 0, 18, 17, 16, 8, 4, 4, ZSTD_lazy }, /* level 12 */ + { 0, 18, 17, 16, 9, 4, 4, ZSTD_lazy }, /* level 13 */ + { 0, 18, 18, 16, 9, 4, 4, ZSTD_lazy }, /* level 14 */ + { 0, 18, 17, 17, 9, 4, 4, ZSTD_lazy2 }, /* level 15 */ + { 0, 18, 18, 18, 9, 4, 4, ZSTD_lazy2 }, /* level 16 */ + { 0, 18, 18, 18, 10, 4, 4, ZSTD_lazy2 }, /* level 17 */ + { 0, 18, 18, 18, 11, 4, 4, ZSTD_lazy2 }, /* level 18 */ + { 0, 18, 18, 18, 12, 4, 4, ZSTD_lazy2 }, /* level 19 */ + { 0, 18, 18, 18, 13, 4, 4, ZSTD_lazy2 }, /* level 20 */ + { 0, 18, 18, 18, 10, 4, 4, ZSTD_lazy2 }, /* level ??? */ }, { /* for srcSize <= 128 KB */ /* W, C, H, S, L, strat */ - { 0, 0, 17, 12, 12, 1, 4, ZSTD_fast }, /* level 0 - never used */ - { 0, 0, 17, 12, 13, 1, 6, ZSTD_fast }, /* level 1 */ - { 0, 0, 17, 14, 16, 1, 5, ZSTD_fast }, /* level 2 */ - { 0, 0, 17, 15, 17, 1, 5, ZSTD_fast }, /* level 3 */ - { 0, 0, 17, 13, 15, 2, 4, ZSTD_greedy }, /* level 4 */ - { 0, 0, 17, 15, 17, 3, 4, ZSTD_greedy }, /* level 5 */ - { 0, 0, 17, 14, 17, 3, 4, ZSTD_lazy }, /* level 6 */ - { 0, 0, 17, 16, 17, 4, 4, ZSTD_lazy }, /* level 7 */ - { 0, 0, 17, 16, 17, 4, 4, ZSTD_lazy2 }, /* level 8 */ - { 0, 0, 17, 17, 16, 5, 4, ZSTD_lazy2 }, /* level 9 */ - { 0, 0, 17, 17, 16, 6, 4, ZSTD_lazy2 }, /* level 10 */ - { 0, 0, 17, 17, 16, 7, 4, ZSTD_lazy2 }, /* level 11 */ - { 0, 0, 17, 17, 16, 8, 4, ZSTD_lazy2 }, /* level 12 */ - { 0, 0, 17, 18, 16, 4, 4, ZSTD_btlazy2 }, /* level 13 */ - { 0, 0, 17, 18, 16, 5, 4, ZSTD_btlazy2 }, /* level 14 */ - { 0, 0, 17, 18, 16, 6, 4, ZSTD_btlazy2 }, /* level 15 */ - { 0, 0, 17, 18, 16, 7, 4, ZSTD_btlazy2 }, /* level 16 */ - { 0, 0, 17, 18, 16, 8, 4, ZSTD_btlazy2 }, /* level 17 */ - { 0, 0, 17, 18, 16, 9, 4, ZSTD_btlazy2 }, /* level 18 */ - { 0, 0, 17, 18, 16, 10, 4, ZSTD_btlazy2 }, /* level 19 */ - { 0, 0, 17, 18, 18, 12, 4, ZSTD_btlazy2 }, /* level 20 */ - { 0, 0, 17, 18, 16, 8, 4, ZSTD_btlazy2 }, /* level ??? */ - { 0, 0, 17, 18, 16, 9, 4, ZSTD_btlazy2 }, /* level ??? */ - { 0, 0, 17, 18, 16, 10, 4, ZSTD_btlazy2 }, /* level ??? */ - { 0, 0, 17, 18, 18, 12, 4, ZSTD_btlazy2 }, /* level ??? */ + { 0, 17, 12, 12, 1, 4, 4, ZSTD_fast }, /* level 0 - never used */ + { 0, 17, 12, 13, 1, 6, 4, ZSTD_fast }, /* level 1 */ + { 0, 17, 14, 16, 1, 5, 4, ZSTD_fast }, /* level 2 */ + { 0, 17, 15, 17, 1, 5, 4, ZSTD_fast }, /* level 3 */ + { 0, 17, 13, 15, 2, 4, 4, ZSTD_greedy }, /* level 4 */ + { 0, 17, 15, 17, 3, 4, 4, ZSTD_greedy }, /* level 5 */ + { 0, 17, 14, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ + { 0, 17, 16, 17, 4, 4, 4, ZSTD_lazy }, /* level 7 */ + { 0, 17, 16, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */ + { 0, 17, 17, 16, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */ + { 0, 17, 17, 16, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */ + { 0, 17, 17, 16, 5, 4, 8, ZSTD_opt }, /* level 11 */ + { 0, 17, 17, 16, 6, 4,12, ZSTD_opt }, /* level 12 */ + { 0, 17, 18, 16, 4, 4, 4, ZSTD_btlazy2 }, /* level 13 */ + { 0, 17, 18, 16, 5, 4, 4, ZSTD_btlazy2 }, /* level 14 */ + { 0, 17, 18, 16, 6, 4, 4, ZSTD_btlazy2 }, /* level 15 */ + { 0, 17, 17, 16, 7, 4,16, ZSTD_opt }, /* level 16 */ + { 0, 17, 18, 16, 5, 4,20, ZSTD_opt_bt }, /* level 17 */ + { 0, 17, 18, 16, 6, 4,32, ZSTD_opt_bt }, /* level 18 */ + { 0, 17, 18, 16, 7, 4,64, ZSTD_opt_bt }, /* level 19 */ + { 0, 17, 18, 17, 9, 4,128, ZSTD_opt_bt }, /* level 20 */ + { 0, 17, 18, 17, 12, 4,256, ZSTD_opt_bt }, /* level ??? */ }, { /* for srcSize <= 16 KB */ /* W, C, H, S, L, strat */ - { 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */ - { 0, 0, 14, 14, 14, 1, 4, ZSTD_fast }, /* level 1 */ - { 0, 0, 14, 14, 16, 1, 4, ZSTD_fast }, /* level 2 */ - { 0, 0, 14, 14, 14, 5, 4, ZSTD_greedy }, /* level 3 */ - { 0, 0, 14, 14, 14, 8, 4, ZSTD_greedy }, /* level 4 */ - { 0, 0, 14, 11, 14, 6, 4, ZSTD_lazy }, /* level 5 */ - { 0, 0, 14, 14, 13, 6, 5, ZSTD_lazy }, /* level 6 */ - { 0, 0, 14, 14, 14, 7, 6, ZSTD_lazy }, /* level 7 */ - { 0, 0, 14, 14, 14, 8, 4, ZSTD_lazy }, /* level 8 */ - { 0, 0, 14, 14, 15, 9, 4, ZSTD_lazy }, /* level 9 */ - { 0, 0, 14, 14, 15, 10, 4, ZSTD_lazy }, /* level 10 */ - { 0, 0, 14, 15, 15, 6, 4, ZSTD_btlazy2 }, /* level 11 */ - { 0, 0, 14, 15, 15, 7, 4, ZSTD_btlazy2 }, /* level 12 */ - { 0, 0, 14, 15, 15, 8, 4, ZSTD_btlazy2 }, /* level 13 */ - { 0, 0, 14, 15, 15, 9, 4, ZSTD_btlazy2 }, /* level 14 */ - { 0, 0, 14, 15, 15, 10, 4, ZSTD_btlazy2 }, /* level 15 */ - { 0, 0, 14, 15, 15, 11, 4, ZSTD_btlazy2 }, /* level 16 */ - { 0, 0, 14, 15, 15, 12, 4, ZSTD_btlazy2 }, /* level 17 */ - { 0, 0, 14, 15, 15, 13, 4, ZSTD_btlazy2 }, /* level 18 */ - { 0, 0, 14, 15, 15, 14, 4, ZSTD_btlazy2 }, /* level 19 */ - { 0, 0, 14, 15, 15, 15, 4, ZSTD_btlazy2 }, /* level 20 */ - { 0, 0, 14, 15, 15, 12, 4, ZSTD_btlazy2 }, /* level ??? */ - { 0, 0, 14, 15, 15, 13, 4, ZSTD_btlazy2 }, /* level ??? */ - { 0, 0, 14, 15, 15, 14, 4, ZSTD_btlazy2 }, /* level ??? */ - { 0, 0, 14, 15, 15, 15, 4, ZSTD_btlazy2 }, /* level ??? */ + { 0, 0, 0, 0, 0, 0, 4, ZSTD_fast }, /* level 0 - never used */ + { 0, 14, 14, 14, 1, 4, 4, ZSTD_fast }, /* level 1 */ + { 0, 14, 14, 16, 1, 4, 4, ZSTD_fast }, /* level 2 */ + { 0, 14, 14, 14, 5, 4, 4, ZSTD_greedy }, /* level 3 */ + { 0, 14, 14, 14, 8, 4, 4, ZSTD_greedy }, /* level 4 */ + { 0, 14, 11, 14, 6, 4, 4, ZSTD_lazy }, /* level 5 */ + { 0, 14, 14, 13, 6, 5, 4, ZSTD_lazy }, /* level 6 */ + { 0, 14, 14, 14, 7, 6, 4, ZSTD_lazy }, /* level 7 */ + { 0, 14, 14, 14, 8, 4, 4, ZSTD_lazy }, /* level 8 */ + { 0, 14, 14, 15, 9, 4, 4, ZSTD_lazy }, /* level 9 */ + { 0, 14, 14, 15, 10, 4, 4, ZSTD_lazy }, /* level 10 */ + { 0, 14, 15, 15, 6, 4, 4, ZSTD_btlazy2 }, /* level 11 */ + { 0, 14, 15, 15, 7, 4, 4, ZSTD_btlazy2 }, /* level 12 */ + { 0, 14, 15, 15, 8, 4, 4, ZSTD_btlazy2 }, /* level 13 */ + { 0, 14, 15, 15, 9, 4, 4, ZSTD_btlazy2 }, /* level 14 */ + { 0, 14, 15, 15, 10, 4, 4, ZSTD_btlazy2 }, /* level 15 */ + { 0, 14, 15, 15, 11, 4, 4, ZSTD_btlazy2 }, /* level 16 */ + { 0, 14, 15, 15, 12, 4, 4, ZSTD_btlazy2 }, /* level 17 */ + { 0, 14, 15, 15, 13, 4, 4, ZSTD_btlazy2 }, /* level 18 */ + { 0, 14, 15, 15, 14, 4, 4, ZSTD_btlazy2 }, /* level 19 */ + { 0, 14, 15, 15, 15, 4, 4, ZSTD_btlazy2 }, /* level 20 */ + { 0, 14, 15, 15, 12, 4, 4, ZSTD_btlazy2 }, /* level ??? */ }, }; diff --git a/lib/zstd_opt.h b/lib/zstd_opt.h index f3e9bd225..2512f803b 100644 --- a/lib/zstd_opt.h +++ b/lib/zstd_opt.h @@ -446,6 +446,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, /* init */ ZSTD_resetSeqStore(seqStorePtr); + ZSTD_resetFreqs(seqStorePtr); if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE; /* Match Loop */ @@ -514,13 +515,9 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, mlen++; } } - if (last_pos < MINMATCH) { - // ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */ - ip++; continue; - } + if (last_pos < MINMATCH) { ip++; continue; } - - // check further positions + /* check further positions */ for (skip_num = 0, cur = 1; cur <= last_pos; cur++) { size_t cur_rep; inr = ip + cur; @@ -607,7 +604,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, ZSTD_LOG_PARSER("%d: Found REP mlen=%d off=%d price=%d litlen=%d price[%d]=%d\n", (int)(inr-base), mlen, 0, price, litlen, cur - litlen, opt[cur - litlen].price); do { - if (cur + mlen > last_pos || price <= opt[cur + mlen].price) // || ((price == opt[cur + mlen].price) && (opt[cur].mlen == 1) && (cur != litlen))) // at equal price prefer REP instead of MATCH + if (cur + mlen > last_pos || price <= opt[cur + mlen].price) SET_PRICE(cur + mlen, mlen, 0, litlen, price); mlen--; } while (mlen >= MINMATCH); @@ -665,7 +662,7 @@ void ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx, // printf("%d: start=%d best_mlen=%d best_off=%d cur=%d\n", (int)(ip - base), (int)(start - ip), (int)best_mlen, (int)best_off, cur); /* store sequence */ -_storeSequence: // cur, last_pos, best_mlen, best_off have to be set +_storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */ for (u = 1; u <= last_pos; u++) ZSTD_LOG_PARSER("%d: price[%d/%d]=%d off=%d mlen=%d litlen=%d rep=%d rep2=%d\n", (int)(ip-base+u), u, last_pos, opt[u].price, opt[u].off, opt[u].mlen, opt[u].litlen, opt[u].rep, opt[u].rep2); ZSTD_LOG_PARSER("%d: cur=%d/%d best_mlen=%d best_off=%d rep=%d\n", (int)(ip-base+cur), (int)cur, (int)last_pos, (int)best_mlen, (int)best_off, opt[cur].rep); @@ -681,8 +678,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set opt[cur].off = best_off; best_mlen = mlen; best_off = offset; - if (mlen > cur) - break; + if (mlen > cur) break; cur -= mlen; } @@ -736,7 +732,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set ZSTD_updatePrice(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, mlen-MINMATCH); anchor = ip = ip + mlen; - } + } /* for (cur=0; cur < last_pos; ) */ /* check immediate repcode */ while ( (anchor <= ilimit) @@ -751,7 +747,7 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, best_mlen); anchor += best_mlen+MINMATCH; ip = anchor; - continue; // faster when present ... (?) + continue; /* faster when present ... (?) */ } } { /* Last Literals */ @@ -798,6 +794,7 @@ void ZSTD_compressBlock_opt_extDict_generic(ZSTD_CCtx* ctx, /* init */ ZSTD_resetSeqStore(seqStorePtr); + ZSTD_resetFreqs(seqStorePtr); if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE; /* Match Loop */ diff --git a/lib/zstd_static.h b/lib/zstd_static.h index f695ccc06..be30d6a63 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -71,12 +71,12 @@ typedef enum { ZSTD_fast, ZSTD_greedy, ZSTD_lazy, ZSTD_lazy2, ZSTD_btlazy2, ZSTD typedef struct { U64 srcSize; /* optional : tells how much bytes are present in the frame. Use 0 if not known. */ - U32 targetLength; /* acceptable match size for optimal parser (only) : larger == more compression, slower */ U32 windowLog; /* largest match distance : larger == more compression, more memory needed during decompression */ U32 contentLog; /* full search segment : larger == more compression, slower, more memory (useless for fast) */ U32 hashLog; /* dispatch table : larger == faster, more memory */ U32 searchLog; /* nb of searches : larger == more compression, slower */ - U32 searchLength; /* size of matches : larger == faster decompression, sometimes less compression */ + U32 searchLength; /* match length searched : larger == faster decompression, sometimes less compression */ + U32 targetLength; /* acceptable match size for optimal parser (only) : larger == more compression, slower */ ZSTD_strategy strategy; } ZSTD_parameters; diff --git a/programs/paramgrill.c b/programs/paramgrill.c index 5ba3afab2..5e496b6b8 100644 --- a/programs/paramgrill.c +++ b/programs/paramgrill.c @@ -433,7 +433,7 @@ static void BMK_printWinners2(FILE* f, const winnerInfo_t* winners, size_t srcSi unsigned cLevel; fprintf(f, "\n /* Proposed configurations : */ \n"); - fprintf(f, " /* l, W, C, H, S, L, strat */ \n"); + fprintf(f, " /* l, W, C, H, S, L, T, strat */ \n"); for (cLevel=0; cLevel <= ZSTD_maxCLevel(); cLevel++) BMK_printWinner(f, cLevel, winners[cLevel].result, winners[cLevel].params, srcSize); From e8bd73df80cefcd13a66f2517283680542217d7c Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 13 Feb 2016 03:09:48 +0100 Subject: [PATCH 095/113] Fixed : error when compressing one file --- lib/zstd_compress.c | 4 ++-- programs/zstdcli.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index ed42de61f..f22c99996 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -2282,8 +2282,8 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 22, 21, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 13 */ { 0, 22, 22, 23, 5, 5, 4, ZSTD_lazy2 }, /* level 14 */ { 0, 23, 23, 23, 5, 5, 4, ZSTD_lazy2 }, /* level 15 */ - { 0, 23, 21, 22, 5, 5, 4, ZSTD_btlazy2 }, /* level 16 */ - { 0, 23, 24, 23, 4, 5, 4, ZSTD_btlazy2 }, /* level 17 */ + { 0, 23, 22, 22, 5, 5, 4, ZSTD_btlazy2 }, /* level 16 */ + { 0, 24, 24, 23, 4, 5, 4, ZSTD_btlazy2 }, /* level 17 */ { 0, 24, 25, 24, 4, 4, 24, ZSTD_opt_bt }, /* level 18 */ { 0, 25, 25, 24, 5, 4, 40, ZSTD_opt_bt }, /* level 19 */ { 0, 26, 26, 25, 8, 4,256, ZSTD_opt_bt }, /* level 20 */ diff --git a/programs/zstdcli.c b/programs/zstdcli.c index c8a372828..cd285f515 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -392,12 +392,12 @@ int main(int argCount, const char** argv) /* IO Stream/File */ FIO_setNotificationLevel(displayLevel); if (decode) { - if (filenameIdx==1) + if (filenameIdx==1 && outFileName) operationResult = FIO_decompressFilename(outFileName, filenameTable[0], dictFileName); else operationResult = FIO_decompressMultipleFilenames(filenameTable, filenameIdx, forceStdout ? NULL : ZSTD_EXTENSION, dictFileName); } else { /* compression */ - if (filenameIdx==1) + if (filenameIdx==1 && outFileName) operationResult = FIO_compressFilename(outFileName, filenameTable[0], dictFileName, cLevel); else operationResult = FIO_compressMultipleFilenames(filenameTable, filenameIdx, forceStdout ? NULL : ZSTD_EXTENSION, dictFileName, cLevel); From 8154c3d7e277b4f8ab870cd32b0fc0c2490dae13 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 13 Feb 2016 03:12:10 +0100 Subject: [PATCH 096/113] added simple one file test --- programs/playTests.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/programs/playTests.sh b/programs/playTests.sh index c9778d960..069acc134 100755 --- a/programs/playTests.sh +++ b/programs/playTests.sh @@ -23,6 +23,10 @@ roundTripTest() { [ -n "$ZSTD" ] || die "ZSTD variable must be defined!" +echo "\n**** simple test **** " +./datagen > tmp +$ZSTD tmp + echo "\n**** frame concatenation **** " echo "hello " > hello.tmp From 38fba56483c8f3d0489e8fc72498f623ef5dec67 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 13 Feb 2016 11:20:23 +0100 Subject: [PATCH 097/113] Changed compression level settings --- lib/zstd_compress.c | 61 +++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index f22c99996..a1c7d2652 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -2315,29 +2315,30 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 18, 18, 18, 10, 4, 4, ZSTD_lazy2 }, /* level ??? */ }, { /* for srcSize <= 128 KB */ - /* W, C, H, S, L, strat */ - { 0, 17, 12, 12, 1, 4, 4, ZSTD_fast }, /* level 0 - never used */ - { 0, 17, 12, 13, 1, 6, 4, ZSTD_fast }, /* level 1 */ - { 0, 17, 14, 16, 1, 5, 4, ZSTD_fast }, /* level 2 */ - { 0, 17, 15, 17, 1, 5, 4, ZSTD_fast }, /* level 3 */ - { 0, 17, 13, 15, 2, 4, 4, ZSTD_greedy }, /* level 4 */ - { 0, 17, 15, 17, 3, 4, 4, ZSTD_greedy }, /* level 5 */ - { 0, 17, 14, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ - { 0, 17, 16, 17, 4, 4, 4, ZSTD_lazy }, /* level 7 */ - { 0, 17, 16, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */ - { 0, 17, 17, 16, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */ - { 0, 17, 17, 16, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */ - { 0, 17, 17, 16, 5, 4, 8, ZSTD_opt }, /* level 11 */ - { 0, 17, 17, 16, 6, 4,12, ZSTD_opt }, /* level 12 */ - { 0, 17, 18, 16, 4, 4, 4, ZSTD_btlazy2 }, /* level 13 */ - { 0, 17, 18, 16, 5, 4, 4, ZSTD_btlazy2 }, /* level 14 */ - { 0, 17, 18, 16, 6, 4, 4, ZSTD_btlazy2 }, /* level 15 */ - { 0, 17, 17, 16, 7, 4,16, ZSTD_opt }, /* level 16 */ - { 0, 17, 18, 16, 5, 4,20, ZSTD_opt_bt }, /* level 17 */ - { 0, 17, 18, 16, 6, 4,32, ZSTD_opt_bt }, /* level 18 */ - { 0, 17, 18, 16, 7, 4,64, ZSTD_opt_bt }, /* level 19 */ - { 0, 17, 18, 17, 9, 4,128, ZSTD_opt_bt }, /* level 20 */ - { 0, 17, 18, 17, 12, 4,256, ZSTD_opt_bt }, /* level ??? */ + /* l, W, C, H, S, L, T, strat */ + { 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */ + { 0, 17, 12, 13, 1, 6, 4, ZSTD_fast }, /* level 1 */ + { 0, 17, 13, 16, 1, 5, 4, ZSTD_fast }, /* level 2 */ + { 0, 17, 13, 14, 2, 5, 4, ZSTD_greedy }, /* level 3 */ + { 0, 17, 13, 15, 3, 4, 4, ZSTD_greedy }, /* level 4 */ + { 0, 17, 15, 17, 4, 4, 4, ZSTD_greedy }, /* level 5 */ + { 0, 17, 16, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ + { 0, 17, 16, 17, 4, 4, 4, ZSTD_lazy }, /* level 7 */ + { 0, 17, 17, 16, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */ + { 0, 17, 17, 16, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */ + { 0, 17, 17, 16, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */ + { 0, 17, 17, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */ + { 0, 17, 17, 17, 8, 4, 4, ZSTD_lazy2 }, /* level 12 */ + { 0, 17, 17, 17, 9, 4, 4, ZSTD_lazy2 }, /* level 13 */ + { 0, 17, 18, 16, 5, 4, 20, ZSTD_opt_bt }, /* level 14 */ + { 0, 17, 18, 16, 9, 4, 48, ZSTD_opt_bt }, /* level 15 */ + { 0, 17, 18, 17, 7, 4,128, ZSTD_opt_bt }, /* level 16 */ + { 0, 17, 18, 17, 8, 4,128, ZSTD_opt_bt }, /* level 17 */ + { 0, 17, 18, 17, 8, 4,256, ZSTD_opt_bt }, /* level 18 */ + { 0, 17, 18, 17, 9, 4,256, ZSTD_opt_bt }, /* level 19 */ + { 0, 17, 18, 17, 10, 4,512, ZSTD_opt_bt }, /* level 20 */ + { 0, 17, 18, 17, 11, 4,512, ZSTD_opt_bt }, /* level 21 */ + }, { /* for srcSize <= 16 KB */ /* W, C, H, S, L, strat */ @@ -2356,13 +2357,13 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 14, 15, 15, 7, 4, 4, ZSTD_btlazy2 }, /* level 12 */ { 0, 14, 15, 15, 8, 4, 4, ZSTD_btlazy2 }, /* level 13 */ { 0, 14, 15, 15, 9, 4, 4, ZSTD_btlazy2 }, /* level 14 */ - { 0, 14, 15, 15, 10, 4, 4, ZSTD_btlazy2 }, /* level 15 */ - { 0, 14, 15, 15, 11, 4, 4, ZSTD_btlazy2 }, /* level 16 */ - { 0, 14, 15, 15, 12, 4, 4, ZSTD_btlazy2 }, /* level 17 */ - { 0, 14, 15, 15, 13, 4, 4, ZSTD_btlazy2 }, /* level 18 */ - { 0, 14, 15, 15, 14, 4, 4, ZSTD_btlazy2 }, /* level 19 */ - { 0, 14, 15, 15, 15, 4, 4, ZSTD_btlazy2 }, /* level 20 */ - { 0, 14, 15, 15, 12, 4, 4, ZSTD_btlazy2 }, /* level ??? */ + { 0, 14, 15, 15, 10, 4, 8, ZSTD_opt }, /* level 15 */ + { 0, 14, 15, 15, 11, 4,12, ZSTD_opt }, /* level 16 */ + { 0, 14, 15, 15, 12, 4,16, ZSTD_opt }, /* level 17 */ + { 0, 14, 15, 15, 13, 4,16, ZSTD_opt_bt }, /* level 18 */ + { 0, 14, 15, 15, 14, 4,32, ZSTD_opt_bt }, /* level 19 */ + { 0, 14, 15, 15, 15, 4,64, ZSTD_opt_bt }, /* level 20 */ + { 0, 14, 15, 15, 12, 4,128,ZSTD_opt_bt }, /* level 21 */ }, }; From 422fd563f3cbf0685941d4d9ce6d5ce52fcefdcb Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 13 Feb 2016 15:07:24 +0100 Subject: [PATCH 098/113] modified : compression Levels for blocks <= 16KB --- lib/zstd_compress.c | 68 ++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index a1c7d2652..01d5dce7d 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -2290,7 +2290,7 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 26, 27, 25, 10, 4,256, ZSTD_opt_bt }, /* level 21 */ }, { /* for srcSize <= 256 KB */ - /* SL, W, C, H, S, L, strat */ + /* SL, W, C, H, S, L,T, strat */ { 0, 18, 13, 14, 1, 7, 4, ZSTD_fast }, /* level 0 - never used */ { 0, 18, 14, 15, 1, 6, 4, ZSTD_fast }, /* level 1 */ { 0, 18, 14, 15, 1, 5, 4, ZSTD_fast }, /* level 2 */ @@ -2300,19 +2300,19 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 18, 13, 15, 4, 4, 4, ZSTD_lazy }, /* level 6 */ { 0, 18, 14, 16, 5, 4, 4, ZSTD_lazy }, /* level 7 */ { 0, 18, 15, 16, 6, 4, 4, ZSTD_lazy }, /* level 8 */ - { 0, 18, 15, 15, 7, 4, 4, ZSTD_lazy }, /* level 9 */ - { 0, 18, 16, 16, 7, 4, 4, ZSTD_lazy }, /* level 10 */ - { 0, 18, 16, 16, 8, 4, 4, ZSTD_lazy }, /* level 11 */ - { 0, 18, 17, 16, 8, 4, 4, ZSTD_lazy }, /* level 12 */ - { 0, 18, 17, 16, 9, 4, 4, ZSTD_lazy }, /* level 13 */ - { 0, 18, 18, 16, 9, 4, 4, ZSTD_lazy }, /* level 14 */ + { 0, 18, 15, 15, 5, 4, 8, ZSTD_opt }, /* level 9 */ + { 0, 18, 16, 16, 6, 4,12, ZSTD_opt }, /* level 10 */ + { 0, 18, 16, 16, 7, 4,16, ZSTD_opt }, /* level 11 */ + { 0, 18, 17, 16, 8, 4,20, ZSTD_opt }, /* level 12 */ + { 0, 18, 17, 16, 9, 4,24, ZSTD_opt }, /* level 13 */ + { 0, 18, 18, 16, 9, 4,32, ZSTD_opt }, /* level 14 */ { 0, 18, 17, 17, 9, 4, 4, ZSTD_lazy2 }, /* level 15 */ { 0, 18, 18, 18, 9, 4, 4, ZSTD_lazy2 }, /* level 16 */ { 0, 18, 18, 18, 10, 4, 4, ZSTD_lazy2 }, /* level 17 */ - { 0, 18, 18, 18, 11, 4, 4, ZSTD_lazy2 }, /* level 18 */ - { 0, 18, 18, 18, 12, 4, 4, ZSTD_lazy2 }, /* level 19 */ - { 0, 18, 18, 18, 13, 4, 4, ZSTD_lazy2 }, /* level 20 */ - { 0, 18, 18, 18, 10, 4, 4, ZSTD_lazy2 }, /* level ??? */ + { 0, 18, 19, 18, 11, 4, 4, ZSTD_btlazy2 }, /* level 18 */ + { 0, 18, 19, 18, 12, 4,32, ZSTD_opt_bt }, /* level 19 */ + { 0, 18, 19, 18, 13, 4,64, ZSTD_opt_bt }, /* level 20 */ + { 0, 18, 19, 18, 10, 4,128,ZSTD_opt_bt }, /* level 21 */ }, { /* for srcSize <= 128 KB */ /* l, W, C, H, S, L, T, strat */ @@ -2341,29 +2341,29 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { }, { /* for srcSize <= 16 KB */ - /* W, C, H, S, L, strat */ - { 0, 0, 0, 0, 0, 0, 4, ZSTD_fast }, /* level 0 - never used */ - { 0, 14, 14, 14, 1, 4, 4, ZSTD_fast }, /* level 1 */ - { 0, 14, 14, 16, 1, 4, 4, ZSTD_fast }, /* level 2 */ - { 0, 14, 14, 14, 5, 4, 4, ZSTD_greedy }, /* level 3 */ - { 0, 14, 14, 14, 8, 4, 4, ZSTD_greedy }, /* level 4 */ - { 0, 14, 11, 14, 6, 4, 4, ZSTD_lazy }, /* level 5 */ - { 0, 14, 14, 13, 6, 5, 4, ZSTD_lazy }, /* level 6 */ - { 0, 14, 14, 14, 7, 6, 4, ZSTD_lazy }, /* level 7 */ - { 0, 14, 14, 14, 8, 4, 4, ZSTD_lazy }, /* level 8 */ - { 0, 14, 14, 15, 9, 4, 4, ZSTD_lazy }, /* level 9 */ - { 0, 14, 14, 15, 10, 4, 4, ZSTD_lazy }, /* level 10 */ - { 0, 14, 15, 15, 6, 4, 4, ZSTD_btlazy2 }, /* level 11 */ - { 0, 14, 15, 15, 7, 4, 4, ZSTD_btlazy2 }, /* level 12 */ - { 0, 14, 15, 15, 8, 4, 4, ZSTD_btlazy2 }, /* level 13 */ - { 0, 14, 15, 15, 9, 4, 4, ZSTD_btlazy2 }, /* level 14 */ - { 0, 14, 15, 15, 10, 4, 8, ZSTD_opt }, /* level 15 */ - { 0, 14, 15, 15, 11, 4,12, ZSTD_opt }, /* level 16 */ - { 0, 14, 15, 15, 12, 4,16, ZSTD_opt }, /* level 17 */ - { 0, 14, 15, 15, 13, 4,16, ZSTD_opt_bt }, /* level 18 */ - { 0, 14, 15, 15, 14, 4,32, ZSTD_opt_bt }, /* level 19 */ - { 0, 14, 15, 15, 15, 4,64, ZSTD_opt_bt }, /* level 20 */ - { 0, 14, 15, 15, 12, 4,128,ZSTD_opt_bt }, /* level 21 */ + /* l, W, C, H, S, L, T, strat */ + { 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 -- never used */ + { 0, 14, 14, 14, 1, 4, 4, ZSTD_fast }, /* level 1 */ + { 0, 14, 14, 15, 1, 4, 4, ZSTD_fast }, /* level 2 */ + { 0, 14, 13, 15, 4, 4, 4, ZSTD_greedy }, /* level 3 */ + { 0, 14, 14, 15, 3, 4, 4, ZSTD_lazy }, /* level 4 */ + { 0, 14, 14, 14, 6, 4, 4, ZSTD_lazy }, /* level 5 */ + { 0, 14, 14, 14, 5, 4, 4, ZSTD_lazy2 }, /* level 6 */ + { 0, 14, 14, 14, 7, 4, 4, ZSTD_lazy2 }, /* level 7 */ + { 0, 14, 14, 14, 8, 4, 4, ZSTD_lazy2 }, /* level 8 */ + { 0, 14, 14, 14, 9, 4, 4, ZSTD_lazy2 }, /* level 9 */ + { 0, 14, 14, 14, 10, 4, 4, ZSTD_lazy2 }, /* level 10 */ + { 0, 14, 14, 14, 11, 4, 4, ZSTD_lazy2 }, /* level 11 */ + { 0, 14, 15, 15, 12, 4, 32, ZSTD_opt_bt }, /* level 12 */ + { 0, 14, 15, 15, 12, 4, 64, ZSTD_opt_bt }, /* level 13 */ + { 0, 14, 15, 15, 12, 4, 96, ZSTD_opt_bt }, /* level 14 */ + { 0, 14, 15, 15, 12, 4,128, ZSTD_opt_bt }, /* level 15 */ + { 0, 14, 15, 15, 12, 4,256, ZSTD_opt_bt }, /* level 16 */ + { 0, 14, 15, 15, 13, 4,256, ZSTD_opt_bt }, /* level 17 */ + { 0, 14, 15, 15, 14, 4,256, ZSTD_opt_bt }, /* level 18 */ + { 0, 14, 15, 15, 15, 4,256, ZSTD_opt_bt }, /* level 19 */ + { 0, 14, 15, 15, 16, 4,256, ZSTD_opt_bt }, /* level 20 */ + { 0, 14, 15, 15, 17, 4,256, ZSTD_opt_bt }, /* level 21 */ }, }; From 0d78a333742950e6632ffeb4e75a8101133c0804 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 15 Feb 2016 06:49:09 +0100 Subject: [PATCH 099/113] updated CLevel confs for 256K --- lib/zstd_compress.c | 46 ++++++++++++++++++++++----------------------- lib/zstd_static.h | 2 +- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 01d5dce7d..0a71d9847 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -2290,29 +2290,29 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 26, 27, 25, 10, 4,256, ZSTD_opt_bt }, /* level 21 */ }, { /* for srcSize <= 256 KB */ - /* SL, W, C, H, S, L,T, strat */ - { 0, 18, 13, 14, 1, 7, 4, ZSTD_fast }, /* level 0 - never used */ - { 0, 18, 14, 15, 1, 6, 4, ZSTD_fast }, /* level 1 */ - { 0, 18, 14, 15, 1, 5, 4, ZSTD_fast }, /* level 2 */ - { 0, 18, 12, 15, 3, 4, 4, ZSTD_greedy }, /* level 3 */ - { 0, 18, 13, 15, 4, 4, 4, ZSTD_greedy }, /* level 4 */ - { 0, 18, 14, 15, 5, 4, 4, ZSTD_greedy }, /* level 5 */ - { 0, 18, 13, 15, 4, 4, 4, ZSTD_lazy }, /* level 6 */ - { 0, 18, 14, 16, 5, 4, 4, ZSTD_lazy }, /* level 7 */ - { 0, 18, 15, 16, 6, 4, 4, ZSTD_lazy }, /* level 8 */ - { 0, 18, 15, 15, 5, 4, 8, ZSTD_opt }, /* level 9 */ - { 0, 18, 16, 16, 6, 4,12, ZSTD_opt }, /* level 10 */ - { 0, 18, 16, 16, 7, 4,16, ZSTD_opt }, /* level 11 */ - { 0, 18, 17, 16, 8, 4,20, ZSTD_opt }, /* level 12 */ - { 0, 18, 17, 16, 9, 4,24, ZSTD_opt }, /* level 13 */ - { 0, 18, 18, 16, 9, 4,32, ZSTD_opt }, /* level 14 */ - { 0, 18, 17, 17, 9, 4, 4, ZSTD_lazy2 }, /* level 15 */ - { 0, 18, 18, 18, 9, 4, 4, ZSTD_lazy2 }, /* level 16 */ - { 0, 18, 18, 18, 10, 4, 4, ZSTD_lazy2 }, /* level 17 */ - { 0, 18, 19, 18, 11, 4, 4, ZSTD_btlazy2 }, /* level 18 */ - { 0, 18, 19, 18, 12, 4,32, ZSTD_opt_bt }, /* level 19 */ - { 0, 18, 19, 18, 13, 4,64, ZSTD_opt_bt }, /* level 20 */ - { 0, 18, 19, 18, 10, 4,128,ZSTD_opt_bt }, /* level 21 */ + /* l, W, C, H, S, L, T, strat */ + { 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 */ + { 0, 18, 14, 15, 1, 6, 4, ZSTD_fast }, /* level 1 */ + { 0, 18, 14, 16, 1, 5, 4, ZSTD_fast }, /* level 2 */ + { 0, 18, 14, 17, 1, 5, 4, ZSTD_fast }, /* level 3.*/ + { 0, 18, 14, 15, 4, 4, 4, ZSTD_greedy }, /* level 4 */ + { 0, 18, 16, 17, 4, 4, 4, ZSTD_greedy }, /* level 5 */ + { 0, 18, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ + { 0, 18, 17, 17, 4, 4, 4, ZSTD_lazy }, /* level 7 */ + { 0, 18, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */ + { 0, 18, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */ + { 0, 18, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */ + { 0, 18, 17, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */ + { 0, 18, 18, 17, 4, 4, 4, ZSTD_btlazy2 }, /* level 12 */ + { 0, 18, 19, 17, 7, 4, 4, ZSTD_btlazy2 }, /* level 13.*/ + { 0, 18, 17, 19, 8, 4, 24, ZSTD_opt_bt }, /* level 14.*/ + { 0, 18, 19, 19, 8, 4, 48, ZSTD_opt_bt }, /* level 15.*/ + { 0, 18, 19, 18, 9, 4,128, ZSTD_opt_bt }, /* level 16.*/ + { 0, 18, 19, 18, 9, 4,192, ZSTD_opt_bt }, /* level 17.*/ + { 0, 18, 19, 18, 9, 4,256, ZSTD_opt_bt }, /* level 18.*/ + { 0, 18, 19, 18, 10, 4,256, ZSTD_opt_bt }, /* level 19.*/ + { 0, 18, 19, 18, 11, 4,256, ZSTD_opt_bt }, /* level 20.*/ + { 0, 18, 19, 18, 12, 4,256, ZSTD_opt_bt }, /* level 21.*/ }, { /* for srcSize <= 128 KB */ /* l, W, C, H, S, L, T, strat */ diff --git a/lib/zstd_static.h b/lib/zstd_static.h index be30d6a63..00ac0b901 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -59,7 +59,7 @@ extern "C" { #define ZSTD_CONTENTLOG_MAX (ZSTD_WINDOWLOG_MAX+1) #define ZSTD_CONTENTLOG_MIN 4 #define ZSTD_HASHLOG_MAX 28 -#define ZSTD_HASHLOG_MIN 4 +#define ZSTD_HASHLOG_MIN 12 #define ZSTD_SEARCHLOG_MAX (ZSTD_CONTENTLOG_MAX-1) #define ZSTD_SEARCHLOG_MIN 1 #define ZSTD_SEARCHLENGTH_MAX 7 From cefef8cde7d6dfec2a0eb44b20be24fd1cab6632 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 15 Feb 2016 07:21:54 +0100 Subject: [PATCH 100/113] Change : zstd_opt_bt => zstd_btopt --- lib/zstd_compress.c | 68 +++++++++++++++++++++---------------------- lib/zstd_static.h | 14 ++++----- programs/fuzzer.c | 2 +- programs/paramgrill.c | 6 ++-- 4 files changed, 45 insertions(+), 45 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 0a71d9847..02386be7c 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -160,7 +160,7 @@ static unsigned ZSTD_highbit(U32 val); optimize for `srcSize` if srcSize > 0 */ void ZSTD_validateParams(ZSTD_parameters* params) { - const U32 btPlus = (params->strategy == ZSTD_btlazy2) || (params->strategy == ZSTD_opt_bt); + const U32 btPlus = (params->strategy == ZSTD_btlazy2) || (params->strategy == ZSTD_btopt); /* validate params */ if (MEM_32bits()) if (params->windowLog > 25) params->windowLog = 25; /* 32 bits mode cannot flush > 24 bits */ @@ -170,7 +170,7 @@ void ZSTD_validateParams(ZSTD_parameters* params) CLAMP(params->searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); CLAMP(params->searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX); CLAMP(params->targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX); - if ((U32)params->strategy>(U32)ZSTD_opt_bt) params->strategy = ZSTD_opt_bt; + if ((U32)params->strategy>(U32)ZSTD_btopt) params->strategy = ZSTD_btopt; /* correct params, to use less memory */ if ((params->srcSize > 0) && (params->srcSize < (1<lowLimit > (1<<30)) { - U32 btplus = (zc->params.strategy == ZSTD_btlazy2) || (zc->params.strategy == ZSTD_opt_bt); + U32 btplus = (zc->params.strategy == ZSTD_btlazy2) || (zc->params.strategy == ZSTD_btopt); U32 contentMask = (1 << (zc->params.contentLog - btplus)) - 1; U32 newLowLimit = zc->lowLimit & contentMask; /* preserve position % contentSize */ U32 correction = zc->lowLimit - newLowLimit; @@ -2055,7 +2055,7 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t break; case ZSTD_btlazy2: - case ZSTD_opt_bt: + case ZSTD_btopt: ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength); break; @@ -2284,10 +2284,10 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 23, 23, 23, 5, 5, 4, ZSTD_lazy2 }, /* level 15 */ { 0, 23, 22, 22, 5, 5, 4, ZSTD_btlazy2 }, /* level 16 */ { 0, 24, 24, 23, 4, 5, 4, ZSTD_btlazy2 }, /* level 17 */ - { 0, 24, 25, 24, 4, 4, 24, ZSTD_opt_bt }, /* level 18 */ - { 0, 25, 25, 24, 5, 4, 40, ZSTD_opt_bt }, /* level 19 */ - { 0, 26, 26, 25, 8, 4,256, ZSTD_opt_bt }, /* level 20 */ - { 0, 26, 27, 25, 10, 4,256, ZSTD_opt_bt }, /* level 21 */ + { 0, 24, 25, 24, 4, 4, 24, ZSTD_btopt }, /* level 18 */ + { 0, 25, 25, 24, 5, 4, 40, ZSTD_btopt }, /* level 19 */ + { 0, 26, 26, 25, 8, 4,256, ZSTD_btopt }, /* level 20 */ + { 0, 26, 27, 25, 10, 4,256, ZSTD_btopt }, /* level 21 */ }, { /* for srcSize <= 256 KB */ /* l, W, C, H, S, L, T, strat */ @@ -2305,14 +2305,14 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 18, 17, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */ { 0, 18, 18, 17, 4, 4, 4, ZSTD_btlazy2 }, /* level 12 */ { 0, 18, 19, 17, 7, 4, 4, ZSTD_btlazy2 }, /* level 13.*/ - { 0, 18, 17, 19, 8, 4, 24, ZSTD_opt_bt }, /* level 14.*/ - { 0, 18, 19, 19, 8, 4, 48, ZSTD_opt_bt }, /* level 15.*/ - { 0, 18, 19, 18, 9, 4,128, ZSTD_opt_bt }, /* level 16.*/ - { 0, 18, 19, 18, 9, 4,192, ZSTD_opt_bt }, /* level 17.*/ - { 0, 18, 19, 18, 9, 4,256, ZSTD_opt_bt }, /* level 18.*/ - { 0, 18, 19, 18, 10, 4,256, ZSTD_opt_bt }, /* level 19.*/ - { 0, 18, 19, 18, 11, 4,256, ZSTD_opt_bt }, /* level 20.*/ - { 0, 18, 19, 18, 12, 4,256, ZSTD_opt_bt }, /* level 21.*/ + { 0, 18, 17, 19, 8, 4, 24, ZSTD_btopt }, /* level 14.*/ + { 0, 18, 19, 19, 8, 4, 48, ZSTD_btopt }, /* level 15.*/ + { 0, 18, 19, 18, 9, 4,128, ZSTD_btopt }, /* level 16.*/ + { 0, 18, 19, 18, 9, 4,192, ZSTD_btopt }, /* level 17.*/ + { 0, 18, 19, 18, 9, 4,256, ZSTD_btopt }, /* level 18.*/ + { 0, 18, 19, 18, 10, 4,256, ZSTD_btopt }, /* level 19.*/ + { 0, 18, 19, 18, 11, 4,256, ZSTD_btopt }, /* level 20.*/ + { 0, 18, 19, 18, 12, 4,256, ZSTD_btopt }, /* level 21.*/ }, { /* for srcSize <= 128 KB */ /* l, W, C, H, S, L, T, strat */ @@ -2330,14 +2330,14 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 17, 17, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */ { 0, 17, 17, 17, 8, 4, 4, ZSTD_lazy2 }, /* level 12 */ { 0, 17, 17, 17, 9, 4, 4, ZSTD_lazy2 }, /* level 13 */ - { 0, 17, 18, 16, 5, 4, 20, ZSTD_opt_bt }, /* level 14 */ - { 0, 17, 18, 16, 9, 4, 48, ZSTD_opt_bt }, /* level 15 */ - { 0, 17, 18, 17, 7, 4,128, ZSTD_opt_bt }, /* level 16 */ - { 0, 17, 18, 17, 8, 4,128, ZSTD_opt_bt }, /* level 17 */ - { 0, 17, 18, 17, 8, 4,256, ZSTD_opt_bt }, /* level 18 */ - { 0, 17, 18, 17, 9, 4,256, ZSTD_opt_bt }, /* level 19 */ - { 0, 17, 18, 17, 10, 4,512, ZSTD_opt_bt }, /* level 20 */ - { 0, 17, 18, 17, 11, 4,512, ZSTD_opt_bt }, /* level 21 */ + { 0, 17, 18, 16, 5, 4, 20, ZSTD_btopt }, /* level 14 */ + { 0, 17, 18, 16, 9, 4, 48, ZSTD_btopt }, /* level 15 */ + { 0, 17, 18, 17, 7, 4,128, ZSTD_btopt }, /* level 16 */ + { 0, 17, 18, 17, 8, 4,128, ZSTD_btopt }, /* level 17 */ + { 0, 17, 18, 17, 8, 4,256, ZSTD_btopt }, /* level 18 */ + { 0, 17, 18, 17, 9, 4,256, ZSTD_btopt }, /* level 19 */ + { 0, 17, 18, 17, 10, 4,512, ZSTD_btopt }, /* level 20 */ + { 0, 17, 18, 17, 11, 4,512, ZSTD_btopt }, /* level 21 */ }, { /* for srcSize <= 16 KB */ @@ -2354,16 +2354,16 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 14, 14, 14, 9, 4, 4, ZSTD_lazy2 }, /* level 9 */ { 0, 14, 14, 14, 10, 4, 4, ZSTD_lazy2 }, /* level 10 */ { 0, 14, 14, 14, 11, 4, 4, ZSTD_lazy2 }, /* level 11 */ - { 0, 14, 15, 15, 12, 4, 32, ZSTD_opt_bt }, /* level 12 */ - { 0, 14, 15, 15, 12, 4, 64, ZSTD_opt_bt }, /* level 13 */ - { 0, 14, 15, 15, 12, 4, 96, ZSTD_opt_bt }, /* level 14 */ - { 0, 14, 15, 15, 12, 4,128, ZSTD_opt_bt }, /* level 15 */ - { 0, 14, 15, 15, 12, 4,256, ZSTD_opt_bt }, /* level 16 */ - { 0, 14, 15, 15, 13, 4,256, ZSTD_opt_bt }, /* level 17 */ - { 0, 14, 15, 15, 14, 4,256, ZSTD_opt_bt }, /* level 18 */ - { 0, 14, 15, 15, 15, 4,256, ZSTD_opt_bt }, /* level 19 */ - { 0, 14, 15, 15, 16, 4,256, ZSTD_opt_bt }, /* level 20 */ - { 0, 14, 15, 15, 17, 4,256, ZSTD_opt_bt }, /* level 21 */ + { 0, 14, 15, 15, 12, 4, 32, ZSTD_btopt }, /* level 12 */ + { 0, 14, 15, 15, 12, 4, 64, ZSTD_btopt }, /* level 13 */ + { 0, 14, 15, 15, 12, 4, 96, ZSTD_btopt }, /* level 14 */ + { 0, 14, 15, 15, 12, 4,128, ZSTD_btopt }, /* level 15 */ + { 0, 14, 15, 15, 12, 4,256, ZSTD_btopt }, /* level 16 */ + { 0, 14, 15, 15, 13, 4,256, ZSTD_btopt }, /* level 17 */ + { 0, 14, 15, 15, 14, 4,256, ZSTD_btopt }, /* level 18 */ + { 0, 14, 15, 15, 15, 4,256, ZSTD_btopt }, /* level 19 */ + { 0, 14, 15, 15, 16, 4,256, ZSTD_btopt }, /* level 20 */ + { 0, 14, 15, 15, 17, 4,256, ZSTD_btopt }, /* level 21 */ }, }; diff --git a/lib/zstd_static.h b/lib/zstd_static.h index 00ac0b901..258327b15 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -32,9 +32,9 @@ #ifndef ZSTD_STATIC_H #define ZSTD_STATIC_H -/* The objects defined into this file shall be considered experimental. - * They are not considered stable, as their prototype may change in the future. - * You can use them for tests, provide feedback, or if you can endure risks of future changes. +/* The prototypes defined within this file are considered experimental. + * They should not be used in the context DLL as they may change in the future. + * Prefer static linking if you need them, to control breaking version changes issues. */ #if defined (__cplusplus) @@ -54,8 +54,6 @@ extern "C" { #define ZSTD_WINDOWLOG_MAX 26 #define ZSTD_WINDOWLOG_MIN 18 #define ZSTD_WINDOWLOG_ABSOLUTEMIN 11 -#define ZSTD_TARGETLENGTH_MIN 4 -#define ZSTD_TARGETLENGTH_MAX 999 #define ZSTD_CONTENTLOG_MAX (ZSTD_WINDOWLOG_MAX+1) #define ZSTD_CONTENTLOG_MIN 4 #define ZSTD_HASHLOG_MAX 28 @@ -64,9 +62,11 @@ extern "C" { #define ZSTD_SEARCHLOG_MIN 1 #define ZSTD_SEARCHLENGTH_MAX 7 #define ZSTD_SEARCHLENGTH_MIN 4 +#define ZSTD_TARGETLENGTH_MIN 4 +#define ZSTD_TARGETLENGTH_MAX 999 /* from faster to stronger */ -typedef enum { ZSTD_fast, ZSTD_greedy, ZSTD_lazy, ZSTD_lazy2, ZSTD_btlazy2, ZSTD_opt, ZSTD_opt_bt } ZSTD_strategy; +typedef enum { ZSTD_fast, ZSTD_greedy, ZSTD_lazy, ZSTD_lazy2, ZSTD_btlazy2, ZSTD_opt, ZSTD_btopt } ZSTD_strategy; typedef struct { @@ -81,7 +81,7 @@ typedef struct } ZSTD_parameters; -/* ************************************* +/*-************************************* * Advanced functions ***************************************/ ZSTDLIB_API unsigned ZSTD_maxCLevel (void); diff --git a/programs/fuzzer.c b/programs/fuzzer.c index c363dbb6e..edc562be6 100644 --- a/programs/fuzzer.c +++ b/programs/fuzzer.c @@ -452,7 +452,7 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit crcOrig = XXH64(sampleBuffer, sampleSize, 0); /* compression test */ - cLevelMod = MAX(1, 38 - (int)(MAX(9, sampleSizeLog) * 2)); /* use high compression levels with small samples, for speed */ + cLevelMod = MAX(1, 38 - (int)(MAX(9, sampleSizeLog) * 2)); /* high levels only for small samples, for manageable speed */ cLevel = (FUZ_rand(&lseed) % cLevelMod) +1; cSize = ZSTD_compressCCtx(ctx, cBuffer, cBufferSize, sampleBuffer, sampleSize, cLevel); CHECK(ZSTD_isError(cSize), "ZSTD_compressCCtx failed"); diff --git a/programs/paramgrill.c b/programs/paramgrill.c index 5e496b6b8..23a54d466 100644 --- a/programs/paramgrill.c +++ b/programs/paramgrill.c @@ -407,7 +407,7 @@ const char* g_stratName[] = { "ZSTD_fast ", "ZSTD_lazy2 ", "ZSTD_btlazy2", "ZSTD_opt ", - "ZSTD_opt_bt " }; + "ZSTD_btopt " }; static void BMK_printWinner(FILE* f, U32 cLevel, BMK_result_t result, ZSTD_parameters params, size_t srcSize) { @@ -549,7 +549,7 @@ static ZSTD_parameters* sanitizeParams(ZSTD_parameters params) g_params = params; if (params.strategy == ZSTD_fast) g_params.contentLog = 0, g_params.searchLog = 0; - if ((params.strategy != ZSTD_opt) && (params.strategy != ZSTD_opt_bt)) + if ((params.strategy != ZSTD_opt) && (params.strategy != ZSTD_btopt )) g_params.targetLength = 0; return &g_params; } @@ -648,7 +648,7 @@ static void potentialRandomParams(ZSTD_parameters* p, U32 inverseChance) p->windowLog = FUZ_rand(&g_rand) % (ZSTD_WINDOWLOG_MAX+1 - ZSTD_WINDOWLOG_MIN) + ZSTD_WINDOWLOG_MIN; p->searchLength=FUZ_rand(&g_rand) % (ZSTD_SEARCHLENGTH_MAX+1 - ZSTD_SEARCHLENGTH_MIN) + ZSTD_SEARCHLENGTH_MIN; p->targetLength=FUZ_rand(&g_rand) % (ZSTD_TARGETLENGTH_MAX+1 - ZSTD_TARGETLENGTH_MIN) + ZSTD_TARGETLENGTH_MIN; - p->strategy = (ZSTD_strategy) (FUZ_rand(&g_rand) % (ZSTD_opt_bt+1)); + p->strategy = (ZSTD_strategy) (FUZ_rand(&g_rand) % (ZSTD_btopt +1)); ZSTD_validateParams(p); } } From b37e0a9241afe2e353b06ea5ea5a88fa2df4c6c4 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 15 Feb 2016 14:07:07 +0100 Subject: [PATCH 101/113] performance tweak : bt search w/ long repeated segments --- lib/zstd_compress.c | 30 ++++++++++++++---------------- lib/zstd_opt.h | 4 ++-- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 02386be7c..a649b3cfe 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -1319,13 +1319,20 @@ static size_t ZSTD_insertBtAndFindBestMatch ( } -static void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls) +#define BT_MAXREF_1 16 +#define BT_MAXREF_2 128 +#define BT_MAXREF (BT_MAXREF_1 + BT_MAXREF_2) +static void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls, U32 extDict, U32 noSkip) { const BYTE* const base = zc->base; const U32 target = (U32)(ip - base); U32 idx = zc->nextToUpdate; - - while(idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0); + if ((!noSkip) && (idx + BT_MAXREF < target)) { + U32 t2 = idx + BT_MAXREF_1; + while(idx < t2) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, extDict); + idx = target - BT_MAXREF_2; + } + while(idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, extDict); } /** Tree updater, providing best match */ @@ -1336,7 +1343,7 @@ static size_t ZSTD_BtFindBestMatch ( const U32 maxNbAttempts, const U32 mls) { if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */ - ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls); + ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls, 0, 0); return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0); } @@ -1357,15 +1364,6 @@ static size_t ZSTD_BtFindBestMatch_selectMLS ( } -static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls) -{ - const BYTE* const base = zc->base; - const U32 target = (U32)(ip - base); - U32 idx = zc->nextToUpdate; - - while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1); -} - /** Tree updater, providing best match */ static size_t ZSTD_BtFindBestMatch_extDict ( @@ -1375,7 +1373,7 @@ static size_t ZSTD_BtFindBestMatch_extDict ( const U32 maxNbAttempts, const U32 mls) { if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */ - ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls); + ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls, 1, 0); return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1); } @@ -2056,7 +2054,7 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t case ZSTD_btlazy2: case ZSTD_btopt: - ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength); + ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength, 0, 1); break; default: @@ -2329,7 +2327,7 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 17, 17, 16, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */ { 0, 17, 17, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */ { 0, 17, 17, 17, 8, 4, 4, ZSTD_lazy2 }, /* level 12 */ - { 0, 17, 17, 17, 9, 4, 4, ZSTD_lazy2 }, /* level 13 */ + { 0, 17, 18, 17, 5, 4, 4, ZSTD_btlazy2 }, /* level 13 */ { 0, 17, 18, 16, 5, 4, 20, ZSTD_btopt }, /* level 14 */ { 0, 17, 18, 16, 9, 4, 48, ZSTD_btopt }, /* level 15 */ { 0, 17, 18, 17, 7, 4,128, ZSTD_btopt }, /* level 16 */ diff --git a/lib/zstd_opt.h b/lib/zstd_opt.h index 2512f803b..9e855c521 100644 --- a/lib/zstd_opt.h +++ b/lib/zstd_opt.h @@ -264,7 +264,7 @@ U32 ZSTD_BtGetAllMatches ( const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, U32 minml) { if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */ - ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls); + ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls, 0, 0); return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 0, matches, minml); } @@ -292,7 +292,7 @@ U32 ZSTD_BtGetAllMatches_extDict ( const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, U32 minml) { if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */ - ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls); + ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls, 1, 0); return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 1, matches, minml); } From b8a6f6824b31b2ea46105c0cddc2c533f028aab6 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 15 Feb 2016 17:06:29 +0100 Subject: [PATCH 102/113] refactored fix to be more generic and applicable to both btlazy2 and btopt --- lib/zstd_compress.c | 43 ++++++++++++++++++++++++++----------------- lib/zstd_opt.h | 4 ++-- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index a649b3cfe..457161565 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -1172,6 +1172,7 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co U32 dummy32; /* to be nullified at the end */ const U32 windowLow = zc->lowLimit; U32 matchEndIdx = current+8; + size_t bestLength = 8; U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0); U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1); predictedSmall += (predictedSmall>0); @@ -1213,8 +1214,11 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co match = base + matchIndex; /* to prepare for next usage of match[matchLength] */ } - if (matchLength > matchEndIdx - matchIndex) - matchEndIdx = matchIndex + (U32)matchLength; + if (matchLength > bestLength) { + bestLength = matchLength; + if (matchLength > matchEndIdx - matchIndex) + matchEndIdx = matchIndex + (U32)matchLength; + } if (ip+matchLength == iend) /* equal : no way to know if inf or sup */ break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */ @@ -1236,7 +1240,9 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co } } *smallerPtr = *largerPtr = 0; - return (matchEndIdx > current + 8) ? (matchEndIdx - current) - 8 : 1; + if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); + if (matchEndIdx > current + 8) return matchEndIdx - current - 8; + return 1; } @@ -1319,20 +1325,14 @@ static size_t ZSTD_insertBtAndFindBestMatch ( } -#define BT_MAXREF_1 16 -#define BT_MAXREF_2 128 -#define BT_MAXREF (BT_MAXREF_1 + BT_MAXREF_2) -static void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls, U32 extDict, U32 noSkip) +static void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls) { const BYTE* const base = zc->base; const U32 target = (U32)(ip - base); U32 idx = zc->nextToUpdate; - if ((!noSkip) && (idx + BT_MAXREF < target)) { - U32 t2 = idx + BT_MAXREF_1; - while(idx < t2) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, extDict); - idx = target - BT_MAXREF_2; - } - while(idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, extDict); + + while(idx < target) + idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0); } /** Tree updater, providing best match */ @@ -1343,7 +1343,7 @@ static size_t ZSTD_BtFindBestMatch ( const U32 maxNbAttempts, const U32 mls) { if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */ - ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls, 0, 0); + ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls); return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0); } @@ -1364,6 +1364,15 @@ static size_t ZSTD_BtFindBestMatch_selectMLS ( } +static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls) +{ + const BYTE* const base = zc->base; + const U32 target = (U32)(ip - base); + U32 idx = zc->nextToUpdate; + + while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1); +} + /** Tree updater, providing best match */ static size_t ZSTD_BtFindBestMatch_extDict ( @@ -1373,7 +1382,7 @@ static size_t ZSTD_BtFindBestMatch_extDict ( const U32 maxNbAttempts, const U32 mls) { if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */ - ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls, 1, 0); + ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls); return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1); } @@ -2054,7 +2063,7 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t case ZSTD_btlazy2: case ZSTD_btopt: - ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength, 0, 1); + ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength); break; default: @@ -2327,7 +2336,7 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { { 0, 17, 17, 16, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */ { 0, 17, 17, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */ { 0, 17, 17, 17, 8, 4, 4, ZSTD_lazy2 }, /* level 12 */ - { 0, 17, 18, 17, 5, 4, 4, ZSTD_btlazy2 }, /* level 13 */ + { 0, 17, 17, 17, 9, 4, 4, ZSTD_lazy2 }, /* level 13 */ { 0, 17, 18, 16, 5, 4, 20, ZSTD_btopt }, /* level 14 */ { 0, 17, 18, 16, 9, 4, 48, ZSTD_btopt }, /* level 15 */ { 0, 17, 18, 17, 7, 4,128, ZSTD_btopt }, /* level 16 */ diff --git a/lib/zstd_opt.h b/lib/zstd_opt.h index 9e855c521..2512f803b 100644 --- a/lib/zstd_opt.h +++ b/lib/zstd_opt.h @@ -264,7 +264,7 @@ U32 ZSTD_BtGetAllMatches ( const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, U32 minml) { if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */ - ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls, 0, 0); + ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls); return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 0, matches, minml); } @@ -292,7 +292,7 @@ U32 ZSTD_BtGetAllMatches_extDict ( const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, U32 minml) { if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */ - ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls, 1, 0); + ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls); return ZSTD_insertBtAndGetAllMatches(zc, ip, iLimit, maxNbAttempts, mls, 1, matches, minml); } From e93add0439efb08414def250cec9d5931b929452 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 15 Feb 2016 17:44:14 +0100 Subject: [PATCH 103/113] Removed `if (matchIndex >= current) return 0;` as recommended by @inikep --- lib/zstd_opt.h | 21 +++++++++------------ programs/fuzzer.c | 4 +++- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/lib/zstd_opt.h b/lib/zstd_opt.h index 2512f803b..6d898400c 100644 --- a/lib/zstd_opt.h +++ b/lib/zstd_opt.h @@ -172,8 +172,7 @@ MEM_STATIC void ZSTD_updatePrice(seqStore_t* seqStorePtr, U32 litLength, const B /*-************************************* * Binary Tree search ***************************************/ -FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ -U32 ZSTD_insertBtAndGetAllMatches ( +static U32 ZSTD_insertBtAndGetAllMatches ( ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, U32 nbCompares, const U32 mls, @@ -201,7 +200,6 @@ U32 ZSTD_insertBtAndGetAllMatches ( U32 dummy32; /* to be nullified at the end */ U32 mnum = 0; - if (matchIndex >= current) return 0; bestLength = MINMATCH-1; hashTable[h] = current; /* Update Hash Table */ @@ -257,8 +255,7 @@ U32 ZSTD_insertBtAndGetAllMatches ( /** Tree updater, providing best match */ -FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ -U32 ZSTD_BtGetAllMatches ( +static U32 ZSTD_BtGetAllMatches ( ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iLimit, const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, U32 minml) @@ -285,8 +282,7 @@ static U32 ZSTD_BtGetAllMatches_selectMLS ( } /** Tree updater, providing best match */ -FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */ -U32 ZSTD_BtGetAllMatches_extDict ( +static U32 ZSTD_BtGetAllMatches_extDict ( ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iLimit, const U32 maxNbAttempts, const U32 mls, ZSTD_match_t* matches, U32 minml) @@ -342,7 +338,6 @@ U32 ZSTD_HcGetAllMatches_generic ( /* HC4 match finder */ matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls); - if (matchIndex >= current) return 0; while ((matchIndex>lowLimit) && (nbAttempts)) { size_t currentMl=0; @@ -746,9 +741,10 @@ _storeSequence: /* cur, last_pos, best_mlen, best_off have to be set */ ZSTD_updatePrice(seqStorePtr, 0, anchor, 0, best_mlen); ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, best_mlen); anchor += best_mlen+MINMATCH; - ip = anchor; continue; /* faster when present ... (?) */ - } } + } + if (anchor > ip) ip = anchor; + } { /* Last Literals */ size_t lastLLSize = iend - anchor; @@ -1112,11 +1108,12 @@ _storeSequence: // cur, last_pos, best_mlen, best_off have to be set ZSTD_updatePrice(seqStorePtr, 0, anchor, 0, mlen-MINMATCH); ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, mlen-MINMATCH); anchor += mlen; - ip = anchor; continue; /* faster when present ... (?) */ } break; - } } + } + if (anchor > ip) ip = anchor; + } { /* Last Literals */ size_t lastLLSize = iend - anchor; diff --git a/programs/fuzzer.c b/programs/fuzzer.c index edc562be6..f09cf06f2 100644 --- a/programs/fuzzer.c +++ b/programs/fuzzer.c @@ -91,6 +91,7 @@ static U32 g_testTime = 0; /********************************************************* * Fuzzer functions *********************************************************/ +#define MIN(a,b) ((a)<(b)?(a):(b)) #define MAX(a,b) ((a)>(b)?(a):(b)) static U32 FUZ_GetMilliStart(void) @@ -452,7 +453,8 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit crcOrig = XXH64(sampleBuffer, sampleSize, 0); /* compression test */ - cLevelMod = MAX(1, 38 - (int)(MAX(9, sampleSizeLog) * 2)); /* high levels only for small samples, for manageable speed */ + //cLevelMod = MAX(1, 38 - (int)(MAX(9, sampleSizeLog) * 2)); /* high levels only for small samples, for manageable speed */ + cLevelMod = MIN( ZSTD_maxCLevel(), (U32)MAX(1, 55 - 3*(int)sampleSizeLog) ); /* high levels only for small samples, for manageable speed */ cLevel = (FUZ_rand(&lseed) % cLevelMod) +1; cSize = ZSTD_compressCCtx(ctx, cBuffer, cBufferSize, sampleBuffer, sampleSize, cLevel); CHECK(ZSTD_isError(cSize), "ZSTD_compressCCtx failed"); From 0068be94d82ce75bad8faa588f78d66180893f19 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 15 Feb 2016 18:42:13 +0100 Subject: [PATCH 104/113] Faster literals cost evaluation (suggested by @inikep) --- lib/zstd_opt.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/zstd_opt.h b/lib/zstd_opt.h index 6d898400c..ec9a2a158 100644 --- a/lib/zstd_opt.h +++ b/lib/zstd_opt.h @@ -79,8 +79,9 @@ FORCE_INLINE U32 ZSTD_getLiteralPriceReal(seqStore_t* seqStorePtr, U32 litLength if (!litLength) return 1; /* special case */ /* literals */ - for (u=0, price=0; u < litLength; u++) - price += ZSTD_highbit(seqStorePtr->litSum) - ZSTD_highbit(seqStorePtr->litFreq[literals[u]]); + price = litLength * ZSTD_highbit(seqStorePtr->litSum); + for (u=0; u < litLength; u++) + price -= ZSTD_highbit(seqStorePtr->litFreq[literals[u]]); /* literal Length */ price += ((litLength >= MaxLL)*8) + ((litLength >= 255+MaxLL)*16) + ((litLength>=(1<<15))*8); From accfd80c375d1c313241bbfe18b22ec7f62dcd19 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 15 Feb 2016 19:33:16 +0100 Subject: [PATCH 105/113] Added : option `-t` to test compressed files integrity --- lib/zstd_internal.h | 1 - lib/zstd_static.h | 6 ++++++ programs/fileio.c | 31 ++++++++++++++++++++----------- programs/fileio.h | 1 - programs/zstdcli.c | 12 ++++++++---- 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/lib/zstd_internal.h b/lib/zstd_internal.h index 318fd55f6..26fc85785 100644 --- a/lib/zstd_internal.h +++ b/lib/zstd_internal.h @@ -50,7 +50,6 @@ /*-************************************* * Common constants ***************************************/ -#define ZSTD_MAGICNUMBER 0xFD2FB525 /* v0.5 */ #define ZSTD_DICT_MAGIC 0xEC30A435 #define KB *(1 <<10) diff --git a/lib/zstd_static.h b/lib/zstd_static.h index 258327b15..61216535b 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -48,6 +48,12 @@ extern "C" { #include "mem.h" +/*-************************************* +* Constants +***************************************/ +#define ZSTD_MAGICNUMBER 0xFD2FB525 /* v0.5 */ + + /*-************************************* * Types ***************************************/ diff --git a/programs/fileio.c b/programs/fileio.c index 003e1bd51..e2ad9e84b 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -587,7 +587,10 @@ static int FIO_decompressSrcFile(dRess_t ress, const char* srcFileName) continue; } #endif /* ZSTD_LEGACY_SUPPORT */ - + if (MEM_readLE32(ress.srcBuffer) != ZSTD_MAGICNUMBER) { + DISPLAYLEVEL(1, "zstd: %s: not in zstd format \n", srcFileName); + return 1; + } filesize += FIO_decompressFrame(ress, dstFile, srcFile, toRead); } @@ -648,13 +651,24 @@ int FIO_decompressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles if (dstFileName==NULL) EXM_THROW(70, "not enough memory for dstFileName"); ress = FIO_createDResources(dictFileName); - if (suffix) { + if (!strcmp(suffix, stdoutmark) || !strcmp(suffix, nulmark)) { + ress.dstFile = FIO_openDstFile(suffix); + if (ress.dstFile == 0) EXM_THROW(71, "cannot open %s", suffix); + for (u=0; u1)) { + if (outFileName && strcmp(outFileName,stdoutmark) && strcmp(outFileName,nulmark) && (filenameIdx>1)) { DISPLAY("Too many files (%u) on the command line. \n", filenameIdx); return filenameIdx; } @@ -395,12 +399,12 @@ int main(int argCount, const char** argv) if (filenameIdx==1 && outFileName) operationResult = FIO_decompressFilename(outFileName, filenameTable[0], dictFileName); else - operationResult = FIO_decompressMultipleFilenames(filenameTable, filenameIdx, forceStdout ? NULL : ZSTD_EXTENSION, dictFileName); + operationResult = FIO_decompressMultipleFilenames(filenameTable, filenameIdx, outFileName ? outFileName : ZSTD_EXTENSION, dictFileName); } else { /* compression */ if (filenameIdx==1 && outFileName) operationResult = FIO_compressFilename(outFileName, filenameTable[0], dictFileName, cLevel); else - operationResult = FIO_compressMultipleFilenames(filenameTable, filenameIdx, forceStdout ? NULL : ZSTD_EXTENSION, dictFileName, cLevel); + operationResult = FIO_compressMultipleFilenames(filenameTable, filenameIdx, outFileName ? outFileName : ZSTD_EXTENSION, dictFileName, cLevel); } _end: From 459a6b712feb742eba5b8e8ce3b64336bc6c20a8 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 15 Feb 2016 20:37:23 +0100 Subject: [PATCH 106/113] Fix corner case multiple files bug Added test cases --- NEWS | 2 ++ programs/fileio.c | 67 ++++++++++++++++++++++++++++--------------- programs/playTests.sh | 20 +++++++++++-- 3 files changed, 63 insertions(+), 26 deletions(-) diff --git a/NEWS b/NEWS index 170f0c824..f6b2d6c91 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,7 @@ v0.5.1 New : Optimal parsing => Very high compression modes, thanks to Przemyslaw Skibinski +Changed : Dictionary builder integrated into libzstd and zstd cli +Fix : high compression modes for big-endian platforms v0.5.0 New : dictionary builder utility diff --git a/programs/fileio.c b/programs/fileio.c index e2ad9e84b..028c7db45 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -120,7 +120,7 @@ #define MAX_DICT_SIZE (1 MB) /* protection against large input (attack scenario) ; can be changed */ -/* ************************************* +/*-************************************* * Macros ***************************************/ #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) @@ -134,8 +134,10 @@ static U32 g_displayLevel = 2; /* 0 : no display; 1: errors; 2 : + result static const unsigned refreshRate = 150; static clock_t g_time = 0; +#define MAX(a,b) ((a)>(b)?(a):(b)) -/* ************************************* + +/*-************************************* * Local Parameters ***************************************/ static U32 g_overwrite = 0; @@ -143,7 +145,7 @@ void FIO_overwriteMode(void) { g_overwrite=1; } void FIO_setNotificationLevel(unsigned level) { g_displayLevel=level; } -/* ************************************* +/*-************************************* * Exceptions ***************************************/ #ifndef DEBUG @@ -160,7 +162,7 @@ void FIO_setNotificationLevel(unsigned level) { g_displayLevel=level; } } -/* ************************************* +/*-************************************* * Functions ***************************************/ static unsigned FIO_GetMilliSpan(clock_t nPrevious) @@ -284,6 +286,7 @@ typedef struct { size_t dictBufferSize; ZBUFF_CCtx* ctx; FILE* dstFile; + FILE* srcFile; } cRess_t; static cRess_t FIO_createCResources(const char* dictFileName) @@ -326,19 +329,15 @@ static int FIO_compressFilename_internal(cRess_t ress, const char* dstFileName, const char* srcFileName, int cLevel) { - FILE* srcFile; + FILE* srcFile = ress.srcFile; FILE* dstFile = ress.dstFile; U64 filesize = 0; U64 compressedfilesize = 0; size_t dictSize = ress.dictBufferSize; size_t sizeCheck, errorCode; - /* File check */ - srcFile = FIO_openSrcFile(srcFileName); - if (!srcFile) return 1; /* srcFile could not be opened */ - /* init */ - filesize = FIO_getFileSize(srcFileName) + dictSize; + filesize = MAX(FIO_getFileSize(srcFileName),dictSize); errorCode = ZBUFF_compressInit_advanced(ress.ctx, ress.dictBuffer, ress.dictBufferSize, ZSTD_getParams(cLevel, filesize)); if (ZBUFF_isError(errorCode)) EXM_THROW(21, "Error initializing compression : %s", ZBUFF_getErrorName(errorCode)); @@ -385,13 +384,33 @@ static int FIO_compressFilename_internal(cRess_t ress, DISPLAYLEVEL(2,"Compressed %llu bytes into %llu bytes ==> %.2f%%\n", (unsigned long long) filesize, (unsigned long long) compressedfilesize, (double)compressedfilesize/filesize*100); - /* clean */ - fclose(srcFile); - return 0; } +/*! FIO_compressFilename_internal() : + * same as FIO_compressFilename_extRess(), with ress.desFile already opened + * @return : 0 : compression completed correctly, + * 1 : missing or pb opening srcFileName + */ +static int FIO_compressFilename_srcFile(cRess_t ress, + const char* dstFileName, const char* srcFileName, + int cLevel) +{ + int result; + + /* File check */ + ress.srcFile = FIO_openSrcFile(srcFileName); + if (!ress.srcFile) return 1; /* srcFile could not be opened */ + + result = FIO_compressFilename_internal(ress, dstFileName, srcFileName, cLevel); + + /* clean */ + fclose(ress.srcFile); + return result; +} + + /*! FIO_compressFilename_extRess() : * @return : 0 : compression completed correctly, * 1 : missing or pb opening srcFileName @@ -402,11 +421,14 @@ static int FIO_compressFilename_extRess(cRess_t ress, { int result; + ress.srcFile = FIO_openSrcFile(srcFileName); + if (ress.srcFile==0) return 1; ress.dstFile = FIO_openDstFile(dstFileName); - if (ress.dstFile==0) return 1; + if (ress.dstFile==0) { fclose(ress.srcFile); return 1; } result = FIO_compressFilename_internal(ress, dstFileName, srcFileName, cLevel); + fclose(ress.srcFile); /* no pb to expect : only reading */ if (fclose(ress.dstFile)) EXM_THROW(28, "Write error : cannot properly close %s", dstFileName); return result; } @@ -456,7 +478,13 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile ress = FIO_createCResources(dictFileName); /* loop on each file */ - if (suffix) { + if (!strcmp(suffix, stdoutmark)) { + ress.dstFile = stdout; + for (u=0; u tmpdec : " cp tmpall tmpall2 $ZSTD -dc tmpall* > tmpdec ls -ls tmp* +echo "compress multiple files including a missing one (notHere) : " $ZSTD -f tmp1 notHere tmp2 && die "missing file not detected!" -rm tmp* + +echo "\n**** integrity tests **** " +echo "test one file (tmp1.zst) " +$ZSTD -t tmp1.zst +echo "test multiple files (*.zst) " +$ZSTD -t *.zst +echo "test good and bad files (*) " +$ZSTD -t * && die "bad files not detected !" echo "\n**** zstd round-trip tests **** " roundTripTest -roundTripTest '' 6 -roundTripTest '' 16 +roundTripTest -g512K 6 # greedy, hash chain +roundTripTest -g512K 16 # btlazy2 +roundTripTest -g512K 19 # btopt + +rm tmp* if [ "$1" != "--test-large-data" ]; then echo "Skipping large data tests" @@ -118,3 +129,6 @@ roundTripTest -g50000000 -P94 19 roundTripTest -g99000000 -P99 20 roundTripTest -g6000000000 -P99 q + +rm tmp* + From 2d08b098efedbe02c33ba20ff0ba18c44dbfc428 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 16 Feb 2016 14:42:08 +0100 Subject: [PATCH 107/113] Updated man zstd Added `-t` | `--test` to zstd cli Added a few long commands, compatible with gzip --- NEWS | 2 ++ programs/playTests.sh | 13 ++++++++- programs/zstd.1 | 68 ++++++++++++++++++++++++++++++------------- programs/zstdcli.c | 7 ++++- 4 files changed, 67 insertions(+), 23 deletions(-) diff --git a/NEWS b/NEWS index f6b2d6c91..036df0076 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,9 @@ v0.5.1 New : Optimal parsing => Very high compression modes, thanks to Przemyslaw Skibinski Changed : Dictionary builder integrated into libzstd and zstd cli +Changed : zstd cli now uses "multiple input files" as default mode Fix : high compression modes for big-endian platforms +New : zstd cli : `-t` | `--test` command v0.5.0 New : dictionary builder utility diff --git a/programs/playTests.sh b/programs/playTests.sh index 014a568c1..25ba687e9 100755 --- a/programs/playTests.sh +++ b/programs/playTests.sh @@ -23,9 +23,19 @@ roundTripTest() { [ -n "$ZSTD" ] || die "ZSTD variable must be defined!" -echo "\n**** simple test **** " +echo "\n**** simple tests **** " ./datagen > tmp $ZSTD tmp +$ZSTD tmp -c > tmpCompressed +$ZSTD tmp --stdout > tmpCompressed +$ZSTD -d tmpCompressed && die "wrong suffix error not detected!" +$ZSTD -d tmpCompressed -c > tmpResult +$ZSTD --decompress tmpCompressed -c > tmpResult +$ZSTD --decompress tmpCompressed --stdout > tmpResult +$ZSTD -q tmp && die "overwrite check failed!" +$ZSTD -q -f tmp +$ZSTD -q --force tmp + echo "\n**** frame concatenation **** " @@ -83,6 +93,7 @@ $ZSTD -f tmp1 notHere tmp2 && die "missing file not detected!" echo "\n**** integrity tests **** " echo "test one file (tmp1.zst) " $ZSTD -t tmp1.zst +$ZSTD --test tmp1.zst echo "test multiple files (*.zst) " $ZSTD -t *.zst echo "test good and bad files (*) " diff --git a/programs/zstd.1 b/programs/zstd.1 index 8d69c4ddf..27d607f5c 100644 --- a/programs/zstd.1 +++ b/programs/zstd.1 @@ -14,7 +14,7 @@ .SH SYNOPSIS .TP 5 -\fBzstd\fR [\fBOPTIONS\fR] [-|INPUT-FILE] +\fBzstd\fR [\fBOPTIONS\fR] [-|INPUT-FILE] [-o ] .PP .B unzstd is equivalent to @@ -28,15 +28,13 @@ is equivalent to .SH DESCRIPTION .PP \fBzstd\fR is a fast lossless compression algorithm. -It is based on the \fBLZ77\fR family, with FSE & huff0 entropy stage. -zstd offers compression speed > 200 MB/s per core. -It also features a fast decoder, with speed > 500 MB/s per core. +It is based on the \fBLZ77\fR family, with further FSE & huff0 entropy stages. +\fBzstd\fR offers configurable compression speed, with fast modes at > 200 MB/s per core. +It also features a very fast decoder, with speed > 500 MB/s per core. \fBzstd\fR command line is generally similar to gzip, but features the following differences : - Original files are preserved - - By default, \fBzstd file1 file2\fR means : compress file1 \fBinto\fR file2. - Use \fB-m\fR command if you want : compress file1 into file1.zstd and file2 into file2.zst - - By default, when compressing files, \fBzstd\fR displays advancement notification and result summary. + - By default, when compressing a single file, \fBzstd\fR displays progress notifications and result summary. Use \fB-q\fR to turn them off @@ -45,22 +43,20 @@ It also features a fast decoder, with speed > 500 MB/s per core. .SH OPTIONS .TP .B \-# - # compression level [1-19](default:1) + # compression level [1-21] (default:1) .TP -.B \-d +.BR \-d ", " --decompress decompression .TP -.B \-f +.B \-D file + use `file` as Dictionary to compress or decompress FILE(s) +.TP +.B \-o file + save result into `file` (only possible with a single input FILE) +.TP +.BR \-f ", " --force overwrite output without prompting .TP -.BR \-m ", " --multiple - multiple files mode - In this mode, multiple files on the command line means compression or decompression of each named file - Notifications are also turned off by default -.TP -.B \-D - Use next file as dictionary content for compress / decompression -.TP .BR \-h/\-H ", " --help display help/long help and exit .TP @@ -73,17 +69,47 @@ It also features a fast decoder, with speed > 500 MB/s per core. .BR \-q ", " --quiet suppress warnings and notifications; specify twice to suppress errors too .TP -.B \-c +.BR \-c ", " --stdout force write to standard output, even if it is the console + +.SH DICTIONARY +.PP +\fBzstd\fR offers \fIdictionary\fR compression, useful for very small files and messages. +It's possible to train \fBzstd\fR with some samples, the result of which is saved into a file called `dictionary`. +Then during compression and decompression, make reference to the same dictionary. +It will improve compression ratio of small files. +Typical gains range from ~10% (at 64KB) to x5 better (at <1KB). .TP -.B \-z - force compression +.B \--train FILEs + use FILEs as training set to create a dictionary. + The training set should contain a lot of small files (> 100). + and weight typically 100x the target dictionary size + (for example, 10 MB for a 100 KB dictionary) +.TP +.B \-o file + dictionary saved into `file` (default: dictionary) +.TP +.B \--maxdict # + limit dictionary to specified size (default : 112640) +.TP +.B \-s# + dictionary selectivity level (default: 9) + the smaller the value, the denser the dictionary, improving its efficiency but reducing its possible maximum size. + +.SH BENCHMARK .TP .B \-b# benchmark file(s) using compression level # .TP .B \-i# iteration loops [1-9](default : 3), benchmark mode only +.TP +.B \-B# + cut file into independent blocks of size # (default: no block) +.TP +.B \-r# + test all compression levels from 1 to # (default: disabled) + .SH BUGS Report bugs at:- https://github.com/Cyan4973/zstd/issues diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 7a6dae99c..5fe1869a9 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -142,8 +142,8 @@ static int usage_advanced(const char* programName) #ifndef ZSTD_NOBENCH DISPLAY( "Benchmark arguments :\n"); DISPLAY( " -b# : benchmark file(s), using # compression level (default : 1) \n"); - DISPLAY( " -B# : cut file into independent blocks of size # (default: no block)\n"); DISPLAY( " -i# : iteration loops [1-9](default : 3)\n"); + DISPLAY( " -B# : cut file into independent blocks of size # (default: no block)\n"); DISPLAY( " -r# : test all compression levels from 1 to # (default: disabled)\n"); #endif return 0; @@ -208,12 +208,17 @@ int main(int argCount, const char** argv) if(!argument) continue; /* Protection if argument empty */ /* long commands (--long-word) */ + if (!strcmp(argument, "--decompress")) { decode=1; continue; } + if (!strcmp(argument, "--force")) { FIO_overwriteMode(); continue; } if (!strcmp(argument, "--version")) { displayOut=stdout; DISPLAY(WELCOME_MESSAGE); return 0; } if (!strcmp(argument, "--help")) { displayOut=stdout; return usage_advanced(programName); } if (!strcmp(argument, "--verbose")) { displayLevel=4; continue; } if (!strcmp(argument, "--quiet")) { displayLevel--; continue; } + if (!strcmp(argument, "--stdout")) { forceStdout=1; outFileName=stdoutmark; displayLevel=1; continue; } + if (!strcmp(argument, "--test")) { decode=1; outFileName=nulmark; FIO_overwriteMode(); continue; } if (!strcmp(argument, "--train")) { dictBuild=1; outFileName=g_defaultDictName; continue; } if (!strcmp(argument, "--maxdict")) { nextArgumentIsMaxDict=1; continue; } + if (!strcmp(argument, "--keep")) { continue; } /* does nothing, since preserving input is default; for gzip/xz compatibility */ /* '-' means stdin/stdout */ if (!strcmp(argument, "-")){ From 31dd08cad5fcce3c5110ddb6bf7507ef9a8eaa2e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 16 Feb 2016 16:06:53 +0100 Subject: [PATCH 108/113] Updated readme (dictionary) --- README.md | 75 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 01ac56850..770f2afed 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ As a reference, several fast compression algorithms were tested and compared to |Name | Ratio | C.speed | D.speed | |-----------------|-------|--------:|--------:| | | | MB/s | MB/s | -|**zstd 0.4.7 -1**|**2.875**|**330**| **890** | +|**zstd 0.5.1 -1**|**2.876**|**330**| **890** | | [zlib] 1.2.8 -1 | 2.730 | 95 | 360 | | brotli -0 | 2.708 | 220 | 430 | | QuickLZ 1.5 | 2.237 | 510 | 605 | @@ -40,33 +40,80 @@ Compression Speed vs Ratio | Decompression Speed ### The case for Small Data compression -The above chart is applicable to large files or large streams scenarios (200 MB in this case). +Above chart provides results applicable to large files or large streams scenarios (200 MB for this case). Small data (< 64 KB) come with different perspectives. The smaller the amount of data to compress, the more difficult it is to achieve any significant compression. On reaching the 1 KB region, it becomes almost impossible to compress anything. -This problem is common to all compression algorithms, and throwing CPU power at it achieves no significant gains. +This problem is common to any compression algorithms, and throwing CPU power at it achieves little gains. The reason is, compression algorithms learn from past data how to compress future data. But at the beginning of a new file, there is no "past" to build upon. -[Starting with 0.5](https://github.com/Cyan4973/zstd/releases), Zstd now offers [a _Dictionary Builder_ tool](https://github.com/Cyan4973/zstd/tree/master/dictBuilder). -It can be used to train the algorithm to fit a selected type of data, by providing it with some samples. -The result is a file (or a byte buffer) called "dictionary", which can be loaded before compression and decompression. -By using this dictionary, the compression ratio achievable on small data improves dramatically : +To solve this situation, Zstd now offers a __training mode__, +which can be used to make the algorithm fit a selected type of data, by providing it with some samples. +The result of the training is a file called "dictionary", which can be loaded before compression and decompression. +Using this dictionary, the compression ratio achievable on small data improves dramatically : -| Collection Name | Direct compression | Dictionary Compression | Gains | Average unit | Range | -| --------------- | ------------------ | ---------------------- | ----- | ------------:| ----- | -| Small JSON records | x1.331 - x1.366 | x5.860 - x6.830 | ~ x4.7 | 300 | 200 - 400 | -| Mercurial events | x2.322 - x2.538 | x3.377 - x4.462 | ~ x1.5 | 1.5 KB | 20 - 200 KB | -| Large JSON docs | x3.813 - x4.043 | x8.935 - x13.366 | ~ x2.8 | 6 KB | 800 - 20 KB | +| Collection Name | Direct compression | Dictionary Compression | Gains | Average unit | Range | +| --------------- | ------------------ | ---------------------- | --------- | ------------:| ----- | +| Small JSON records | x1.331 - x1.366 | x5.860 - x6.830 | ~ __x4.7__ | 300 | 200 - 400 | +| Mercurial events | x2.322 - x2.538 | x3.377 - x4.462 | ~ __x1.5__ | 1.5 KB | 20 - 200 KB | +| Large JSON docs | x3.813 - x4.043 | x8.935 - x13.366 | ~ __x2.8__ | 6 KB | 800 - 20 KB | -It has to be noted that these compression gains are achieved without any speed loss, and even some faster decompression processing. +These compression gains are achieved without any speed loss, and prove in general a bit faster to compress and decompress. Dictionary work if there is some correlation in a family of small data (there is no _universal dictionary_). Hence, deploying one dictionary per type of data will provide the greater benefits. Large documents will benefit proportionally less, since dictionary gains are mostly effective in the first few KB. -Then there is enough history to build upon, and the compression algorithm can rely on it to compress the rest of the file. +Then, the compression algorithm will rely more and more on already decoded content to compress the rest of the file. + +#### Dictionary compression How To : + +##### _Using the Command Line Utility_ : + +1) Create the dictionary + +`zstd --train FullPathToTrainingSet/* -o dictionaryName` + +2) Compression with dictionary + +`zstd FILE -D dictionaryName` + +3) Decompress with dictionary + +`zstd --decompress FILE.zst -D dictionaryName` + +##### _Using API_ : + +1) Create dictionary + +``` +#include "zdict.h" +(...) +/* Train a dictionary from a memory buffer `samplesBuffer`, + where `nbSamples` samples have been stored concatenated. */ +size_t dictSize = ZDICT_trainFromBuffer(dictBuffer, dictBufferCapacity, + samplesBuffer, samplesSizes, nbSamples); +``` + +2) Compression with dictionary + +``` +#include "zstd.h" +(...) +ZSTD_CCtx* context = ZSTD_createCCtx(); +size_t compressedSize = ZSTD_compress_usingDict(context, dst, dstCapacity, src, srcSize, dict, dictSize, compressionLevel); +``` + +3) Decompress with dictionary + +``` +#include "zstd.h" +(...) +ZSTD_DCtx* context = ZSTD_createDCtx(); +size_t regeneratedSize = ZSTD_decompress_usingDict(context, dst, dstCapacity, cSrc, cSrcSize, dict, dictSize); +``` ### Status From 6aa896adc6415bff61305c19c637ad1f5a01c4a6 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 16 Feb 2016 16:33:48 +0100 Subject: [PATCH 109/113] zstd cli : control maximum compression level --- programs/zstdcli.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/programs/zstdcli.c b/programs/zstdcli.c index 5fe1869a9..abe13013c 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -241,6 +241,8 @@ int main(int argCount, const char** argv) argument++; } dictCLevel = cLevel; + if (dictCLevel > ZSTD_maxCLevel()) + return badusage(programName); continue; } From 9abc358df6dc1a5ba9dce96cafdba94555a81e42 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 16 Feb 2016 16:35:28 +0100 Subject: [PATCH 110/113] added : test for too large CLevel --- programs/playTests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/programs/playTests.sh b/programs/playTests.sh index 25ba687e9..ec625ee84 100755 --- a/programs/playTests.sh +++ b/programs/playTests.sh @@ -26,6 +26,7 @@ roundTripTest() { echo "\n**** simple tests **** " ./datagen > tmp $ZSTD tmp +$ZSTD -99 tmp && die "too large compression level undetected" $ZSTD tmp -c > tmpCompressed $ZSTD tmp --stdout > tmpCompressed $ZSTD -d tmpCompressed && die "wrong suffix error not detected!" From 6062b15a073eca53ceadaa86a577e5c413246a5e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 16 Feb 2016 17:41:03 +0100 Subject: [PATCH 111/113] performance fix for hash chain mode --- lib/zstd_compress.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 457161565..389cf4f7c 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -1411,7 +1411,8 @@ static size_t ZSTD_BtFindBestMatch_selectMLS_extDict ( /* Update chains up to ip (excluded) Assumption : always within prefix (ie. not within extDict) */ -static U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls) +FORCE_INLINE +U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls) { U32* const hashTable = zc->hashTable; const U32 hashLog = zc->params.hashLog; @@ -1613,7 +1614,7 @@ void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx, break; /* nothing found : store previous solution */ } - /* catch up */ + /* catch up */ if (offset) { while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) /* only search for offset within prefix */ { start--; matchLength++; } From 2673076b3d0d40cadbd46bdcd35a290716ae55d2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 17 Feb 2016 13:40:11 +0100 Subject: [PATCH 112/113] fix zstd-frugal --- programs/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/Makefile b/programs/Makefile index 7da0cc61d..958cdff53 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -101,11 +101,11 @@ zstd-pgo : clean zstd rm zstd $(MAKE) zstd MOREFLAGS=-fprofile-use -zstd-frugal: $(ZSTD_FILES) $(ZSTDDIR)/zstd_buffered.c zstdcli.c fileio.c +zstd-frugal: $(ZSTD_FILES) $(ZSTDDIR)/zbuff.c zstdcli.c fileio.c $(CC) $(FLAGS) -DZSTD_NOBENCH -DZSTD_NODICT -DZSTD_LEGACY_SUPPORT=0 $^ -o zstd$(EXT) zstd-small: clean - CFLAGS=-Os $(MAKE) zstd-frugal + CFLAGS="-Os -s" $(MAKE) zstd-frugal fullbench : $(ZSTD_FILES) \ datagen.c fullbench.c From 728c8fc99577d42541816a4057e7a6f5d6eb2275 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 17 Feb 2016 17:04:12 +0100 Subject: [PATCH 113/113] longer pgo tests --- programs/Makefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/programs/Makefile b/programs/Makefile index 958cdff53..4a650c488 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -53,7 +53,7 @@ BINDIR = $(PREFIX)/bin MANDIR = $(PREFIX)/share/man/man1 ZSTDDIR = ../lib -ZSTD_FILES := $(ZSTDDIR)/zstd_compress.c $(ZSTDDIR)/zstd_decompress.c $(ZSTDDIR)/fse.c $(ZSTDDIR)/huff0.c +ZSTD_FILES := $(ZSTDDIR)/huff0.c $(ZSTDDIR)/fse.c $(ZSTDDIR)/zstd_compress.c $(ZSTDDIR)/zstd_decompress.c ifeq ($(ZSTD_LEGACY_SUPPORT), 0) CPPFLAGS += -DZSTD_LEGACY_SUPPORT=0 @@ -97,7 +97,12 @@ zstd_nolegacy : zstd-pgo : MOREFLAGS = -fprofile-generate zstd-pgo : clean zstd + ./zstd -b19i1 $(PROFILE_WITH) + ./zstd -b16i1 $(PROFILE_WITH) + ./zstd -b9i2 $(PROFILE_WITH) ./zstd -b $(PROFILE_WITH) + ./zstd -b7i2 $(PROFILE_WITH) + ./zstd -b5 $(PROFILE_WITH) rm zstd $(MAKE) zstd MOREFLAGS=-fprofile-use