diff --git a/lib/zstd.c b/lib/zstd.c index 37c67144b..6c3db75b0 100644 --- a/lib/zstd.c +++ b/lib/zstd.c @@ -130,12 +130,6 @@ static const U32 g_searchStrength = 8; #define WORKPLACESIZE (BLOCKSIZE*3) #define MINMATCH 4 -#define MLbits 7 -#define LLbits 6 -#define Offbits 5 -#define MaxML ((1<offset = ssPtr->offsetStart; @@ -205,7 +162,6 @@ void ZSTD_resetSeqStore(seqStore_t* ssPtr) ssPtr->dumps = ssPtr->dumpsStart; } - struct ZSTD_CCtx_s { const BYTE* base; @@ -231,7 +187,7 @@ void ZSTD_resetCCtx(ZSTD_CCtx* ctx) ctx->seqStore.litLengthStart = ctx->seqStore.litStart + BLOCKSIZE; ctx->seqStore.matchLengthStart = ctx->seqStore.litLengthStart + (BLOCKSIZE>>2); ctx->seqStore.dumpsStart = ctx->seqStore.matchLengthStart + (BLOCKSIZE>>2); - memset(ctx->hashTable, 0, HASH_TABLESIZE*4); + memset(ctx->hashTable, 0, sizeof(ctx->hashTable)); } ZSTD_CCtx* ZSTD_createCCtx(void) @@ -289,100 +245,6 @@ static unsigned ZSTD_highbit(U32 val) } -/* ************************************* -* Function body to include -***************************************/ -#include "mem.h" -static size_t ZSTD_read_ARCH(const void* p) { size_t r; memcpy(&r, p, sizeof(r)); return r; } - -MEM_STATIC unsigned ZSTD_NbCommonBytes (register size_t val) -{ - if (MEM_isLittleEndian()) - { - if (MEM_64bits()) - { -# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanForward64( &r, (U64)val ); - return (int)(r>>3); -# elif defined(__GNUC__) && (__GNUC__ >= 3) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctzll((U64)val) >> 3); -# else - static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; - return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; -# endif - } - else /* 32 bits */ - { -# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r; - _BitScanForward( &r, (U32)val ); - return (int)(r>>3); -# elif defined(__GNUC__) && (__GNUC__ >= 3) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctz((U32)val) >> 3); -# else - static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; - return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; -# endif - } - } - else /* Big Endian CPU */ - { - if (MEM_32bits()) - { -# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse64( &r, val ); - return (unsigned)(r>>3); -# elif defined(__GNUC__) && (__GNUC__ >= 3) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clzll(val) >> 3); -# else - unsigned r; - const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */ - if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; } - if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } - r += (!val); - return r; -# endif - } - else /* 32 bits */ - { -# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse( &r, (unsigned long)val ); - return (unsigned)(r>>3); -# elif defined(__GNUC__) && (__GNUC__ >= 3) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clz((U32)val) >> 3); -# else - unsigned r; - if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } - r += (!val); - return r; -# endif - } - } -} - - -MEM_STATIC size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) -{ - const BYTE* const pStart = pIn; - - while ((pIn> 6) + 1; } static size_t ZSTD_compressLiterals (void* dst, size_t maxDstSize, - const void* src, size_t srcSize) + const void* src, size_t srcSize) { const size_t minGain = ZSTD_minGain(srcSize); BYTE* const ostart = (BYTE*)dst; @@ -461,9 +323,9 @@ static size_t ZSTD_compressLiterals (void* dst, size_t maxDstSize, } -static size_t ZSTD_compressSequences(BYTE* dst, size_t maxDstSize, - const seqStore_t* seqStorePtr, - size_t srcSize) +size_t ZSTD_compressSequences(BYTE* dst, size_t maxDstSize, + const seqStore_t* seqStorePtr, + size_t srcSize) { U32 count[MaxSeq+1]; S16 norm[MaxSeq+1]; @@ -475,7 +337,6 @@ static size_t ZSTD_compressSequences(BYTE* dst, size_t maxDstSize, U32 CTable_MatchLength[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML )]; U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */ const BYTE* const op_lit_start = seqStorePtr->litStart; - const BYTE* op_lit = seqStorePtr->lit; const BYTE* const llTable = seqStorePtr->litLengthStart; const BYTE* const llPtr = seqStorePtr->litLength; const BYTE* const mlTable = seqStorePtr->matchLengthStart; @@ -492,7 +353,7 @@ static size_t ZSTD_compressSequences(BYTE* dst, size_t maxDstSize, /* Compress literals */ { size_t cSize; - size_t litSize = op_lit - op_lit_start; + size_t litSize = seqStorePtr->lit - op_lit_start; if (litSize <= LITERAL_NOENTROPY) cSize = ZSTD_compressRawLiteralsBlock(op, maxDstSize, op_lit_start, litSize); @@ -665,48 +526,6 @@ static size_t ZSTD_compressSequences(BYTE* dst, size_t maxDstSize, } -static void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offset, size_t matchLength) -{ - BYTE* op_lit = seqStorePtr->lit; - BYTE* const l_end = op_lit + litLength; - - /* copy Literals */ - while (op_litlit += litLength; - - /* literal Length */ - if (litLength >= MaxLL) - { - *(seqStorePtr->litLength++) = MaxLL; - if (litLength<255 + MaxLL) - *(seqStorePtr->dumps++) = (BYTE)(litLength - MaxLL); - else - { - *(seqStorePtr->dumps++) = 255; - MEM_writeLE32(seqStorePtr->dumps, (U32)litLength); seqStorePtr->dumps += 3; - } - } - else *(seqStorePtr->litLength++) = (BYTE)litLength; - - /* match offset */ - *(seqStorePtr->offset++) = (U32)offset; - - /* match Length */ - if (matchLength >= MaxML) - { - *(seqStorePtr->matchLength++) = MaxML; - if (matchLength < 255+MaxML) - *(seqStorePtr->dumps++) = (BYTE)(matchLength - MaxML); - else - { - *(seqStorePtr->dumps++) = 255; - MEM_writeLE32(seqStorePtr->dumps, (U32)matchLength); seqStorePtr->dumps+=3; - } - } - else *(seqStorePtr->matchLength++) = (BYTE)matchLength; -} - - //static const U32 hashMask = (1<litSize = litSize; return 4; } + default: + return ERROR(corruption_detected); /* forbidden nominal case */ } } @@ -1343,8 +1163,8 @@ static size_t ZSTD_execSequence(BYTE* op, const BYTE* match = op - sequence.offset; /* check */ - if (sequence.offset > (size_t)op) return ERROR(corruption_detected); /* address space overflow test (this test seems kept by clang optimizer) */ //if (match > op) return ERROR(corruption_detected); /* address space overflow test (is clang optimizer removing this test ?) */ + if (sequence.offset > (size_t)op) return ERROR(corruption_detected); /* address space overflow test (this test seems kept by clang optimizer) */ if (match < base) return ERROR(corruption_detected); /* close range match, overlap */ @@ -1419,9 +1239,10 @@ static size_t ZSTD_decompressSequences( seqState_t seqState; memset(&sequence, 0, sizeof(sequence)); + sequence.offset = 4; seqState.dumps = dumps; seqState.dumpsEnd = dumps + dumpsLength; - seqState.prevOffset = 1; + seqState.prevOffset = 4; errorCode = BIT_initDStream(&(seqState.DStream), ip, iend-ip); if (ERR_isError(errorCode)) return ERROR(corruption_detected); FSE_initDState(&(seqState.stateLL), &(seqState.DStream), DTableLL); @@ -1447,7 +1268,7 @@ static size_t ZSTD_decompressSequences( size_t lastLLSize = litEnd - litPtr; if (litPtr > litEnd) return ERROR(corruption_detected); if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); - if (op != litPtr) memmove(op, litPtr, lastLLSize); + if (op != litPtr) memcpy(op, litPtr, lastLLSize); op += lastLLSize; } } @@ -1542,9 +1363,9 @@ size_t ZSTD_decompress(void* dst, size_t maxDstSize, const void* src, size_t src } -/******************************* +/* ****************************** * Streaming Decompression API -*******************************/ +********************************/ size_t ZSTD_resetDCtx(ZSTD_DCtx* dctx) { diff --git a/lib/zstd_static.h b/lib/zstd_static.h index dcdabdb25..6eacc5302 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -82,6 +82,195 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, co #include "error.h" +/* ************************************* +* Function body to include +***************************************/ +#include "mem.h" +static size_t ZSTD_read_ARCH(const void* p) { size_t r; memcpy(&r, p, sizeof(r)); return r; } + +MEM_STATIC unsigned ZSTD_NbCommonBytes (register size_t val) +{ + if (MEM_isLittleEndian()) + { + if (MEM_64bits()) + { +# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanForward64( &r, (U64)val ); + return (int)(r>>3); +# elif defined(__GNUC__) && (__GNUC__ >= 3) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_ctzll((U64)val) >> 3); +# else + static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; + return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; +# endif + } + else /* 32 bits */ + { +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r; + _BitScanForward( &r, (U32)val ); + return (int)(r>>3); +# elif defined(__GNUC__) && (__GNUC__ >= 3) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_ctz((U32)val) >> 3); +# else + static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; + return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; +# endif + } + } + else /* Big Endian CPU */ + { + if (MEM_32bits()) + { +# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanReverse64( &r, val ); + return (unsigned)(r>>3); +# elif defined(__GNUC__) && (__GNUC__ >= 3) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_clzll(val) >> 3); +# else + unsigned r; + const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */ + if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; } + if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } + r += (!val); + return r; +# endif + } + else /* 32 bits */ + { +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanReverse( &r, (unsigned long)val ); + return (unsigned)(r>>3); +# elif defined(__GNUC__) && (__GNUC__ >= 3) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_clz((U32)val) >> 3); +# else + unsigned r; + if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } + r += (!val); + return r; +# endif + } + } +} + + +MEM_STATIC size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) +{ + const BYTE* const pStart = pIn; + + while ((pInlit, literals, litLength); + seqStorePtr->lit += litLength; + + /* literal Length */ + if (litLength >= MaxLL) + { + *(seqStorePtr->litLength++) = MaxLL; + if (litLength<255 + MaxLL) + *(seqStorePtr->dumps++) = (BYTE)(litLength - MaxLL); + else + { + *(seqStorePtr->dumps++) = 255; + MEM_writeLE32(seqStorePtr->dumps, (U32)litLength); seqStorePtr->dumps += 3; + } + } + else *(seqStorePtr->litLength++) = (BYTE)litLength; + + /* match offset */ + *(seqStorePtr->offset++) = (U32)offsetCode; + + /* match Length */ + if (matchCode >= MaxML) + { + *(seqStorePtr->matchLength++) = MaxML; + if (matchCode < 255+MaxML) + *(seqStorePtr->dumps++) = (BYTE)(matchCode - MaxML); + else + { + *(seqStorePtr->dumps++) = 255; + MEM_writeLE32(seqStorePtr->dumps, (U32)matchCode); seqStorePtr->dumps += 3; + } + } + else *(seqStorePtr->matchLength++) = (BYTE)matchCode; +} + +size_t ZSTD_compressSequences(BYTE* dst, size_t maxDstSize, const seqStore_t* seqStorePtr, size_t srcSize); + #if defined (__cplusplus) } #endif diff --git a/lib/zstdhc.c b/lib/zstdhc.c new file mode 100644 index 000000000..a635e1afc --- /dev/null +++ b/lib/zstdhc.c @@ -0,0 +1,512 @@ +/* + ZSTD HC - High Compression Mode of Zstandard + Copyright (C) 2015, Yann Collet. + + 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 +*/ + + +/* ************************************* +* Includes +***************************************/ +#include /* malloc */ +#include /* memset */ +#include "zstdhc.h" +#include "zstd_static.h" +#include "mem.h" + + +/* ************************************* +* Tuning Parameter +***************************************/ +static const U32 ZSTD_HC_compressionLevel_default = 9; + + +/* ************************************* +* Local Constants +***************************************/ +#define MINMATCH 4 +#define MAX_DISTANCE 65535 /* <=== To be changed (dynamic ?) */ + +#define DICTIONARY_LOGSIZE 16 +#define MAXD (1< g_maxCompressionLevel) compressionLevel = g_maxCompressionLevel; + memset(zc->hashTable, 0, sizeof(zc->hashTable)); + memset(zc->chainTable, 0xFF, sizeof(zc->chainTable)); + zc->nextToUpdate = 64 KB; + zc->base = start - 64 KB; + zc->end = start; + zc->dictBase = start - 64 KB; + zc->dictLimit = 64 KB; + zc->lowLimit = 64 KB; + zc->compressionLevel = compressionLevel; + zc->seqStore.buffer = zc->buffer; + zc->seqStore.offsetStart = (U32*) (zc->seqStore.buffer); + zc->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); +} + +/* ************************************* +* Local Macros +***************************************/ +#define HASH_FUNCTION(u) (((u) * 2654435761U) >> ((MINMATCH*8)-HASH_LOG)) +//#define DELTANEXTU16(p) chainTable[(p) & MAXD_MASK] /* flexible, MAXD dependent */ +#define DELTANEXTU16(p) chainTable[(U16)(p)] /* faster */ + +static U32 ZSTD_HC_hashPtr(const void* ptr) { return HASH_FUNCTION(MEM_read32(ptr)); } + + +/* ************************************* +* HC Compression +***************************************/ +/* Update chains up to ip (excluded) */ +static void ZSTD_HC_insert (ZSTD_HC_CCtx* zc, const BYTE* ip) +{ + U16* chainTable = zc->chainTable; + U32* HashTable = zc->hashTable; + const BYTE* const base = zc->base; + const U32 target = (U32)(ip - base); + U32 idx = zc->nextToUpdate; + + while(idx < target) + { + U32 h = ZSTD_HC_hashPtr(base+idx); + size_t delta = idx - HashTable[h]; + if (delta>MAX_DISTANCE) delta = MAX_DISTANCE; + DELTANEXTU16(idx) = (U16)delta; + HashTable[h] = idx; + idx++; + } + + zc->nextToUpdate = target; +} + + +static size_t ZSTD_HC_insertAndFindBestMatch ( + ZSTD_HC_CCtx* zc, /* Index table will be updated */ + const BYTE* ip, const BYTE* const iLimit, + const BYTE** matchpos, + const U32 maxNbAttempts) +{ + U16* const chainTable = zc->chainTable; + U32* const HashTable = zc->hashTable; + const BYTE* const base = zc->base; + const BYTE* const dictBase = zc->dictBase; + const U32 dictLimit = zc->dictLimit; + const U32 lowLimit = (zc->lowLimit + 64 KB > (U32)(ip-base)) ? zc->lowLimit : (U32)(ip - base) - (64 KB - 1); + U32 matchIndex; + const BYTE* match; + int nbAttempts=maxNbAttempts; + size_t ml=0; + + /* HC4 match finder */ + ZSTD_HC_insert(zc, ip); + matchIndex = HashTable[ZSTD_HC_hashPtr(ip)]; + + while ((matchIndex>=lowLimit) && (nbAttempts)) + { + nbAttempts--; + if (matchIndex >= dictLimit) + { + match = base + matchIndex; + if (*(match+ml) == *(ip+ml) + && (MEM_read32(match) == MEM_read32(ip))) + { + const size_t mlt = ZSTD_count(ip+MINMATCH, match+MINMATCH, iLimit) + MINMATCH; + if (mlt > ml) { ml = mlt; *matchpos = match; } + } + } + else + { + match = dictBase + matchIndex; + if (MEM_read32(match) == MEM_read32(ip)) + { + size_t mlt; + const BYTE* vLimit = ip + (dictLimit - matchIndex); + if (vLimit > iLimit) vLimit = iLimit; + mlt = ZSTD_count(ip+MINMATCH, match+MINMATCH, vLimit) + MINMATCH; + if ((ip+mlt == vLimit) && (vLimit < iLimit)) + mlt += ZSTD_count(ip+mlt, base+dictLimit, iLimit); + if (mlt > ml) { ml = mlt; *matchpos = base + matchIndex; } /* virtual matchpos */ + } + } + matchIndex -= DELTANEXTU16(matchIndex); + } + + return ml; +} + + +size_t ZSTD_HC_InsertAndGetWiderMatch ( + ZSTD_HC_CCtx* zc, + const BYTE* const ip, + const BYTE* const iLowLimit, + const BYTE* const iHighLimit, + size_t longest, + const BYTE** matchpos, + const BYTE** startpos, + const int maxNbAttempts) +{ + U16* const chainTable = zc->chainTable; + U32* const HashTable = zc->hashTable; + const BYTE* const base = zc->base; + const U32 dictLimit = zc->dictLimit; + const BYTE* const lowPrefixPtr = base + dictLimit; + const U32 lowLimit = (zc->lowLimit + 64 KB > (U32)(ip-base)) ? zc->lowLimit : (U32)(ip - base) - (64 KB - 1); + const BYTE* const dictBase = zc->dictBase; + U32 matchIndex; + int nbAttempts = maxNbAttempts; + int delta = (int)(ip-iLowLimit); + + + /* First Match */ + ZSTD_HC_insert(zc, ip); + matchIndex = HashTable[ZSTD_HC_hashPtr(ip)]; + + while ((matchIndex>=lowLimit) && (nbAttempts)) + { + nbAttempts--; + if (matchIndex >= dictLimit) + { + const BYTE* matchPtr = base + matchIndex; + if (*(iLowLimit + longest) == *(matchPtr - delta + longest)) + if (MEM_read32(matchPtr) == MEM_read32(ip)) + { + size_t mlt = MINMATCH + ZSTD_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit); + int back = 0; + + while ((ip+back>iLowLimit) + && (matchPtr+back > lowPrefixPtr) + && (ip[back-1] == matchPtr[back-1])) + back--; + + mlt -= back; + + if (mlt > longest) + { + longest = mlt; + *matchpos = matchPtr+back; + *startpos = ip+back; + } + } + } + else + { + const BYTE* matchPtr = dictBase + matchIndex; + if (MEM_read32(matchPtr) == MEM_read32(ip)) + { + size_t mlt; + int back=0; + const BYTE* vLimit = ip + (dictLimit - matchIndex); + if (vLimit > iHighLimit) vLimit = iHighLimit; + mlt = ZSTD_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH; + if ((ip+mlt == vLimit) && (vLimit < iHighLimit)) + mlt += ZSTD_count(ip+mlt, base+dictLimit, iHighLimit); + while ((ip+back > iLowLimit) && (matchIndex+back > lowLimit) && (ip[back-1] == matchPtr[back-1])) back--; + mlt -= back; + if (mlt > longest) { longest = (int)mlt; *matchpos = base + matchIndex + back; *startpos = ip+back; } + } + } + matchIndex -= DELTANEXTU16(matchIndex); + } + + return longest; +} + + +static size_t ZSTD_HC_compressBlock(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize) +{ + seqStore_t* seqStorePtr = &(ctx->seqStore); + const BYTE* const istart = (const BYTE*)src; + const BYTE* ip = istart + 1; + const BYTE* anchor = istart; + const BYTE* const iend = istart + srcSize; + const BYTE* const ilimit = iend - 8; + + size_t offset_2=4, offset_1=4; + const U32 maxSearches = 1 << ctx->compressionLevel; + + /* init */ + ZSTD_resetSeqStore(seqStorePtr); + + /* Main Search Loop */ + while (ip < ilimit) + { + const BYTE* match; + size_t matchLength = ZSTD_HC_insertAndFindBestMatch(ctx, ip, ilimit, &match, maxSearches); + if (!matchLength) { ip++; continue; } + /* save match */ + { + size_t litLength = ip-anchor; + size_t offset = ip-match; + if (litLength) offset_2 = offset_1; + if (offset == offset_2) offset = 0; + offset_2 = offset_1; + offset_1 = ip-match; + ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH); + ip += matchLength; + anchor = ip; + } + } + + /* Last Literals */ + { + size_t lastLLSize = iend - anchor; + memcpy(seqStorePtr->lit, anchor, lastLLSize); + seqStorePtr->lit += lastLLSize; + } + + /* Finale compression stage */ + return ZSTD_compressSequences((BYTE*)dst, maxDstSize, + seqStorePtr, srcSize); +} + +static size_t ZSTD_HC_compress_generic (ZSTD_HC_CCtx* ctxPtr, + void* dst, size_t maxDstSize, + const void* src, size_t srcSize) +{ + static const size_t blockSize = 128 KB; + size_t remaining = srcSize; + const BYTE* ip = (const BYTE*)src; + BYTE* const ostart = (BYTE*)dst; + BYTE* op = ostart; + BYTE* const oend = op + maxDstSize; + + while (remaining > blockSize) + { + size_t cSize = ZSTD_HC_compressBlock(ctxPtr, op+3, oend-op, ip, blockSize); + + if (cSize == 0) + { + cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, blockSize); /* block is not compressible */ + } + else + { + op[0] = (BYTE)(cSize>>16); + op[1] = (BYTE)(cSize>>8); + op[2] = (BYTE)cSize; + op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */ + cSize += 3; + } + + remaining -= blockSize; + ip += blockSize; + op += cSize; + if (ZSTD_isError(cSize)) return cSize; + } + + /* last block */ + { + size_t cSize = ZSTD_HC_compressBlock(ctxPtr, op+3, oend-op, ip, remaining); + + if (cSize == 0) + { + cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, remaining); /* block is not compressible */ + } + else + { + op[0] = (BYTE)(cSize>>16); + op[1] = (BYTE)(cSize>>8); + op[2] = (BYTE)cSize; + op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */ + cSize += 3; + } + + op += cSize; + if (ZSTD_isError(cSize)) return cSize; + } + + return op-ostart; +} + + +size_t ZSTD_HC_loadDict(ZSTD_HC_CCtx* ctx, const void* dictionary, size_t dictSize) +{ + /* TBD */ + (void)ctx; (void)dictionary; (void)dictSize; + return 0; +} + +static void ZSTD_HC_setExternalDict(ZSTD_HC_CCtx* ctxPtr, const void* newBlock) +{ + if (ctxPtr->end >= ctxPtr->base + 4) + ZSTD_HC_insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */ + /* Only one memory segment for extDict, so any previous extDict is lost at this stage */ + ctxPtr->lowLimit = ctxPtr->dictLimit; + ctxPtr->dictLimit = (U32)(ctxPtr->end - ctxPtr->base); + ctxPtr->dictBase = ctxPtr->base; + ctxPtr->base = newBlock - ctxPtr->dictLimit; + ctxPtr->end = newBlock; + ctxPtr->nextToUpdate = ctxPtr->dictLimit; /* match referencing will resume from there */ +} + +size_t ZSTD_HC_compress_continue (ZSTD_HC_CCtx* ctxPtr, + void* dst, size_t dstSize, + const void* src, size_t srcSize) +{ + /* Check overflow */ + if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB) + { + size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base) - ctxPtr->dictLimit; + if (dictSize > 64 KB) dictSize = 64 KB; + + ZSTD_HC_loadDict(ctxPtr, ctxPtr->end - dictSize, dictSize); + } + + /* Check if blocks follow each other */ + if ((const BYTE*)src != ctxPtr->end) + ZSTD_HC_setExternalDict(ctxPtr, (const BYTE*)src); + + /* Check overlapping src/dictionary space (typical of cycling buffers) */ + { + const BYTE* sourceEnd = (const BYTE*) src + srcSize; + const BYTE* dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit; + const BYTE* dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit; + if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) + { + if (sourceEnd > dictEnd) sourceEnd = dictEnd; + ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase); + if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit; + } + } + + return ZSTD_HC_compress_generic (ctxPtr, dst, dstSize, src, srcSize); +} + + +size_t ZSTD_HC_compressBegin(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, unsigned compressionLevel, const void* src) +{ + /* Sanity check */ + if (maxDstSize < 4) return ERROR(dstSize_tooSmall); + + /* Init */ + ZSTD_HC_resetCCtx(ctx, compressionLevel, src); + + /* Write Header */ + MEM_writeLE32(dst, ZSTD_magicNumber); + + return 4; +} + +size_t ZSTD_HC_compressCCtx (ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize, unsigned compressionLevel) +{ + BYTE* const ostart = (BYTE*)dst; + BYTE* op = ostart; + + /* Header */ + size_t oSize = ZSTD_HC_compressBegin(ctx, dst, maxDstSize, compressionLevel, src); + if(ZSTD_isError(oSize)) return oSize; + op += oSize; + maxDstSize -= oSize; + + /* body (compression) */ + op += ZSTD_HC_compress_generic (ctx, op, maxDstSize, src, srcSize); + if(ZSTD_isError(oSize)) return oSize; + op += oSize; + maxDstSize -= oSize; + + /* Close frame */ + oSize = ZSTD_compressEnd((ZSTD_CCtx*)ctx, op, maxDstSize); + if(ZSTD_isError(oSize)) return oSize; + op += oSize; + + return (op - ostart); +} + +size_t ZSTD_HC_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSize, unsigned compressionLevel) +{ + ZSTD_HC_CCtx ctxBody; + return ZSTD_HC_compressCCtx(&ctxBody, dst, maxDstSize, src, srcSize, compressionLevel); +} + + + +/************************************** +* Streaming Functions +**************************************/ + + + +/* dictionary saving */ + +size_t ZSTD_HC_saveDict (ZSTD_HC_CCtx* ctx, void* safeBuffer, size_t dictSize) +{ + /* TBD */ + (void)ctx; (void)safeBuffer; (void)dictSize; + return 0; +} + diff --git a/lib/zstdhc.h b/lib/zstdhc.h new file mode 100644 index 000000000..e7053a849 --- /dev/null +++ b/lib/zstdhc.h @@ -0,0 +1,76 @@ +/* + zstdhc - high compression variant + Header File + Copyright (C) 2015, Yann Collet. + + 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 : http://www.zstd.net +*/ +#pragma once + +#if defined (__cplusplus) +extern "C" { +#endif + +/* ************************************* +* Includes +***************************************/ +#include /* size_t */ + + +/* ************************************* +* Simple function +***************************************/ +/** +ZSTD_HC_compress() : + Compresses 'srcSize' bytes from buffer 'src' into buffer 'dst', of maximum size 'dstSize'. + Destination buffer must be already allocated. + Compression runs faster if maxDstSize >= ZSTD_compressBound(srcSize). + @return : the number of bytes written into buffer 'dst' + or an error code if it fails (which can be tested using ZSTD_isError()) +*/ +size_t ZSTD_HC_compress(void* dst, size_t maxDstSize, + const void* src, size_t srcSize, + unsigned compressionLevel); + + +/* ************************************* +* Advanced functions +***************************************/ +typedef struct ZSTD_HC_CCtx_s ZSTD_HC_CCtx; /* incomplete type */ +ZSTD_HC_CCtx* ZSTD_HC_createCCtx(void); +size_t ZSTD_HC_freeCCtx(ZSTD_HC_CCtx* cctx); + +/** +ZSTD_HC_compressCCtx() : + Same as ZSTD_compress(), but requires a ZSTD_HC_CCtx working space already allocated +*/ +size_t ZSTD_HC_compressCCtx(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize, unsigned compressionLevel); + + +#if defined (__cplusplus) +} +#endif diff --git a/programs/Makefile b/programs/Makefile index bf7768c7a..7295425bc 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -30,7 +30,7 @@ # fullbench32: Same as fullbench, but forced to compile in 32-bits mode # ########################################################################## -VERSION?= v0.2.0 +VERSION?= 0.3.0 DESTDIR?= PREFIX ?= /usr/local @@ -58,7 +58,7 @@ default: zstd all: zstd zstd32 fullbench fullbench32 fuzzer fuzzer32 datagen -zstd : $(ZSTDDIR)/zstd.c $(ZSTDDIR)/fse.c $(ZSTDDIR)/huff0.c $(ZSTDDIR)/legacy/zstd_v01.c xxhash.c bench.c fileio.c zstdcli.c +zstd : $(ZSTDDIR)/zstd.c $(ZSTDDIR)/zstdhc.c $(ZSTDDIR)/fse.c $(ZSTDDIR)/huff0.c $(ZSTDDIR)/legacy/zstd_v01.c xxhash.c bench.c fileio.c zstdcli.c $(CC) $(FLAGS) $^ -o $@$(EXT) zstd32: $(ZSTDDIR)/zstd.c $(ZSTDDIR)/fse.c $(ZSTDDIR)/huff0.c $(ZSTDDIR)/legacy/zstd_v01.c xxhash.c bench.c fileio.c zstdcli.c diff --git a/programs/bench.c b/programs/bench.c index 53ff5e9e9..86a536851 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -23,29 +23,29 @@ - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c */ -/*************************************** +/* ************************************** * Compiler Options -***************************************/ +****************************************/ /* Disable some Visual warning messages */ #define _CRT_SECURE_NO_WARNINGS /* fopen */ -// Unix Large Files support (>4GB) +/* Unix Large Files support (>4GB) */ #define _FILE_OFFSET_BITS 64 -#if (defined(__sun__) && (!defined(__LP64__))) // Sun Solaris 32-bits requires specific definitions +#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 +#elif ! defined(__LP64__) /* No point defining Large file for 64 bit */ # define _LARGEFILE64_SOURCE #endif -// S_ISREG & gettimeofday() are not supported by MSVC +/* S_ISREG & gettimeofday() are not supported by MSVC */ #if defined(_MSC_VER) || defined(_WIN32) # define BMK_LEGACY_TIMER 1 #endif -/************************************** +/* ************************************* * Includes -**************************************/ +***************************************/ #include /* malloc, free */ #include /* memset */ #include // fprintf, fopen, ftello64 @@ -59,40 +59,23 @@ # include // gettimeofday #endif +#include "mem.h" #include "zstd.h" +#include "zstdhc.h" #include "xxhash.h" -/************************************** +/* ************************************* * Compiler specifics -**************************************/ +***************************************/ #if !defined(S_ISREG) # define S_ISREG(x) (((x) & S_IFMT) == S_IFREG) #endif -/************************************** -* Basic Types -**************************************/ -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ -# include - typedef uint8_t BYTE; - typedef uint16_t U16; - typedef uint32_t U32; - typedef int32_t S32; - typedef uint64_t U64; -#else - typedef unsigned char BYTE; - typedef unsigned short U16; - typedef unsigned int U32; - typedef signed int S32; - typedef unsigned long long U64; -#endif - - -/************************************** +/* ************************************* * Constants -**************************************/ +***************************************/ #define NBLOOPS 3 #define TIMELOOP 2500 @@ -108,15 +91,15 @@ static U32 prime1 = 2654435761U; static U32 prime2 = 2246822519U; -/************************************** +/* ************************************* * Macros -**************************************/ +***************************************/ #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) -/************************************** +/* ************************************* * Benchmark Parameters -**************************************/ +***************************************/ static int nbIterations = NBLOOPS; static size_t g_blockSize = 0; @@ -133,9 +116,9 @@ void BMK_SetBlockSize(size_t blockSize) } -/********************************************************* +/* ******************************************************** * Private functions -*********************************************************/ +**********************************************************/ #if defined(BMK_LEGACY_TIMER) @@ -176,10 +159,9 @@ static int BMK_GetMilliSpan( int nTimeStart ) } - -/********************************************************* +/* ******************************************************** * Data generator -*********************************************************/ +**********************************************************/ /* will hopefully be converted into ROL instruction by compiler */ static U32 BMK_rotl32(unsigned val32, unsigned nbBits) { return((val32 << nbBits) | (val32 >> (32 - nbBits))); } @@ -234,9 +216,9 @@ static void BMK_datagen(void* buffer, size_t bufferSize, double proba, U32 seed) } -/********************************************************* +/* ******************************************************** * Bench functions -*********************************************************/ +**********************************************************/ typedef struct { char* srcPtr; @@ -249,6 +231,14 @@ typedef struct } blockParam_t; +typedef size_t (*compressor_t) (void* dst, size_t maxDstSize, const void* src, size_t srcSize, unsigned compressionLevel); + +static size_t local_compress_fast (void* dst, size_t maxDstSize, const void* src, size_t srcSize, unsigned compressionLevel) +{ + (void)compressionLevel; + return ZSTD_compress(dst, maxDstSize, src, srcSize); +} + #define MIN(a,b) (a='0') && (*argument<='9')) + { + cLevel = 0; + while ((*argument >= '0') && (*argument <= '9')) + { + cLevel *= 10; + cLevel += *argument - '0'; + argument++; + } + continue; + } + switch(argument[0]) { /* Display help */ @@ -307,7 +321,7 @@ int main(int argc, char** argv) if (!strcmp(inFileName, stdinmark) && IS_CONSOLE(stdin) ) return badusage(programName); /* Check if benchmark is selected */ - if (bench) { BMK_benchFiles(argv+fileNameStart, nbFiles, 0); goto _end; } + if (bench) { BMK_benchFiles(argv+fileNameStart, nbFiles, cLevel); goto _end; } /* No output filename ==> try to select one automatically (when possible) */ while (!outFileName) @@ -351,7 +365,7 @@ int main(int argc, char** argv) if (decode) FIO_decompressFilename(outFileName, inFileName); else - FIO_compressFilename(outFileName, inFileName); + FIO_compressFilename(outFileName, inFileName, cLevel); _end: if (main_pause) waitEnter();