From 59d1f797681d24fe479b1f60cf66ddf5135a6002 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 23 Jan 2016 19:28:41 +0100 Subject: [PATCH 01/34] variable litblock header size --- lib/huff0.c | 21 ++-- lib/huff0.h | 9 +- lib/huff0_static.h | 21 +++- lib/zstd.h | 4 +- lib/zstd_compress.c | 261 ++++++++++++++++++++++++++++-------------- lib/zstd_decompress.c | 156 ++++++++++++++++++------- lib/zstd_internal.h | 9 +- lib/zstd_static.h | 4 +- programs/bench.c | 12 +- 9 files changed, 339 insertions(+), 158 deletions(-) diff --git a/lib/huff0.c b/lib/huff0.c index 26a7639ff..2544c9e69 100644 --- a/lib/huff0.c +++ b/lib/huff0.c @@ -49,7 +49,6 @@ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ #else # ifdef __GNUC__ -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) # define FORCE_INLINE static inline __attribute__((always_inline)) # else # define FORCE_INLINE static inline @@ -512,7 +511,7 @@ size_t HUF_compress2 (void* dst, size_t dstSize, op += errorCode; /* Compress */ - //errorCode = HUF_compress_usingCTable(op, oend - op, src, srcSize, CTable); /* single segment */ + //if (srcSize < MIN_4STREAMS) errorCode = HUF_compress_usingCTable(op, oend - op, src, srcSize, CTable); else /* single segment */ errorCode = HUF_compress_into4Segments(op, oend - op, src, srcSize, CTable); if (HUF_isError(errorCode)) return errorCode; if (errorCode==0) return 0; @@ -531,7 +530,7 @@ size_t HUF_compress (void* dst, size_t maxDstSize, const void* src, size_t srcSi } -/********************************************************* +/* ******************************************************* * Huff0 : Huffman block decompression *********************************************************/ typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX2; /* single-symbol decoding */ @@ -621,9 +620,9 @@ static size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, } -/**************************/ +/* ************************/ /* single-symbol decoding */ -/**************************/ +/* ************************/ size_t HUF_readDTableX2 (U16* DTable, const void* src, size_t srcSize) { @@ -866,9 +865,9 @@ size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cS } -/***************************/ +/* *************************/ /* double-symbols decoding */ -/***************************/ +/* *************************/ static void HUF_fillDTableX4Level2(HUF_DEltX4* DTable, U32 sizeLog, const U32 consumed, const U32* rankValOrigin, const int minWeight, @@ -1266,9 +1265,9 @@ size_t HUF_decompress4X4 (void* dst, size_t dstSize, const void* cSrc, size_t cS } -/**********************************/ +/* ********************************/ /* quad-symbol decoding */ -/**********************************/ +/* ********************************/ typedef struct { BYTE nbBits; BYTE nbBytes; } HUF_DDescX6; typedef union { BYTE byte[4]; U32 sequence; } HUF_DSeqX6; @@ -1657,9 +1656,9 @@ size_t HUF_decompress4X6 (void* dst, size_t dstSize, const void* cSrc, size_t cS } -/**********************************/ +/* ********************************/ /* Generic decompression selector */ -/**********************************/ +/* ********************************/ typedef struct { U32 tableTime; U32 decode256Time; } algo_time_t; static const algo_time_t algoTime[16 /* Quantization */][3 /* single, double, quad */] = diff --git a/lib/huff0.h b/lib/huff0.h index 2ebd5cfbd..fe28d7bea 100644 --- a/lib/huff0.h +++ b/lib/huff0.h @@ -1,7 +1,7 @@ /* ****************************************************************** Huff0 : Huffman coder, part of New Generation Entropy library header file - Copyright (C) 2013-2015, Yann Collet. + Copyright (C) 2013-2016, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -30,7 +30,6 @@ You can contact the author at : - Source repository : https://github.com/Cyan4973/FiniteStateEntropy - - Public forum : https://groups.google.com/forum/#!forum/lz4c ****************************************************************** */ #ifndef HUFF0_H #define HUFF0_H @@ -66,8 +65,10 @@ HUF_compress(): HUF_decompress(): Decompress Huff0 data from buffer 'cSrc', of size 'cSrcSize', into already allocated destination buffer 'dst', of size 'dstSize'. - 'dstSize' must be the exact size of original (uncompressed) data. - Note : in contrast with FSE, HUF_decompress can regenerate RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data, because it knows size to regenerate. + @dstSize : must be the **exact** size of original (uncompressed) data. + Note : in contrast with FSE, HUF_decompress can regenerate + RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data, + because it knows size to regenerate. @return : size of regenerated data (== dstSize) or an error code, which can be tested using HUF_isError() */ diff --git a/lib/huff0_static.h b/lib/huff0_static.h index 5df0727d7..28ae92ab2 100644 --- a/lib/huff0_static.h +++ b/lib/huff0_static.h @@ -1,7 +1,7 @@ /* ****************************************************************** - Huff0 : Huffman coder, part of New Generation Entropy library - header file for static linking (only) - Copyright (C) 2013-2015, Yann Collet + Huff0 : Huffman codec, part of New Generation Entropy library + header file, for static linking only + Copyright (C) 2013-2016, Yann Collet BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -30,7 +30,6 @@ You can contact the author at : - Source repository : https://github.com/Cyan4973/FiniteStateEntropy - - Public forum : https://groups.google.com/forum/#!forum/lz4c ****************************************************************** */ #ifndef HUFF0_STATIC_H #define HUFF0_STATIC_H @@ -47,15 +46,21 @@ extern "C" { /* **************************************** -* Static allocation macros +* Static allocation ******************************************/ /* Huff0 buffer bounds */ #define HUF_CTABLEBOUND 129 #define HUF_BLOCKBOUND(size) (size + (size>>8) + 8) /* only true if incompressible pre-filtered with fast heuristic */ #define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ +/* static allocation of Huff0's Compression Table */ +#define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \ + U32 name##hb[maxSymbolValue+1]; \ + void* name##hv = &(name##hb); \ + HUF_CElt* name = (HUF_CElt*)(name##hv) /* no final ; */ + /* static allocation of Huff0's DTable */ -#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1< /* For Visual 2005 */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ #else -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) # ifdef __GNUC__ # define FORCE_INLINE static inline __attribute__((always_inline)) # else @@ -64,10 +63,17 @@ /* ************************************* * Constants ***************************************/ -ZSTDLIB_API unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } static const U32 g_searchStrength = 8; +/* ************************************* +* Helper functions +***************************************/ +unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } + +size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; } + + /* ************************************* * Sequence storage ***************************************/ @@ -116,7 +122,6 @@ struct ZSTD_CCtx_s size_t hbSize; char headerBuffer[ZSTD_frameHeaderSize_max]; - seqStore_t seqStore; /* sequences storage ptrs */ U32* hashTable; U32* contentTable; @@ -236,11 +241,64 @@ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, /* ******************************************************* * Block entropic compression *********************************************************/ -size_t ZSTD_compressBound(size_t srcSize) /* maximum compressed size */ -{ - return FSE_compressBound(srcSize) + 12; -} +/* Block format description + + Block = Literal Section - Sequences Section + Prerequisite : size of (compressed) block, maximum size of regenerated data + + 1) Literal Section + + 1.1) Header : 1-5 bytes + flags: 2 bits + 00 compressed by Huff0 + 01 unused + 10 is Raw (uncompressed) + 11 is Rle + Note : using 01 => Huff0 with precomputed table ? + Note : delta map ? => compressed ? + + 1.1.1) Huff0-compressed literal block : 3-5 bytes + srcSize < 1 KB => 3 bytes (2-2-10-10) + srcSize < 17KB => 4 bytes (2-2-14-14) + else => 5 bytes (2-2-18-18) + big endian convention + + 1.1.2) Raw (uncompressed) literal block header : 1-3 bytes + size : 5 bits: (IS_RAW<<6) + (0<<4) + size + 12 bits: (IS_RAW<<6) + (2<<4) + (size>>8) + size&255 + 20 bits: (IS_RAW<<6) + (3<<4) + (size>>16) + size>>8&255 + size&255 + + 1.1.3) Rle (repeated single byte) literal block header : 1-3 bytes + size : 5 bits: (IS_RLE<<6) + (0<<4) + size + 12 bits: (IS_RLE<<6) + (2<<4) + (size>>8) + size&255 + 20 bits: (IS_RLE<<6) + (3<<4) + (size>>16) + size>>8&255 + size&255 + + 1.1.4) Unused + Use Huff0 w/ precalculated DTable ? + FSE ? => probably not, not efficient on literals + + 1.2) Literal block content + + 1.2.1) Huff0 block, using sizes from header + See Huff0 format + + 1.2.2) Raw content + + 1.2.3) single byte + + 1.2.4) _usingDTable variant ? + + + 2) Sequences section + TO DO +*/ size_t ZSTD_noCompressBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize) { @@ -262,24 +320,60 @@ size_t ZSTD_noCompressBlock (void* dst, size_t maxDstSize, const void* src, size static size_t ZSTD_noCompressLiterals (void* dst, size_t maxDstSize, const void* src, size_t srcSize) { BYTE* const ostart = (BYTE* const)dst; + const U32 flSize = 1 + (srcSize>31) + (srcSize>4095); - if (srcSize + 3 > maxDstSize) return ERROR(dstSize_tooSmall); + if (srcSize + flSize > maxDstSize) return ERROR(dstSize_tooSmall); - MEM_writeLE32(dst, ((U32)srcSize << 2) | IS_RAW); - memcpy(ostart + 3, src, srcSize); - return srcSize + 3; + switch(flSize) + { + case 1: /* 2 - 1 - 5 */ + ostart[0] = (BYTE)((IS_RAW<<6) + (0<<5) + srcSize); + break; + case 2: /* 2 - 2 - 12 */ + ostart[0] = (BYTE)((IS_RAW<<6) + (2<<4) + (srcSize >> 8)); + ostart[1] = (BYTE)srcSize; + break; + default: /*note : should not be necessary : flSize is within {1,2,3} */ + case 3: /* 2 - 2 - 20 */ + ostart[0] = (BYTE)((IS_RAW<<6) + (3<<4) + (srcSize >> 16)); + ostart[1] = (BYTE)(srcSize>>8); + ostart[2] = (BYTE)srcSize; + break; + } + + memcpy(ostart + flSize, src, srcSize); + return srcSize + flSize; } static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize) { BYTE* const ostart = (BYTE* const)dst; + U32 flSize = 1 + (srcSize>31) + (srcSize>4095); - (void)maxDstSize; - MEM_writeLE32(dst, ((U32)srcSize << 2) | IS_RLE); /* note : maxDstSize > litHeaderSize > 4 */ - ostart[3] = *(const BYTE*)src; - return 4; + (void)maxDstSize; /* maxDstSize guaranteed to be >=4, hence large enough ? */ + + switch(flSize) + { + case 1: /* 2 - 1 - 5 */ + ostart[0] = (BYTE)((IS_RLE<<6) + (0<<5) + srcSize); + break; + case 2: /* 2 - 2 - 12 */ + ostart[0] = (BYTE)((IS_RLE<<6) + (2<<4) + (srcSize >> 8)); + ostart[1] = (BYTE)srcSize; + break; + default: /*note : should not be necessary : flSize is necessary within {1,2,3} */ + case 3: /* 2 - 2 - 20 */ + ostart[0] = (BYTE)((IS_RLE<<6) + (3<<4) + (srcSize >> 16)); + ostart[1] = (BYTE)(srcSize>>8); + ostart[2] = (BYTE)srcSize; + break; + } + + ostart[flSize] = *(const BYTE*)src; + return flSize+1; } + size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 1; } static size_t ZSTD_compressLiterals (void* dst, size_t maxDstSize, @@ -287,27 +381,41 @@ static size_t ZSTD_compressLiterals (void* dst, size_t maxDstSize, { const size_t minGain = ZSTD_minGain(srcSize); BYTE* const ostart = (BYTE*)dst; - size_t hsize; - static const size_t litHeaderSize = 5; + size_t lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB); + size_t clitSize; - if (maxDstSize < litHeaderSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */ + if (maxDstSize < 4) return ERROR(dstSize_tooSmall); /* not enough space for compression */ - hsize = HUF_compress(ostart+litHeaderSize, maxDstSize-litHeaderSize, src, srcSize); + clitSize = HUF_compress(ostart+lhSize, maxDstSize-lhSize, src, srcSize); - if ((hsize==0) || (hsize >= srcSize - minGain)) return ZSTD_noCompressLiterals(dst, maxDstSize, src, srcSize); - if (hsize==1) return ZSTD_compressRleLiteralsBlock(dst, maxDstSize, src, srcSize); + if ((clitSize==0) || (clitSize >= srcSize - minGain)) return ZSTD_noCompressLiterals(dst, maxDstSize, src, srcSize); + if (clitSize==1) return ZSTD_compressRleLiteralsBlock(dst, maxDstSize, src, srcSize); /* Build header */ + switch(lhSize) { - ostart[0] = (BYTE)(srcSize << 2); /* is a block, is compressed */ - ostart[1] = (BYTE)(srcSize >> 6); - ostart[2] = (BYTE)(srcSize >>14); - ostart[2] += (BYTE)(hsize << 5); - ostart[3] = (BYTE)(hsize >> 3); - ostart[4] = (BYTE)(hsize >>11); + case 3: /* 2 - 2 - 10 - 10 */ + ostart[0] = (BYTE) (srcSize>>6) + (0<< 4); + ostart[1] = (BYTE)((srcSize<<2) + (clitSize>>8)); + ostart[2] = (BYTE)(clitSize); + break; + case 4: /* 2 - 2 - 14 - 14 */ + ostart[0] = (BYTE)(srcSize>>10) + (2<<4); + ostart[1] = (BYTE)(srcSize>> 2); + ostart[2] = (BYTE)((srcSize<<6) + (clitSize>>8)); + ostart[3] = (BYTE)(clitSize); + break; + default: /* should not be necessary, lhSize is {3,4,5} */ + case 5: /* 2 - 2 - 18 - 18 */ + ostart[0] = (BYTE)(srcSize>>14) + (3<<4); + ostart[1] = (BYTE)(srcSize>>6); + ostart[2] = (BYTE)((srcSize<<2) + (clitSize>>16)); + ostart[3] = (BYTE)(clitSize>>8); + ostart[4] = (BYTE)(clitSize); + break; } - return hsize+litHeaderSize; + return lhSize+clitSize; } @@ -754,8 +862,7 @@ static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls) FORCE_INLINE -size_t ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc, - void* dst, size_t maxDstSize, +void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc, const void* src, size_t srcSize, const U32 mls) { @@ -848,38 +955,32 @@ size_t ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc, memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } - - /* Finale compression stage */ - return ZSTD_compressSequences(dst, maxDstSize, - seqStorePtr, srcSize); } -size_t ZSTD_compressBlock_fast(ZSTD_CCtx* ctx, - void* dst, size_t maxDstSize, - const void* src, size_t srcSize) +void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx, + const void* src, size_t srcSize) { const U32 mls = ctx->params.searchLength; switch(mls) { default: case 4 : - return ZSTD_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 4); + ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return; case 5 : - return ZSTD_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 5); + ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return; case 6 : - return ZSTD_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 6); + ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return; case 7 : - return ZSTD_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 7); + ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return; } } //FORCE_INLINE -size_t ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, - void* dst, size_t maxDstSize, - const void* src, size_t srcSize, - const U32 mls) +void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, + const void* src, size_t srcSize, + const U32 mls) { U32* hashTable = ctx->hashTable; const U32 hBits = ctx->params.hashLog; @@ -989,15 +1090,10 @@ size_t ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } - - /* Finale compression stage */ - return ZSTD_compressSequences(dst, maxDstSize, - seqStorePtr, srcSize); } -size_t ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx, - void* dst, size_t maxDstSize, +void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { const U32 mls = ctx->params.searchLength; @@ -1005,13 +1101,13 @@ size_t ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx, { default: case 4 : - return ZSTD_compressBlock_fast_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 4); + return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); case 5 : - return ZSTD_compressBlock_fast_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 5); + return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); case 6 : - return ZSTD_compressBlock_fast_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 6); + return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); case 7 : - return ZSTD_compressBlock_fast_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 7); + return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); } } @@ -1415,8 +1511,8 @@ FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS ( * Common parser - lazy strategy *********************************/ FORCE_INLINE -size_t ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx, - void* dst, size_t maxDstSize, const void* src, size_t srcSize, +void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx, + const void* src, size_t srcSize, const U32 searchMethod, const U32 depth) { seqStore_t* seqStorePtr = &(ctx->seqStore); @@ -1559,36 +1655,32 @@ _storeSequence: memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } - - /* Final compression stage */ - return ZSTD_compressSequences(dst, maxDstSize, - seqStorePtr, srcSize); } -size_t ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize) +static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 1, 2); + return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2); } -size_t ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize) +static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 0, 2); + return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2); } -size_t ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize) +static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 0, 1); + return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1); } -size_t ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize) +static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 0, 0); + return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0); } FORCE_INLINE -size_t ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, - void* dst, size_t maxDstSize, const void* src, size_t srcSize, +void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, + const void* src, size_t srcSize, const U32 searchMethod, const U32 depth) { seqStore_t* seqStorePtr = &(ctx->seqStore); @@ -1778,36 +1870,32 @@ _storeSequence: memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } - - /* Final compression stage */ - return ZSTD_compressSequences(dst, maxDstSize, - seqStorePtr, srcSize); } -size_t ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize) +void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 0, 0); + return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0); } -size_t ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize) +static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 0, 1); + return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1); } -size_t ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize) +static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 0, 2); + return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2); } -static size_t ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize) +static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 1, 2); + return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2); } -typedef size_t (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize); +typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize); -static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict) +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 }, @@ -1822,7 +1910,8 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t maxDs { ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.strategy, zc->lowLimit < zc->dictLimit); if (srcSize < MIN_CBLOCK_SIZE+3) return 0; /* don't even attempt compression below a certain srcSize */ - return blockCompressor(zc, dst, maxDstSize, src, srcSize); + blockCompressor(zc, src, srcSize); + return ZSTD_compressSequences(dst, maxDstSize, &(zc->seqStore), srcSize); } diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 4a026df33..6dc6f9a7d 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -171,6 +171,49 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx) /* ************************************************************* * Decompression section ***************************************************************/ + +/* Frame format description + Frame Header - [ Block Header - Block ] - Frame End + 1) Frame Header + - 4 bytes - Magic Number : ZSTD_MAGICNUMBER (defined within zstd_internal.h) + - 1 byte - Window Descriptor + 2) Block Header + - 3 bytes, starting with a 2-bits descriptor + Uncompressed, Compressed, Frame End, unused + 3) Block + See Block Format Description + 4) Frame End + - 3 bytes, compatible with Block Header +*/ + +/* Block format description + Literal Section - Sequences Section + 1) Literal Section + 1.1) Header : up to 5 bytes + flags: + 00 compressed by Huff0 + 01 is Raw (uncompressed) + 10 is Rle + 11 unused + Note : using 11 for Huff0 with precomputed table ? + Note : delta map ? => compressed ? + Note 2 : 19 bits for sizes, seems a bit larger than necessary + Note 3 : RLE blocks ? + + 1.2.1) Huff0 block, using sizes from header + See Huff0 format + + 1.2.2) Huff0 block, using precomputed DTable + _usingDTable variants + + 1.2.3) uncompressed blocks + as the name says (both 2 or 3 bytes variants) + + 2) Sequences section + TO DO +*/ + + /** ZSTD_decodeFrameHeader_Part1 * decode the 1st part of the Frame Header, which tells Frame Header size. * srcSize must be == ZSTD_frameHeaderSize_min @@ -231,6 +274,7 @@ size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bp return cSize; } + static size_t ZSTD_copyRawBlock(void* dst, size_t maxDstSize, const void* src, size_t srcSize) { if (srcSize > maxDstSize) return ERROR(dstSize_tooSmall); @@ -239,26 +283,6 @@ static size_t ZSTD_copyRawBlock(void* dst, size_t maxDstSize, const void* src, s } -/** ZSTD_decompressLiterals - @return : nb of bytes read from src, or an error code*/ -static size_t ZSTD_decompressLiterals(void* dst, size_t* maxDstSizePtr, - const void* src, size_t srcSize) -{ - const BYTE* ip = (const BYTE*)src; - - const size_t litSize = (MEM_readLE32(src) & 0x1FFFFF) >> 2; /* no buffer issue : srcSize >= MIN_CBLOCK_SIZE */ - const size_t litCSize = (MEM_readLE32(ip+2) & 0xFFFFFF) >> 5; /* no buffer issue : srcSize >= MIN_CBLOCK_SIZE */ - - if (litSize > *maxDstSizePtr) return ERROR(corruption_detected); - if (litCSize + 5 > srcSize) return ERROR(corruption_detected); - - if (HUF_isError(HUF_decompress(dst, litSize, ip+5, litCSize))) return ERROR(corruption_detected); - - *maxDstSizePtr = litSize; - return litCSize + 5; -} - - /** ZSTD_decodeLiteralsBlock @return : nb of bytes read from src (< srcSize ) */ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, @@ -269,47 +293,101 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, /* any compressed block with literals segment must be at least this size */ if (srcSize < MIN_CBLOCK_SIZE) return ERROR(corruption_detected); - switch(*istart & 3) + switch(istart[0]>> 6) { - /* compressed */ - case 0: + case IS_HUF: { - size_t litSize = BLOCKSIZE; - const size_t readSize = ZSTD_decompressLiterals(dctx->litBuffer, &litSize, src, srcSize); + size_t litSize, litCSize; + U32 lhSize = ((istart[0]) >> 4) & 3; + switch(lhSize) + { + case 0: case 1: default: /* note : default is impossible, since lhSize into [0..3] */ + /* 2 - 2 - 10 - 10 */ + lhSize=3; + litSize = ((istart[0] & 15) << 6) + (istart[1] >> 2); + litCSize = ((istart[1] & 3) << 8) + istart[2]; + break; + case 2: + /* 2 - 2 - 14 - 14 */ + lhSize=4; + litSize = ((istart[0] & 15) << 10) + (istart[1] << 2) + (istart[2] >> 6); + litCSize = ((istart[2] & 63) << 8) + istart[3]; + break; + case 3: + /* 2 - 2 - 18 - 18 */ + lhSize=5; + litSize = ((istart[0] & 15) << 14) + (istart[1] << 6) + (istart[2] >> 2); + litCSize = ((istart[2] & 3) << 16) + (istart[3] << 8) + istart[4]; + break; + } + + if (HUF_isError( HUF_decompress(dctx->litBuffer, litSize, istart+lhSize, litCSize) )) + return ERROR(corruption_detected); + dctx->litPtr = dctx->litBuffer; dctx->litBufSize = BLOCKSIZE+8; dctx->litSize = litSize; - return readSize; /* works if it's an error too */ + return litCSize + lhSize; } case IS_RAW: { - const size_t litSize = (MEM_readLE32(istart) & 0xFFFFFF) >> 2; /* no buffer issue : srcSize >= MIN_CBLOCK_SIZE */ - if (litSize > srcSize-11) /* risk of reading too far with wildcopy */ + size_t litSize; + U32 lhSize = ((istart[0]) >> 4) & 3; + switch(lhSize) { - if (litSize > srcSize-3) return ERROR(corruption_detected); - memcpy(dctx->litBuffer, istart, litSize); + case 0: case 1: default: /* note : default is impossible, since lhSize into [0..3] */ + lhSize=1; + litSize = istart[0] & 31; + break; + case 2: + litSize = ((istart[0] & 15) << 8) + istart[1]; + break; + case 3: + litSize = ((istart[0] & 15) << 16) + (istart[1] << 8) + istart[2]; + break; + } + + if (litSize > srcSize-11) /* risk of reading beyond src buffer with wildcopy */ + { + if (litSize > srcSize-litSize) return ERROR(corruption_detected); + memcpy(dctx->litBuffer, istart+lhSize, litSize); dctx->litPtr = dctx->litBuffer; dctx->litBufSize = BLOCKSIZE+8; dctx->litSize = litSize; - return litSize+3; + return litSize+lhSize; } /* direct reference into compressed stream */ - dctx->litPtr = istart+3; - dctx->litBufSize = srcSize-3; + dctx->litPtr = istart+lhSize; + dctx->litBufSize = srcSize-lhSize; dctx->litSize = litSize; - return litSize+3; } + return lhSize+litSize; + } case IS_RLE: { - const size_t litSize = (MEM_readLE32(istart) & 0xFFFFFF) >> 2; /* no buffer issue : srcSize >= MIN_CBLOCK_SIZE */ + size_t litSize; + U32 lhSize = ((istart[0]) >> 4) & 3; + switch(lhSize) + { + case 0: case 1: default: /* note : default is impossible, since lhSize into [0..3] */ + lhSize = 1; + litSize = istart[0] & 31; + break; + case 2: + litSize = ((istart[0] & 15) << 8) + istart[1]; + break; + case 3: + litSize = ((istart[0] & 15) << 16) + (istart[1] << 8) + istart[2]; + break; + } if (litSize > BLOCKSIZE) return ERROR(corruption_detected); - memset(dctx->litBuffer, istart[3], litSize); + memset(dctx->litBuffer, istart[lhSize], litSize); dctx->litPtr = dctx->litBuffer; dctx->litBufSize = BLOCKSIZE+8; dctx->litSize = litSize; - return 4; + return lhSize+1; } - default: - return ERROR(corruption_detected); /* forbidden nominal case */ + default: /* IS_PCH */ + return ERROR(corruption_detected); /* not yet nominal case */ } } diff --git a/lib/zstd_internal.h b/lib/zstd_internal.h index cae2cb8f8..a5d20409b 100644 --- a/lib/zstd_internal.h +++ b/lib/zstd_internal.h @@ -42,6 +42,7 @@ extern "C" { ***************************************/ #include "mem.h" #include "error_private.h" +#include "zstd_static.h" /* ************************************* @@ -73,8 +74,10 @@ static const size_t ZSTD_frameHeaderSize_min = 5; #define BIT1 2 #define BIT0 1 -#define IS_RAW BIT0 -#define IS_RLE BIT1 +#define IS_HUF 0 +#define IS_PCH 1 +#define IS_RAW 2 +#define IS_RLE 3 #define MINMATCH 4 #define REPCODE_STARTVALUE 4 @@ -104,7 +107,7 @@ static void ZSTD_copy8(void* dst, const void* src) { memcpy(dst, src, 8); } #define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; } /*! ZSTD_wildcopy : custom version of memcpy(), can copy up to 7-8 bytes too many */ -static void ZSTD_wildcopy(void* dst, const void* src, size_t length) +MEM_STATIC void ZSTD_wildcopy(void* dst, const void* src, size_t length) { const BYTE* ip = (const BYTE*)src; BYTE* op = (BYTE*)dst; diff --git a/lib/zstd_static.h b/lib/zstd_static.h index c60fa65c2..4ce266148 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -123,7 +123,7 @@ ZSTDLIB_API size_t ZSTD_decompress_usingDict(ZSTD_DCtx* ctx, ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* ctx, ZSTD_parameters params); -ZSTDLIB_API size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* ctx, const void* src, size_t srcSize); +ZSTDLIB_API size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* ctx, const void* dict, size_t dictSize); ZSTDLIB_API size_t ZSTD_duplicateCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx); ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize); @@ -169,7 +169,7 @@ ZSTDLIB_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize); /** - Streaming decompression, bufferless mode + Streaming decompression, direct mode (bufferless) A ZSTD_DCtx object is required to track streaming operations. Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it. diff --git a/programs/bench.c b/programs/bench.c index fcd674aac..fe2b07f0f 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -357,15 +357,17 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, { if (((const BYTE*)srcBuffer)[u] != ((const BYTE*)resultBuffer)[u]) { - U32 bn; + U32 segNb, bNb, pos; size_t bacc = 0; printf("Decoding error at pos %u ", (U32)u); - for (bn = 0; bn < nbBlocks; bn++) + for (segNb = 0; segNb < nbBlocks; segNb++) { - if (bacc + blockTable[bn].srcSize > u) break; - bacc += blockTable[bn].srcSize; + if (bacc + blockTable[segNb].srcSize > u) break; + bacc += blockTable[segNb].srcSize; } - printf("(block %u, pos %u) \n", bn, (U32)(u - bacc)); + pos = (U32)(u - bacc); + bNb = pos / (128 KB); + printf("(segment %u, block %u, pos %u) \n", segNb, bNb, pos); break; } } From afe0709964757252dfaecb03776d697c54cf3669 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 25 Jan 2016 04:10:46 +0100 Subject: [PATCH 02/34] stream control --- lib/huff0.c | 74 +++++++++++++++++++++++++++++++++++++++++-- lib/huff0_static.h | 13 +++++--- lib/zstd_compress.c | 19 +++++++---- lib/zstd_decompress.c | 9 ++++-- 4 files changed, 99 insertions(+), 16 deletions(-) diff --git a/lib/huff0.c b/lib/huff0.c index 2544c9e69..9bc905a5b 100644 --- a/lib/huff0.c +++ b/lib/huff0.c @@ -473,10 +473,76 @@ static size_t HUF_compress_into4Segments(void* dst, size_t dstSize, const void* } +static size_t HUF_compress_internal ( + void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned huffLog, + unsigned singleStream) +{ + BYTE* const ostart = (BYTE*)dst; + BYTE* op = ostart; + BYTE* const oend = ostart + dstSize; + + U32 count[HUF_MAX_SYMBOL_VALUE+1]; + HUF_CElt CTable[HUF_MAX_SYMBOL_VALUE+1]; + size_t errorCode; + + /* checks & inits */ + if (srcSize < 2) return 0; /* Uncompressed */ + if (dstSize < 1) return 0; /* not compressible within dst budget */ + if (srcSize > 128 * 1024) return ERROR(srcSize_wrong); /* current block size limit */ + if (huffLog > HUF_MAX_TABLELOG) return ERROR(tableLog_tooLarge); + if (!maxSymbolValue) maxSymbolValue = HUF_MAX_SYMBOL_VALUE; + if (!huffLog) huffLog = HUF_DEFAULT_TABLELOG; + + /* Scan input and build symbol stats */ + errorCode = FSE_count (count, &maxSymbolValue, (const BYTE*)src, srcSize); + if (HUF_isError(errorCode)) return errorCode; + if (errorCode == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } + if (errorCode <= (srcSize >> 7)+1) return 0; /* Heuristic : not compressible enough */ + + /* Build Huffman Tree */ + errorCode = HUF_buildCTable (CTable, count, maxSymbolValue, huffLog); + if (HUF_isError(errorCode)) return errorCode; + huffLog = (U32)errorCode; + + /* Write table description header */ + errorCode = HUF_writeCTable (op, dstSize, CTable, maxSymbolValue, huffLog); + if (HUF_isError(errorCode)) return errorCode; + if (errorCode + 12 >= srcSize) return 0; /* not useful to try compression */ + op += errorCode; + + /* Compress */ + if (singleStream) + errorCode = HUF_compress_usingCTable(op, oend - op, src, srcSize, CTable); /* single segment */ + else + errorCode = HUF_compress_into4Segments(op, oend - op, src, srcSize, CTable); + if (HUF_isError(errorCode)) return errorCode; + if (errorCode==0) return 0; + op += errorCode; + + /* check compressibility */ + if ((size_t)(op-ostart) >= srcSize-1) + return 0; + + return op-ostart; +} + + +size_t HUF_compress1X (void* dst, size_t dstSize, + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned huffLog) +{ + return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 1); +} + size_t HUF_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog) { +#if 1 + return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 0); +#else BYTE* const ostart = (BYTE*)dst; BYTE* op = ostart; BYTE* const oend = ostart + dstSize; @@ -522,8 +588,10 @@ size_t HUF_compress2 (void* dst, size_t dstSize, return 0; return op-ostart; +#endif } + size_t HUF_compress (void* dst, size_t maxDstSize, const void* src, size_t srcSize) { return HUF_compress2(dst, maxDstSize, src, (U32)srcSize, 255, HUF_DEFAULT_TABLELOG); @@ -620,9 +688,9 @@ static size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, } -/* ************************/ -/* single-symbol decoding */ -/* ************************/ +/*-***************************/ +/* single-symbol decoding */ +/*-***************************/ size_t HUF_readDTableX2 (U16* DTable, const void* src, size_t srcSize) { diff --git a/lib/huff0_static.h b/lib/huff0_static.h index 28ae92ab2..bb39496b1 100644 --- a/lib/huff0_static.h +++ b/lib/huff0_static.h @@ -111,14 +111,19 @@ size_t HUF_readDTableX2 (unsigned short* DTable, const void* src, size_t srcSize size_t HUF_readDTableX4 (unsigned* DTable, const void* src, size_t srcSize); size_t HUF_readDTableX6 (unsigned* DTable, const void* src, size_t srcSize); -size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */ -size_t HUF_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */ -size_t HUF_decompress1X6 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* quad-symbol decoder */ - size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const unsigned short* DTable); size_t HUF_decompress4X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const unsigned* DTable); size_t HUF_decompress4X6_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const unsigned* DTable); + +/* single stream variants */ + +size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog); + +size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */ +size_t HUF_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */ +size_t HUF_decompress1X6 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* quad-symbol decoder */ + size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const unsigned short* DTable); size_t HUF_decompress1X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const unsigned* DTable); size_t HUF_decompress1X6_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const unsigned* DTable); diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 7cf03ead7..626000934 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -55,7 +55,7 @@ #include /* memset */ #include "mem.h" #include "fse_static.h" -#include "huff0.h" +#include "huff0_static.h" #include "zstd_static.h" #include "zstd_internal.h" @@ -259,10 +259,14 @@ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, Note : delta map ? => compressed ? 1.1.1) Huff0-compressed literal block : 3-5 bytes + srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream srcSize < 1 KB => 3 bytes (2-2-10-10) srcSize < 17KB => 4 bytes (2-2-14-14) else => 5 bytes (2-2-18-18) big endian convention + Note : 1 or 4 streams ? => controlled by zstd => requires 1 bit => reserved to < 1 KB + 1 stream : orig size ? (note : not required ) + if not : get orig size from decoding, & saves 10 bits 1.1.2) Raw (uncompressed) literal block header : 1-3 bytes size : 5 bits: (IS_RAW<<6) + (0<<4) + size @@ -281,8 +285,9 @@ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, size&255 1.1.4) Unused - Use Huff0 w/ precalculated DTable ? - FSE ? => probably not, not efficient on literals + Use Huff0 w/ precalculated CTable ? + Store CTable into workspace : build during dict Loading, use during encoding + Same issue about size and Nstreams 1.2) Literal block content @@ -382,11 +387,13 @@ static size_t ZSTD_compressLiterals (void* dst, size_t maxDstSize, const size_t minGain = ZSTD_minGain(srcSize); BYTE* const ostart = (BYTE*)dst; size_t lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB); + U32 singleStream = srcSize < 256; size_t clitSize; if (maxDstSize < 4) return ERROR(dstSize_tooSmall); /* not enough space for compression */ - clitSize = HUF_compress(ostart+lhSize, maxDstSize-lhSize, src, srcSize); + clitSize = singleStream ? HUF_compress1X(ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12) + : HUF_compress2 (ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12); if ((clitSize==0) || (clitSize >= srcSize - minGain)) return ZSTD_noCompressLiterals(dst, maxDstSize, src, srcSize); if (clitSize==1) return ZSTD_compressRleLiteralsBlock(dst, maxDstSize, src, srcSize); @@ -395,7 +402,7 @@ static size_t ZSTD_compressLiterals (void* dst, size_t maxDstSize, switch(lhSize) { case 3: /* 2 - 2 - 10 - 10 */ - ostart[0] = (BYTE) (srcSize>>6) + (0<< 4); + ostart[0] = (BYTE) (srcSize>>6) + (singleStream << 4); ostart[1] = (BYTE)((srcSize<<2) + (clitSize>>8)); ostart[2] = (BYTE)(clitSize); break; @@ -419,7 +426,7 @@ static size_t ZSTD_compressLiterals (void* dst, size_t maxDstSize, } -#define LITERAL_NOENTROPY 63 /* cheap heuristic */ +#define LITERAL_NOENTROPY 63 /* don't even attempt to compress literals below this threshold (cheap heuristic) */ size_t ZSTD_compressSequences(void* dst, size_t maxDstSize, const seqStore_t* seqStorePtr, diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 6dc6f9a7d..88ec78e6c 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -61,7 +61,7 @@ #include "zstd_static.h" #include "zstd_internal.h" #include "fse_static.h" -#include "huff0.h" +#include "huff0_static.h" #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1) # include "zstd_legacy.h" @@ -297,13 +297,14 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, { case IS_HUF: { - size_t litSize, litCSize; + size_t litSize, litCSize, singleStream=0; U32 lhSize = ((istart[0]) >> 4) & 3; switch(lhSize) { case 0: case 1: default: /* note : default is impossible, since lhSize into [0..3] */ /* 2 - 2 - 10 - 10 */ lhSize=3; + singleStream = istart[0] & 16; litSize = ((istart[0] & 15) << 6) + (istart[1] >> 2); litCSize = ((istart[1] & 3) << 8) + istart[2]; break; @@ -321,7 +322,9 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, break; } - if (HUF_isError( HUF_decompress(dctx->litBuffer, litSize, istart+lhSize, litCSize) )) + if (HUF_isError(singleStream ? + HUF_decompress1X2(dctx->litBuffer, litSize, istart+lhSize, litCSize) : + HUF_decompress (dctx->litBuffer, litSize, istart+lhSize, litCSize) )) return ERROR(corruption_detected); dctx->litPtr = dctx->litBuffer; From a1249dc8dae4495b162590c5c39aa7444ae6bb93 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 25 Jan 2016 04:22:03 +0100 Subject: [PATCH 03/34] fix visual warnings --- lib/zstd_compress.c | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 626000934..99c569667 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -261,12 +261,9 @@ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, 1.1.1) Huff0-compressed literal block : 3-5 bytes srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream srcSize < 1 KB => 3 bytes (2-2-10-10) - srcSize < 17KB => 4 bytes (2-2-14-14) + srcSize < 16KB => 4 bytes (2-2-14-14) else => 5 bytes (2-2-18-18) big endian convention - Note : 1 or 4 streams ? => controlled by zstd => requires 1 bit => reserved to < 1 KB - 1 stream : orig size ? (note : not required ) - if not : get orig size from decoding, & saves 10 bits 1.1.2) Raw (uncompressed) literal block header : 1-3 bytes size : 5 bits: (IS_RAW<<6) + (0<<4) + size @@ -284,10 +281,16 @@ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, size>>8&255 size&255 - 1.1.4) Unused - Use Huff0 w/ precalculated CTable ? - Store CTable into workspace : build during dict Loading, use during encoding - Same issue about size and Nstreams + 1.1.4) Huff0-compressed literal block, using precomputed CTables : 3-5 bytes + srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream + srcSize < 1 KB => 3 bytes (2-2-10-10) + srcSize < 16KB => 4 bytes (2-2-14-14) + else => 5 bytes (2-2-18-18) + big endian convention + + 1- CTable available (stored into workspace ?) + 2- Small input + 1.2) Literal block content @@ -402,7 +405,7 @@ static size_t ZSTD_compressLiterals (void* dst, size_t maxDstSize, switch(lhSize) { case 3: /* 2 - 2 - 10 - 10 */ - ostart[0] = (BYTE) (srcSize>>6) + (singleStream << 4); + ostart[0] = (BYTE)((srcSize>>6) + (singleStream << 4)); ostart[1] = (BYTE)((srcSize<<2) + (clitSize>>8)); ostart[2] = (BYTE)(clitSize); break; @@ -1108,13 +1111,13 @@ void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx, { default: case 4 : - return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); + ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return; case 5 : - return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); + ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return; case 6 : - return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); + ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return; case 7 : - return ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); + ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return; } } @@ -1666,22 +1669,22 @@ _storeSequence: static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2); + ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2); } static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2); + ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2); } static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1); + ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1); } static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0); + ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0); } @@ -1881,22 +1884,22 @@ _storeSequence: void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0); + ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0); } static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1); + ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1); } static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2); + ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2); } static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize) { - return ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2); + ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2); } From 3742219b4e8971f1d5751d783997731fbe86876e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 25 Jan 2016 16:54:05 +0100 Subject: [PATCH 04/34] fixed decompression bugs --- lib/zstd_decompress.c | 83 ++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 88ec78e6c..096d90ffe 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -321,6 +321,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, litCSize = ((istart[2] & 3) << 16) + (istart[3] << 8) + istart[4]; break; } + if (litSize > BLOCKSIZE) return ERROR(corruption_detected);; if (HUF_isError(singleStream ? HUF_decompress1X2(dctx->litBuffer, litSize, istart+lhSize, litCSize) : @@ -352,7 +353,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, if (litSize > srcSize-11) /* risk of reading beyond src buffer with wildcopy */ { - if (litSize > srcSize-litSize) return ERROR(corruption_detected); + if (litSize > srcSize-lhSize) return ERROR(corruption_detected); memcpy(dctx->litBuffer, istart+lhSize, litSize); dctx->litPtr = dctx->litBuffer; dctx->litBufSize = BLOCKSIZE+8; @@ -776,7 +777,7 @@ size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, } -size_t ZSTD_decompress_usingDict(ZSTD_DCtx* ctx, +size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize, const void* dict, size_t dictSize) @@ -790,17 +791,17 @@ size_t ZSTD_decompress_usingDict(ZSTD_DCtx* ctx, blockProperties_t blockProperties; /* init */ - ZSTD_resetDCtx(ctx); + ZSTD_resetDCtx(dctx); if (dict) { - ZSTD_decompress_insertDictionary(ctx, dict, dictSize); - ctx->dictEnd = ctx->previousDstEnd; - ctx->vBase = (const char*)dst - ((const char*)(ctx->previousDstEnd) - (const char*)(ctx->base)); - ctx->base = dst; + ZSTD_decompress_insertDictionary(dctx, dict, dictSize); + dctx->dictEnd = dctx->previousDstEnd; + dctx->vBase = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base)); + dctx->base = dst; } else { - ctx->vBase = ctx->base = ctx->dictEnd = dst; + dctx->vBase = dctx->base = dctx->dictEnd = dst; } /* Frame Header */ @@ -814,11 +815,11 @@ size_t ZSTD_decompress_usingDict(ZSTD_DCtx* ctx, return ZSTD_decompressLegacy(dst, maxDstSize, src, srcSize, magicNumber); } #endif - frameHeaderSize = ZSTD_decodeFrameHeader_Part1(ctx, src, ZSTD_frameHeaderSize_min); + frameHeaderSize = ZSTD_decodeFrameHeader_Part1(dctx, src, ZSTD_frameHeaderSize_min); if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize; if (srcSize < frameHeaderSize+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); ip += frameHeaderSize; remainingSize -= frameHeaderSize; - frameHeaderSize = ZSTD_decodeFrameHeader_Part2(ctx, src, frameHeaderSize); + frameHeaderSize = ZSTD_decodeFrameHeader_Part2(dctx, src, frameHeaderSize); if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize; } @@ -836,7 +837,7 @@ size_t ZSTD_decompress_usingDict(ZSTD_DCtx* ctx, switch(blockProperties.blockType) { case bt_compressed: - decodedSize = ZSTD_decompressBlock_internal(ctx, op, oend-op, ip, cBlockSize); + decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize); break; case bt_raw : decodedSize = ZSTD_copyRawBlock(op, oend-op, ip, cBlockSize); @@ -892,39 +893,39 @@ size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) return dctx->expected; } -size_t ZSTD_decompressContinue(ZSTD_DCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize) +size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize) { /* Sanity check */ - if (srcSize != ctx->expected) return ERROR(srcSize_wrong); - ZSTD_checkContinuity(ctx, dst); + if (srcSize != dctx->expected) return ERROR(srcSize_wrong); + ZSTD_checkContinuity(dctx, dst); /* Decompress : frame header; part 1 */ - switch (ctx->stage) + switch (dctx->stage) { case ZSTDds_getFrameHeaderSize : { /* get frame header size */ if (srcSize != ZSTD_frameHeaderSize_min) return ERROR(srcSize_wrong); /* impossible */ - ctx->headerSize = ZSTD_decodeFrameHeader_Part1(ctx, src, ZSTD_frameHeaderSize_min); - if (ZSTD_isError(ctx->headerSize)) return ctx->headerSize; - memcpy(ctx->headerBuffer, src, ZSTD_frameHeaderSize_min); - if (ctx->headerSize > ZSTD_frameHeaderSize_min) + dctx->headerSize = ZSTD_decodeFrameHeader_Part1(dctx, src, ZSTD_frameHeaderSize_min); + if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize; + memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_min); + if (dctx->headerSize > ZSTD_frameHeaderSize_min) { - ctx->expected = ctx->headerSize - ZSTD_frameHeaderSize_min; - ctx->stage = ZSTDds_decodeFrameHeader; + dctx->expected = dctx->headerSize - ZSTD_frameHeaderSize_min; + dctx->stage = ZSTDds_decodeFrameHeader; return 0; } - ctx->expected = 0; /* not necessary to copy more */ + dctx->expected = 0; /* not necessary to copy more */ } case ZSTDds_decodeFrameHeader: { /* get frame header */ size_t result; - memcpy(ctx->headerBuffer + ZSTD_frameHeaderSize_min, src, ctx->expected); - result = ZSTD_decodeFrameHeader_Part2(ctx, ctx->headerBuffer, ctx->headerSize); + memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_min, src, dctx->expected); + result = ZSTD_decodeFrameHeader_Part2(dctx, dctx->headerBuffer, dctx->headerSize); if (ZSTD_isError(result)) return result; - ctx->expected = ZSTD_blockHeaderSize; - ctx->stage = ZSTDds_decodeBlockHeader; + dctx->expected = ZSTD_blockHeaderSize; + dctx->stage = ZSTDds_decodeBlockHeader; return 0; } case ZSTDds_decodeBlockHeader: @@ -935,14 +936,14 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* ctx, void* dst, size_t maxDstSize, con if (ZSTD_isError(blockSize)) return blockSize; if (bp.blockType == bt_end) { - ctx->expected = 0; - ctx->stage = ZSTDds_getFrameHeaderSize; + dctx->expected = 0; + dctx->stage = ZSTDds_getFrameHeaderSize; } else { - ctx->expected = blockSize; - ctx->bType = bp.blockType; - ctx->stage = ZSTDds_decompressBlock; + dctx->expected = blockSize; + dctx->bType = bp.blockType; + dctx->stage = ZSTDds_decompressBlock; } return 0; } @@ -950,10 +951,10 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* ctx, void* dst, size_t maxDstSize, con { /* Decompress : block content */ size_t rSize; - switch(ctx->bType) + switch(dctx->bType) { case bt_compressed: - rSize = ZSTD_decompressBlock_internal(ctx, dst, maxDstSize, src, srcSize); + rSize = ZSTD_decompressBlock_internal(dctx, dst, maxDstSize, src, srcSize); break; case bt_raw : rSize = ZSTD_copyRawBlock(dst, maxDstSize, src, srcSize); @@ -967,9 +968,9 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* ctx, void* dst, size_t maxDstSize, con default: return ERROR(GENERIC); } - ctx->stage = ZSTDds_decodeBlockHeader; - ctx->expected = ZSTD_blockHeaderSize; - ctx->previousDstEnd = (char*)dst + rSize; + dctx->stage = ZSTDds_decodeBlockHeader; + dctx->expected = ZSTD_blockHeaderSize; + dctx->previousDstEnd = (char*)dst + rSize; return rSize; } default: @@ -978,10 +979,10 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* ctx, void* dst, size_t maxDstSize, con } -void ZSTD_decompress_insertDictionary(ZSTD_DCtx* ctx, const void* dict, size_t dictSize) +void ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) { - ctx->dictEnd = ctx->previousDstEnd; - ctx->vBase = (const char*)dict - ((const char*)(ctx->previousDstEnd) - (const char*)(ctx->base)); - ctx->base = dict; - ctx->previousDstEnd = (const char*)dict + dictSize; + dctx->dictEnd = dctx->previousDstEnd; + dctx->vBase = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base)); + dctx->base = dict; + dctx->previousDstEnd = (const char*)dict + dictSize; } From bc4c8aa4b7bae9b31b854b2aa88aff8b927a9cbc Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 25 Jan 2016 17:26:01 +0100 Subject: [PATCH 05/34] fixed new MIN_CBLOCK_SIZE --- lib/zstd_decompress.c | 4 ++-- lib/zstd_internal.h | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 096d90ffe..a0f4d2d86 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -351,14 +351,14 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, break; } - if (litSize > srcSize-11) /* risk of reading beyond src buffer with wildcopy */ + if (litSize+WILDCOPY_OVERLENGTH > srcSize) /* risk reading beyond src buffer with wildcopy */ { if (litSize > srcSize-lhSize) return ERROR(corruption_detected); memcpy(dctx->litBuffer, istart+lhSize, litSize); dctx->litPtr = dctx->litBuffer; dctx->litBufSize = BLOCKSIZE+8; dctx->litSize = litSize; - return litSize+lhSize; + return lhSize+litSize; } /* direct reference into compressed stream */ dctx->litPtr = istart+lhSize; diff --git a/lib/zstd_internal.h b/lib/zstd_internal.h index a5d20409b..3c3d78ce8 100644 --- a/lib/zstd_internal.h +++ b/lib/zstd_internal.h @@ -94,7 +94,9 @@ static const size_t ZSTD_frameHeaderSize_min = 5; #define MaxSeq MAX(MaxLL, MaxML) #define MIN_SEQUENCES_SIZE (2 /*seqNb*/ + 2 /*dumps*/ + 3 /*seqTables*/ + 1 /*bitStream*/) -#define MIN_CBLOCK_SIZE (3 /*litCSize*/ + MIN_SEQUENCES_SIZE) +#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + MIN_SEQUENCES_SIZE) + +#define WILDCOPY_OVERLENGTH 8 typedef enum { bt_compressed, bt_raw, bt_rle, bt_end } blockType_t; @@ -106,7 +108,7 @@ static void ZSTD_copy8(void* dst, const void* src) { memcpy(dst, src, 8); } #define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; } -/*! ZSTD_wildcopy : custom version of memcpy(), can copy up to 7-8 bytes too many */ +/*! ZSTD_wildcopy : custom version of memcpy(), can copy up to 7 bytes too many (8 bytes if length==0) */ MEM_STATIC void ZSTD_wildcopy(void* dst, const void* src, size_t length) { const BYTE* ip = (const BYTE*)src; From b923f65076d1fd54f627264271ba5cb55a16c672 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 26 Jan 2016 03:14:20 +0100 Subject: [PATCH 06/34] introduced dictionary format --- lib/error_private.h | 1 + lib/error_public.h | 1 + lib/huff0.c | 152 ++++++++++++++++++++++-------------------- lib/huff0_static.h | 15 +++-- lib/zstd_compress.c | 96 ++++++++++++++++++++------ lib/zstd_decompress.c | 68 +++++++++++++++++-- lib/zstd_internal.h | 5 +- lib/zstd_static.h | 5 +- programs/bench.c | 20 +++--- 9 files changed, 245 insertions(+), 118 deletions(-) diff --git a/lib/error_private.h b/lib/error_private.h index e56753899..8cb0b8768 100644 --- a/lib/error_private.h +++ b/lib/error_private.h @@ -96,6 +96,7 @@ ERR_STATIC const char* ERR_getErrorName(size_t code) case ZSTD_error_tableLog_tooLarge: return "tableLog requires too much memory"; case ZSTD_error_maxSymbolValue_tooLarge: return "Unsupported max possible Symbol Value : too large"; case ZSTD_error_maxSymbolValue_tooSmall: return "Specified maxSymbolValue is too small"; + case ZSTD_error_dictionary_corrupted: return "Dictionary is corrupted"; case ZSTD_error_maxCode: default: return codeError; } diff --git a/lib/error_public.h b/lib/error_public.h index 78b0e80a9..ceb5a5922 100644 --- a/lib/error_public.h +++ b/lib/error_public.h @@ -56,6 +56,7 @@ enum { ZSTD_error_tableLog_tooLarge, ZSTD_error_maxSymbolValue_tooLarge, ZSTD_error_maxSymbolValue_tooSmall, + ZSTD_error_dictionary_corrupted, ZSTD_error_maxCode }; diff --git a/lib/huff0.c b/lib/huff0.c index 9bc905a5b..3e6107673 100644 --- a/lib/huff0.c +++ b/lib/huff0.c @@ -106,7 +106,8 @@ typedef struct nodeElt_s { @dst : destination buffer @CTable : huffman tree to save, using huff0 representation @return : size of saved CTable */ -size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, U32 maxSymbolValue, U32 huffLog) +size_t HUF_writeCTable (void* dst, size_t maxDstSize, + const HUF_CElt* CTable, U32 maxSymbolValue, U32 huffLog) { BYTE bitsToWeight[HUF_MAX_TABLELOG + 1]; BYTE huffWeight[HUF_MAX_SYMBOL_VALUE + 1]; @@ -172,6 +173,68 @@ size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, U3 } +static size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize); + + +size_t HUF_readCTable (HUF_CElt* CTable, U32 maxSymbolValue, const void* src, size_t srcSize) +{ + BYTE huffWeight[HUF_MAX_SYMBOL_VALUE + 1]; + U32 rankVal[HUF_ABSOLUTEMAX_TABLELOG + 1]; /* large enough for values from 0 to 16 */ + U32 tableLog = 0; + size_t iSize; + U32 nbSymbols = 0; + U32 n; + U32 nextRankStart; + //memset(huffWeight, 0, sizeof(huffWeight)); /* is not necessary, even though some analyzer complain ... */ + + /* get symbol weights */ + iSize = HUF_readStats(huffWeight, HUF_MAX_SYMBOL_VALUE+1, rankVal, &nbSymbols, &tableLog, src, srcSize); + if (HUF_isError(iSize)) return iSize; + + /* check result */ + if (tableLog > HUF_MAX_TABLELOG) return ERROR(tableLog_tooLarge); + if (nbSymbols > maxSymbolValue+1) return ERROR(maxSymbolValue_tooSmall); + + /* Prepare base value per rank */ + nextRankStart = 0; + for (n=1; n<=tableLog; n++) { + U32 current = nextRankStart; + nextRankStart += (rankVal[n] << (n-1)); + rankVal[n] = current; + } + + /* fill nbBits */ + for (n=0; n0; n--) + { + valPerRank[n] = min; /* get starting value within each rank */ + min += nbPerRank[n]; + min >>= 1; + } + } + for (n=0; n<=maxSymbolValue; n++) + CTable[n].val = valPerRank[CTable[n].nbBits]++; /* assign value within rank, symbol order */ + } + + return iSize; +} + + static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) { int totalCost = 0; @@ -384,7 +447,7 @@ size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); } #define HUF_FLUSHBITS_2(stream) \ if (sizeof((stream)->bitContainer)*8 < HUF_MAX_TABLELOG*4+7) HUF_FLUSHBITS(stream) -size_t HUF_compress_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) +size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) { const BYTE* ip = (const BYTE*) src; BYTE* const ostart = (BYTE*)dst; @@ -429,7 +492,7 @@ size_t HUF_compress_usingCTable(void* dst, size_t dstSize, const void* src, size } -static size_t HUF_compress_into4Segments(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) +size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) { size_t segmentSize = (srcSize+3)/4; /* first 3 segments */ size_t errorCode; @@ -443,28 +506,28 @@ static size_t HUF_compress_into4Segments(void* dst, size_t dstSize, const void* if (srcSize < 12) return 0; /* no saving possible : too small input */ op += 6; /* jumpTable */ - errorCode = HUF_compress_usingCTable(op, oend-op, ip, segmentSize, CTable); + errorCode = HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable); if (HUF_isError(errorCode)) return errorCode; if (errorCode==0) return 0; MEM_writeLE16(ostart, (U16)errorCode); ip += segmentSize; op += errorCode; - errorCode = HUF_compress_usingCTable(op, oend-op, ip, segmentSize, CTable); + errorCode = HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable); if (HUF_isError(errorCode)) return errorCode; if (errorCode==0) return 0; MEM_writeLE16(ostart+2, (U16)errorCode); ip += segmentSize; op += errorCode; - errorCode = HUF_compress_usingCTable(op, oend-op, ip, segmentSize, CTable); + errorCode = HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable); if (HUF_isError(errorCode)) return errorCode; if (errorCode==0) return 0; MEM_writeLE16(ostart+4, (U16)errorCode); ip += segmentSize; op += errorCode; - errorCode = HUF_compress_usingCTable(op, oend-op, ip, iend-ip, CTable); + errorCode = HUF_compress1X_usingCTable(op, oend-op, ip, iend-ip, CTable); if (HUF_isError(errorCode)) return errorCode; if (errorCode==0) return 0; @@ -488,7 +551,7 @@ static size_t HUF_compress_internal ( size_t errorCode; /* checks & inits */ - if (srcSize < 2) return 0; /* Uncompressed */ + if (srcSize < 1) return 0; /* Uncompressed - note : 1 means rle, so first byte must be correct */ if (dstSize < 1) return 0; /* not compressible within dst budget */ if (srcSize > 128 * 1024) return ERROR(srcSize_wrong); /* current block size limit */ if (huffLog > HUF_MAX_TABLELOG) return ERROR(tableLog_tooLarge); @@ -514,9 +577,9 @@ static size_t HUF_compress_internal ( /* Compress */ if (singleStream) - errorCode = HUF_compress_usingCTable(op, oend - op, src, srcSize, CTable); /* single segment */ + errorCode = HUF_compress1X_usingCTable(op, oend - op, src, srcSize, CTable); /* single segment */ else - errorCode = HUF_compress_into4Segments(op, oend - op, src, srcSize, CTable); + errorCode = HUF_compress4X_usingCTable(op, oend - op, src, srcSize, CTable); if (HUF_isError(errorCode)) return errorCode; if (errorCode==0) return 0; op += errorCode; @@ -540,55 +603,7 @@ size_t HUF_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned huffLog) { -#if 1 return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 0); -#else - BYTE* const ostart = (BYTE*)dst; - BYTE* op = ostart; - BYTE* const oend = ostart + dstSize; - - U32 count[HUF_MAX_SYMBOL_VALUE+1]; - HUF_CElt CTable[HUF_MAX_SYMBOL_VALUE+1]; - size_t errorCode; - - /* checks & inits */ - if (srcSize < 1) return 0; /* Uncompressed */ - if (dstSize < 1) return 0; /* not compressible within dst budget */ - if (srcSize > 128 * 1024) return ERROR(srcSize_wrong); /* current block size limit */ - if (huffLog > HUF_MAX_TABLELOG) return ERROR(tableLog_tooLarge); - if (!maxSymbolValue) maxSymbolValue = HUF_MAX_SYMBOL_VALUE; - if (!huffLog) huffLog = HUF_DEFAULT_TABLELOG; - - /* Scan input and build symbol stats */ - errorCode = FSE_count (count, &maxSymbolValue, (const BYTE*)src, srcSize); - if (HUF_isError(errorCode)) return errorCode; - if (errorCode == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } - if (errorCode <= (srcSize >> 7)+1) return 0; /* Heuristic : not compressible enough */ - - /* Build Huffman Tree */ - errorCode = HUF_buildCTable (CTable, count, maxSymbolValue, huffLog); - if (HUF_isError(errorCode)) return errorCode; - huffLog = (U32)errorCode; - - /* Write table description header */ - errorCode = HUF_writeCTable (op, dstSize, CTable, maxSymbolValue, huffLog); - if (HUF_isError(errorCode)) return errorCode; - if (errorCode + 12 >= srcSize) return 0; /* not useful to try compression */ - op += errorCode; - - /* Compress */ - //if (srcSize < MIN_4STREAMS) errorCode = HUF_compress_usingCTable(op, oend - op, src, srcSize, CTable); else /* single segment */ - errorCode = HUF_compress_into4Segments(op, oend - op, src, srcSize, CTable); - if (HUF_isError(errorCode)) return errorCode; - if (errorCode==0) return 0; - op += errorCode; - - /* check compressibility */ - if ((size_t)(op-ostart) >= srcSize-1) - return 0; - - return op-ostart; -#endif } @@ -625,31 +640,24 @@ static size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, //memset(huffWeight, 0, hwSize); /* is not necessary, even though some analyzer complain ... */ - if (iSize >= 128) /* special header */ - { - if (iSize >= (242)) /* RLE */ - { + if (iSize >= 128) { /* special header */ + if (iSize >= (242)) { /* RLE */ static int l[14] = { 1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 127, 128 }; oSize = l[iSize-242]; memset(huffWeight, 1, hwSize); iSize = 0; } - else /* Incompressible */ - { + else { /* Incompressible */ oSize = iSize - 127; iSize = ((oSize+1)/2); if (iSize+1 > srcSize) return ERROR(srcSize_wrong); if (oSize >= hwSize) return ERROR(corruption_detected); ip += 1; - for (n=0; n> 4; huffWeight[n+1] = ip[n/2] & 15; - } - } - } - else /* header compressed with FSE (normal case) */ - { + } } } + else { /* header compressed with FSE (normal case) */ if (iSize+1 > srcSize) return ERROR(srcSize_wrong); oSize = FSE_decompress(huffWeight, hwSize-1, ip+1, iSize); /* max (hwSize-1) values decoded, as last one is implied */ if (FSE_isError(oSize)) return oSize; @@ -712,7 +720,7 @@ size_t HUF_readDTableX2 (U16* DTable, const void* src, size_t srcSize) /* check result */ if (tableLog > DTable[0]) return ERROR(tableLog_tooLarge); /* DTable is too small */ - DTable[0] = (U16)tableLog; /* maybe should separate sizeof DTable, as allocated, from used size of DTable, in case of DTable re-use */ + DTable[0] = (U16)tableLog; /* maybe should separate sizeof allocated DTable, from used size of DTable, in case of re-use */ /* Prepare ranks */ nextRankStart = 0; diff --git a/lib/huff0_static.h b/lib/huff0_static.h index bb39496b1..84033964a 100644 --- a/lib/huff0_static.h +++ b/lib/huff0_static.h @@ -91,13 +91,11 @@ The following API allows targeting specific sub-functions for advanced tasks. For example, it's possible to compress several blocks using the same 'CTable', or to save and regenerate 'CTable' using external methods. */ - /* FSE_count() : find it within "fse.h" */ - typedef struct HUF_CElt_s HUF_CElt; /* incomplete type */ -size_t HUF_buildCTable (HUF_CElt* tree, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits); -size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* tree, unsigned maxSymbolValue, unsigned huffLog); -size_t HUF_compress_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable); +size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits); +size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog); +size_t HUF_compress4X_into4Segments(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable); /*! @@ -105,7 +103,6 @@ HUF_decompress() does the following: 1. select the decompression algorithm (X2, X4, X6) based on pre-computed heuristics 2. build Huffman table from save, using HUF_readDTableXn() 3. decode 1 or 4 segments in parallel using HUF_decompressSXn_usingDTable - */ size_t HUF_readDTableX2 (unsigned short* DTable, const void* src, size_t srcSize); size_t HUF_readDTableX4 (unsigned* DTable, const void* src, size_t srcSize); @@ -119,6 +116,7 @@ size_t HUF_decompress4X6_usingDTable(void* dst, size_t maxDstSize, const void* c /* single stream variants */ size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog); +size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable); size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */ size_t HUF_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */ @@ -129,6 +127,11 @@ size_t HUF_decompress1X4_usingDTable(void* dst, size_t maxDstSize, const void* c size_t HUF_decompress1X6_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const unsigned* DTable); +/* Loading a CTable saved with HUF_writeCTable() */ + +size_t HUF_readCTable (HUF_CElt* CTable, unsigned maxSymbolValue, const void* src, size_t srcSize); + + #if defined (__cplusplus) } #endif diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 99c569667..db01c3385 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -125,6 +125,8 @@ struct ZSTD_CCtx_s seqStore_t seqStore; /* sequences storage ptrs */ U32* hashTable; U32* contentTable; + HUF_CElt* hufTable; + U32 flagHufTable; }; @@ -185,18 +187,21 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, { 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 + (3*blockSize); + const size_t neededSpace = tableSpace + (256*sizeof(U32)) + (3*blockSize); if (zc->workSpaceSize < neededSpace) { free(zc->workSpace); - zc->workSpaceSize = neededSpace; zc->workSpace = malloc(neededSpace); if (zc->workSpace == NULL) return ERROR(memory_allocation); + zc->workSpaceSize = neededSpace; } - memset(zc->workSpace, 0, tableSpace ); + memset(zc->workSpace, 0, tableSpace ); /* reset only tables */ zc->hashTable = (U32*)(zc->workSpace); zc->contentTable = zc->hashTable + ((size_t)1 << params.hashLog); - zc->seqStore.buffer = (void*) (zc->contentTable + ((size_t)1 << contentLog)); + zc->seqStore.buffer = zc->contentTable + ((size_t)1 << contentLog); + zc->hufTable = (HUF_CElt*)zc->seqStore.buffer; + zc->flagHufTable = 0; + zc->seqStore.buffer = (U32*)(zc->seqStore.buffer) + 256; } zc->nextToUpdate = 1; @@ -289,7 +294,7 @@ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, big endian convention 1- CTable available (stored into workspace ?) - 2- Small input + 2- Small input (fast heuristic ? Full comparison ? depend on clevel ?) 1.2) Literal block content @@ -382,21 +387,32 @@ static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t maxDstSize, const } -size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 1; } +size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; } -static size_t ZSTD_compressLiterals (void* dst, size_t maxDstSize, +static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc, + void* dst, size_t maxDstSize, const void* src, size_t srcSize) { const size_t minGain = ZSTD_minGain(srcSize); BYTE* const ostart = (BYTE*)dst; - size_t lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB); + const size_t lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB); U32 singleStream = srcSize < 256; + U32 hType = IS_HUF; size_t clitSize; if (maxDstSize < 4) return ERROR(dstSize_tooSmall); /* not enough space for compression */ - clitSize = singleStream ? HUF_compress1X(ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12) - : HUF_compress2 (ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12); + if (zc->flagHufTable && (lhSize==3)) + { + hType = IS_PCH; + singleStream = 1; + clitSize = HUF_compress1X_usingCTable(ostart+lhSize, maxDstSize-lhSize, src, srcSize, zc->hufTable); + } + else + { + clitSize = singleStream ? HUF_compress1X(ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12) + : HUF_compress2 (ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12); + } if ((clitSize==0) || (clitSize >= srcSize - minGain)) return ZSTD_noCompressLiterals(dst, maxDstSize, src, srcSize); if (clitSize==1) return ZSTD_compressRleLiteralsBlock(dst, maxDstSize, src, srcSize); @@ -405,19 +421,19 @@ static size_t ZSTD_compressLiterals (void* dst, size_t maxDstSize, switch(lhSize) { case 3: /* 2 - 2 - 10 - 10 */ - ostart[0] = (BYTE)((srcSize>>6) + (singleStream << 4)); + ostart[0] = (BYTE)((srcSize>>6) + (singleStream << 4) + (hType<<6)); ostart[1] = (BYTE)((srcSize<<2) + (clitSize>>8)); ostart[2] = (BYTE)(clitSize); break; case 4: /* 2 - 2 - 14 - 14 */ - ostart[0] = (BYTE)(srcSize>>10) + (2<<4); + ostart[0] = (BYTE)((srcSize>>10) + (2<<4) + (hType<<6)); ostart[1] = (BYTE)(srcSize>> 2); ostart[2] = (BYTE)((srcSize<<6) + (clitSize>>8)); ostart[3] = (BYTE)(clitSize); break; default: /* should not be necessary, lhSize is {3,4,5} */ case 5: /* 2 - 2 - 18 - 18 */ - ostart[0] = (BYTE)(srcSize>>14) + (3<<4); + ostart[0] = (BYTE)((srcSize>>14) + (3<<4) + (hType<<6)); ostart[1] = (BYTE)(srcSize>>6); ostart[2] = (BYTE)((srcSize<<2) + (clitSize>>16)); ostart[3] = (BYTE)(clitSize>>8); @@ -431,10 +447,11 @@ static size_t ZSTD_compressLiterals (void* dst, size_t maxDstSize, #define LITERAL_NOENTROPY 63 /* don't even attempt to compress literals below this threshold (cheap heuristic) */ -size_t ZSTD_compressSequences(void* dst, size_t maxDstSize, - const seqStore_t* seqStorePtr, +size_t ZSTD_compressSequences(ZSTD_CCtx* zc, + void* dst, size_t maxDstSize, size_t srcSize) { + const seqStore_t* seqStorePtr = &(zc->seqStore); U32 count[MaxSeq+1]; S16 norm[MaxSeq+1]; size_t mostFrequent; @@ -463,11 +480,12 @@ size_t ZSTD_compressSequences(void* dst, size_t maxDstSize, { size_t cSize; size_t litSize = seqStorePtr->lit - op_lit_start; + const size_t minLitSize = zc->flagHufTable ? 6 : LITERAL_NOENTROPY; - if (litSize <= LITERAL_NOENTROPY) + if (litSize <= minLitSize) cSize = ZSTD_noCompressLiterals(op, maxDstSize, op_lit_start, litSize); else - cSize = ZSTD_compressLiterals(op, maxDstSize, op_lit_start, litSize); + cSize = ZSTD_compressLiterals(zc, op, maxDstSize, op_lit_start, litSize); if (ZSTD_isError(cSize)) return cSize; op += cSize; } @@ -1905,7 +1923,7 @@ static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize); -ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict) +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 }, @@ -1921,7 +1939,7 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t maxDs ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.strategy, zc->lowLimit < zc->dictLimit); if (srcSize < MIN_CBLOCK_SIZE+3) return 0; /* don't even attempt compression below a certain srcSize */ blockCompressor(zc, src, srcSize); - return ZSTD_compressSequences(dst, maxDstSize, &(zc->seqStore), srcSize); + return ZSTD_compressSequences(zc, dst, maxDstSize, srcSize); } @@ -2057,7 +2075,7 @@ size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t maxDstSize, const voi } -size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* src, size_t srcSize) +static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize) { const BYTE* const ip = (const BYTE*) src; const BYTE* const iend = ip + srcSize; @@ -2097,6 +2115,35 @@ size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* src, size_t src } +/* Dictionary format : + Magic == ZSTD_DICT_MAGIC (4 bytes) + Huff0 CTable (256 * 4 bytes) => to be changed to read from writeCTable + Dictionary content +*/ +/*! ZSTD_loadDictEntropyStats + @return : size read from dictionary */ +static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t dictSize) +{ + /* note : magic number already checked */ + const size_t hufHeaderSize = HUF_readCTable(zc->hufTable, 255, dict, dictSize); + if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted); + zc->flagHufTable = 1; + return hufHeaderSize; +} + +size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize) +{ + U32 magic = MEM_readLE32(dict); + U32 eSize; + if (magic != ZSTD_DICT_MAGIC) + return ZSTD_loadDictionaryContent(zc, dict, dictSize); + + eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+4, dictSize-4) + 4; + if (ZSTD_isError(eSize)) return eSize; + return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize); +} + + /*! ZSTD_duplicateCCtx * Duplicate an existing context @srcCCtx into another one @dstCCtx. * Only works during stage 0 (i.e. before first call to ZSTD_compressContinue()) @@ -2125,6 +2172,10 @@ size_t ZSTD_duplicateCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx) dstCCtx->dictLimit = srcCCtx->dictLimit; dstCCtx->lowLimit = srcCCtx->lowLimit; + dstCCtx->flagHufTable = srcCCtx->flagHufTable; + if (dstCCtx->flagHufTable) + memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4); + return 0; } @@ -2164,6 +2215,11 @@ ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint) return result; } +/* to do +size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict,size_t dictSize, int compressionLevel) +{ + return 0; +}*/ size_t ZSTD_compressBegin(ZSTD_CCtx* ctx, int compressionLevel) { diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index a0f4d2d86..ce54d200d 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -126,6 +126,7 @@ struct ZSTD_DCtx_s U32 LLTable[FSE_DTABLE_SIZE_U32(LLFSELog)]; U32 OffTable[FSE_DTABLE_SIZE_U32(OffFSELog)]; U32 MLTable[FSE_DTABLE_SIZE_U32(MLFSELog)]; + U32 hufTableX4[HUF_DTABLE_SIZE(HufLog)]; const void* previousDstEnd; const void* base; const void* vBase; @@ -138,7 +139,7 @@ struct ZSTD_DCtx_s const BYTE* litPtr; size_t litBufSize; size_t litSize; - BYTE litBuffer[BLOCKSIZE + 8 /* margin for wildcopy */]; + BYTE litBuffer[BLOCKSIZE + WILDCOPY_OVERLENGTH]; BYTE headerBuffer[ZSTD_frameHeaderSize_max]; }; /* typedef'd to ZSTD_DCtx within "zstd_static.h" */ @@ -150,6 +151,7 @@ size_t ZSTD_resetDCtx(ZSTD_DCtx* dctx) dctx->base = NULL; dctx->vBase = NULL; dctx->dictEnd = NULL; + dctx->hufTableX4[0] = HufLog; return 0; } @@ -333,6 +335,27 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, dctx->litSize = litSize; return litCSize + lhSize; } + case IS_PCH: + { + size_t errorCode; + size_t litSize, litCSize; + U32 lhSize = ((istart[0]) >> 4) & 3; + if (lhSize != 1) /* only case supported for now : small litSize, single stream */ + return ERROR(corruption_detected); + + /* 2 - 2 - 10 - 10 */ + lhSize=3; + litSize = ((istart[0] & 15) << 6) + (istart[1] >> 2); + litCSize = ((istart[1] & 3) << 8) + istart[2]; + + errorCode = HUF_decompress1X4_usingDTable(dctx->litBuffer, litSize, istart+lhSize, litCSize, dctx->hufTableX4); + if (HUF_isError(errorCode)) return ERROR(corruption_detected); + + dctx->litPtr = dctx->litBuffer; + dctx->litBufSize = BLOCKSIZE+WILDCOPY_OVERLENGTH; + dctx->litSize = litSize; + return litCSize + lhSize; + } case IS_RAW: { size_t litSize; @@ -386,12 +409,12 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, if (litSize > BLOCKSIZE) return ERROR(corruption_detected); memset(dctx->litBuffer, istart[lhSize], litSize); dctx->litPtr = dctx->litBuffer; - dctx->litBufSize = BLOCKSIZE+8; + dctx->litBufSize = BLOCKSIZE+WILDCOPY_OVERLENGTH; dctx->litSize = litSize; return lhSize+1; } - default: /* IS_PCH */ - return ERROR(corruption_detected); /* not yet nominal case */ + default: + return ERROR(corruption_detected); /* impossible */ } } @@ -794,7 +817,8 @@ size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, ZSTD_resetDCtx(dctx); if (dict) { - ZSTD_decompress_insertDictionary(dctx, dict, dictSize); + size_t errorCode = ZSTD_decompress_insertDictionary(dctx, dict, dictSize); + if (ZSTD_isError(errorCode)) return ERROR(dictionary_corrupted); dctx->dictEnd = dctx->previousDstEnd; dctx->vBase = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base)); dctx->base = dst; @@ -979,10 +1003,42 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, co } -void ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +static void ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) { dctx->dictEnd = dctx->previousDstEnd; dctx->vBase = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base)); dctx->base = dict; dctx->previousDstEnd = (const char*)dict + dictSize; } + + +static size_t ZSTD_loadEntropy(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +{ + size_t hSize = HUF_readDTableX4(dctx->hufTableX4, dict, dictSize); + if (HUF_isError(hSize)) return ERROR(dictionary_corrupted); + return hSize; +} + +size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +{ + size_t eSize; + U32 magic = MEM_readLE32(dict); + if (magic != ZSTD_DICT_MAGIC) { + /* pure content mode */ + ZSTD_refDictContent(dctx, dict, dictSize); + return 0; + } + /* load entropy tables */ + dict = (const char*)dict + 4; + dictSize -= 4; + eSize = ZSTD_loadEntropy(dctx, dict, dictSize); + if (ZSTD_isError(eSize)) return ERROR(dictionary_corrupted); + + /* reference dictionary content */ + dict = (const char*)dict + eSize; + dictSize -= eSize; + ZSTD_refDictContent(dctx, dict, dictSize); + + return 0; +} + diff --git a/lib/zstd_internal.h b/lib/zstd_internal.h index 3c3d78ce8..38bda786e 100644 --- a/lib/zstd_internal.h +++ b/lib/zstd_internal.h @@ -55,7 +55,8 @@ extern "C" { /* ************************************* * Common constants ***************************************/ -#define ZSTD_MAGICNUMBER 0xFD2FB524 /* v0.4 */ +#define ZSTD_MAGICNUMBER 0xFD2FB525 /* v0.5 */ +#define ZSTD_DICT_MAGIC 0xEC30A435 #define KB *(1 <<10) #define MB *(1 <<20) @@ -93,6 +94,8 @@ static const size_t ZSTD_frameHeaderSize_min = 5; #define OffFSELog 9 #define MaxSeq MAX(MaxLL, MaxML) +#define HufLog 12 + #define MIN_SEQUENCES_SIZE (2 /*seqNb*/ + 2 /*dumps*/ + 3 /*seqTables*/ + 1 /*bitStream*/) #define MIN_CBLOCK_SIZE (1 /*litCSize*/ + MIN_SEQUENCES_SIZE) diff --git a/lib/zstd_static.h b/lib/zstd_static.h index 4ce266148..f99893d71 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -121,6 +121,9 @@ ZSTDLIB_API size_t ZSTD_decompress_usingDict(ZSTD_DCtx* ctx, * Streaming functions (direct mode) ****************************************/ ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); +ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict,size_t dictSize, int compressionLevel); +//ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* ctx, const void* dict,size_t dictSize, ZSTD_parameters params); + ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* ctx, ZSTD_parameters params); ZSTDLIB_API size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* ctx, const void* dict, size_t dictSize); @@ -163,7 +166,7 @@ ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t maxDstSiz ZSTDLIB_API size_t ZSTD_resetDCtx(ZSTD_DCtx* dctx); ZSTDLIB_API size_t ZSTD_getFrameParams(ZSTD_parameters* params, const void* src, size_t srcSize); -ZSTDLIB_API void ZSTD_decompress_insertDictionary(ZSTD_DCtx* ctx, const void* src, size_t srcSize); +ZSTDLIB_API size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* ctx, const void* src, size_t srcSize); ZSTDLIB_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize); diff --git a/programs/bench.c b/programs/bench.c index fe2b07f0f..30555660f 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -310,11 +310,6 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, if (ZSTD_isError(rSize)) EXM_THROW(2, "ZSTD_compressEnd() failed : %s", ZSTD_getErrorName(rSize)); blockTable[blockNb].cSize += rSize; } - /*blockTable[blockNb].cSize = ZSTD_compress_usingDict(ctx, - blockTable[blockNb].cPtr, blockTable[blockNb].cRoom, - blockTable[blockNb].srcPtr,blockTable[blockNb].srcSize, - dictBuffer, dictBufferSize, - cLevel);*/ nbLoops++; } milliTime = BMK_GetMilliSpan(milliTime); @@ -334,14 +329,15 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, milliTime = BMK_GetMilliStart(); while (BMK_GetMilliStart() == milliTime); milliTime = BMK_GetMilliStart(); - for ( ; BMK_GetMilliSpan(milliTime) < TIMELOOP; nbLoops++) - { - for (blockNb=0; blockNb Date: Tue, 26 Jan 2016 15:58:49 +0100 Subject: [PATCH 07/34] modified streaming decompression API --- lib/zstd_buffered.c | 17 ++----- lib/zstd_buffered.h | 19 +++---- lib/zstd_compress.c | 88 ++++++++++++++++---------------- lib/zstd_decompress.c | 114 +++++++++++++++++++++++++----------------- lib/zstd_static.h | 59 +++++++++++++--------- programs/bench.c | 46 +++++++++-------- programs/fileio.c | 3 +- programs/fuzzer.c | 12 ++--- programs/zbufftest.c | 6 +-- 9 files changed, 193 insertions(+), 171 deletions(-) diff --git a/lib/zstd_buffered.c b/lib/zstd_buffered.c index 48721d628..aab83e606 100644 --- a/lib/zstd_buffered.c +++ b/lib/zstd_buffered.c @@ -335,8 +335,6 @@ struct ZBUFF_DCtx_s { size_t outStart; size_t outEnd; size_t hPos; - const char* dict; - size_t dictSize; ZBUFF_dStage stage; unsigned char headerBuffer[ZSTD_frameHeaderSize_max]; }; /* typedef'd to ZBUFF_DCtx within "zstd_buffered.h" */ @@ -365,19 +363,16 @@ size_t ZBUFF_freeDCtx(ZBUFF_DCtx* zbc) /* *** Initialization *** */ -size_t ZBUFF_decompressInit(ZBUFF_DCtx* zbc) +size_t ZBUFF_decompressInitDictionary(ZBUFF_DCtx* zbc, const void* dict, size_t dictSize) { zbc->stage = ZBUFFds_readHeader; - zbc->hPos = zbc->inPos = zbc->outStart = zbc->outEnd = zbc->dictSize = 0; - return ZSTD_resetDCtx(zbc->zc); + zbc->hPos = zbc->inPos = zbc->outStart = zbc->outEnd = 0; + return ZSTD_decompressBegin_usingDict(zbc->zc, dict, dictSize); } - -size_t ZBUFF_decompressWithDictionary(ZBUFF_DCtx* zbc, const void* src, size_t srcSize) +size_t ZBUFF_decompressInit(ZBUFF_DCtx* zbc) { - zbc->dict = (const char*)src; - zbc->dictSize = srcSize; - return 0; + return ZBUFF_decompressInitDictionary(zbc, NULL, 0); } @@ -458,8 +453,6 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt if (zbc->outBuff == NULL) return ERROR(memory_allocation); } } - if (zbc->dictSize) - ZSTD_decompress_insertDictionary(zbc->zc, zbc->dict, zbc->dictSize); if (zbc->hPos) { /* some data already loaded into headerBuffer : transfer into inBuff */ diff --git a/lib/zstd_buffered.h b/lib/zstd_buffered.h index d2316a82b..63101a107 100644 --- a/lib/zstd_buffered.h +++ b/lib/zstd_buffered.h @@ -48,7 +48,7 @@ extern "C" { /* *************************************************************** -* Tuning parameters +* Compiler specifics *****************************************************************/ /*! * ZSTD_DLL_EXPORT : @@ -69,7 +69,7 @@ ZSTDLIB_API ZBUFF_CCtx* ZBUFF_createCCtx(void); ZSTDLIB_API size_t ZBUFF_freeCCtx(ZBUFF_CCtx* cctx); ZSTDLIB_API size_t ZBUFF_compressInit(ZBUFF_CCtx* cctx, int compressionLevel); -ZSTDLIB_API size_t ZBUFF_compressWithDictionary(ZBUFF_CCtx* cctx, const void* src, size_t srcSize); +ZSTDLIB_API size_t ZBUFF_compressWithDictionary(ZBUFF_CCtx* cctx, const void* dict, size_t dictSize); ZSTDLIB_API size_t ZBUFF_compressContinue(ZBUFF_CCtx* cctx, void* dst, size_t* maxDstSizePtr, const void* src, size_t* srcSizePtr); ZSTDLIB_API size_t ZBUFF_compressFlush(ZBUFF_CCtx* cctx, void* dst, size_t* maxDstSizePtr); ZSTDLIB_API size_t ZBUFF_compressEnd(ZBUFF_CCtx* cctx, void* dst, size_t* maxDstSizePtr); @@ -119,7 +119,7 @@ ZSTDLIB_API ZBUFF_DCtx* ZBUFF_createDCtx(void); ZSTDLIB_API size_t ZBUFF_freeDCtx(ZBUFF_DCtx* dctx); ZSTDLIB_API size_t ZBUFF_decompressInit(ZBUFF_DCtx* dctx); -ZSTDLIB_API size_t ZBUFF_decompressWithDictionary(ZBUFF_DCtx* dctx, const void* src, size_t srcSize); +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* maxDstSizePtr, const void* src, size_t* srcSizePtr); @@ -128,19 +128,16 @@ ZSTDLIB_API size_t ZBUFF_decompressContinue(ZBUFF_DCtx* dctx, void* dst, size_t* * * A ZBUFF_DCtx object is required to track streaming operation. * Use ZBUFF_createDCtx() and ZBUFF_freeDCtx() to create/release resources. -* Use ZBUFF_decompressInit() to start a new decompression operation. -* ZBUFF_DCtx objects can be reused multiple times. -* -* Optionally, a reference to a static dictionary can be set, using ZBUFF_decompressWithDictionary() -* It must be the same content as the one set during compression phase. -* Dictionary content must remain accessible during the decompression process. +* Use ZBUFF_decompressInit() to start a new decompression operation, +* or ZBUFF_decompressInitDictionary() if decompression requires a dictionary. +* Note that ZBUFF_DCtx objects can be reused multiple times. * * Use ZBUFF_decompressContinue() repetitively to consume your input. * *srcSizePtr and *maxDstSizePtr can be any size. * The function will report how many bytes were read or written by modifying *srcSizePtr and *maxDstSizePtr. * Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again. * The content of dst will be overwritten (up to *maxDstSizePtr) at each function call, so save its content if it matters or change dst. -* @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to improve latency) +* @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to help latency) * or 0 when a frame is completely decoded * or an error code, which can be tested using ZBUFF_isError(). * @@ -157,7 +154,7 @@ 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. -* These sizes are not compulsory, they just tend to offer better latency */ +* 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); ZSTDLIB_API size_t ZBUFF_recommendedDInSize(void); diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index db01c3385..4124e4f2b 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -225,6 +225,42 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, } +/*! ZSTD_copyCCtx +* Duplicate an existing context @srcCCtx into another one @dstCCtx. +* Only works during stage 0 (i.e. before first call to ZSTD_compressContinue()) +* @return : 0, or an error code */ +size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx) +{ + const U32 contentLog = (srcCCtx->params.strategy == ZSTD_fast) ? 1 : srcCCtx->params.contentLog; + const size_t tableSpace = ((1 << contentLog) + (1 << srcCCtx->params.hashLog)) * sizeof(U32); + + if (srcCCtx->stage!=0) return ERROR(stage_wrong); + + ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params); + + /* copy tables */ + memcpy(dstCCtx->hashTable, srcCCtx->hashTable, tableSpace); + + /* copy frame header */ + dstCCtx->hbSize = srcCCtx->hbSize; + memcpy(dstCCtx->headerBuffer , srcCCtx->headerBuffer, srcCCtx->hbSize); + + /* copy dictionary pointers */ + dstCCtx->nextToUpdate= srcCCtx->nextToUpdate; + dstCCtx->nextSrc = srcCCtx->nextSrc; + dstCCtx->base = srcCCtx->base; + dstCCtx->dictBase = srcCCtx->dictBase; + dstCCtx->dictLimit = srcCCtx->dictLimit; + dstCCtx->lowLimit = srcCCtx->lowLimit; + + dstCCtx->flagHufTable = srcCCtx->flagHufTable; + if (dstCCtx->flagHufTable) + memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4); + + return 0; +} + + /** ZSTD_reduceIndex * rescale indexes to avoid future overflow (indexes are U32) */ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, @@ -2133,49 +2169,17 @@ static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize) { - U32 magic = MEM_readLE32(dict); - U32 eSize; - if (magic != ZSTD_DICT_MAGIC) - return ZSTD_loadDictionaryContent(zc, dict, dictSize); - - eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+4, dictSize-4) + 4; - if (ZSTD_isError(eSize)) return eSize; - return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize); -} - - -/*! ZSTD_duplicateCCtx -* Duplicate an existing context @srcCCtx into another one @dstCCtx. -* Only works during stage 0 (i.e. before first call to ZSTD_compressContinue()) -* @return : 0, or an error code */ -size_t ZSTD_duplicateCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx) -{ - const U32 contentLog = (srcCCtx->params.strategy == ZSTD_fast) ? 1 : srcCCtx->params.contentLog; - const size_t tableSpace = ((1 << contentLog) + (1 << srcCCtx->params.hashLog)) * sizeof(U32); - - if (srcCCtx->stage!=0) return ERROR(stage_wrong); - - ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params); - - /* copy tables */ - memcpy(dstCCtx->hashTable, srcCCtx->hashTable, tableSpace); - - /* copy frame header */ - dstCCtx->hbSize = srcCCtx->hbSize; - memcpy(dstCCtx->headerBuffer , srcCCtx->headerBuffer, srcCCtx->hbSize); - - /* copy dictionary pointers */ - dstCCtx->nextToUpdate= srcCCtx->nextToUpdate; - dstCCtx->nextSrc = srcCCtx->nextSrc; - dstCCtx->base = srcCCtx->base; - dstCCtx->dictBase = srcCCtx->dictBase; - dstCCtx->dictLimit = srcCCtx->dictLimit; - dstCCtx->lowLimit = srcCCtx->lowLimit; - - dstCCtx->flagHufTable = srcCCtx->flagHufTable; - if (dstCCtx->flagHufTable) - memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4); + if (dict && dictSize) + { + U32 magic = MEM_readLE32(dict); + size_t eSize; + if (magic != ZSTD_DICT_MAGIC) + return ZSTD_loadDictionaryContent(zc, dict, dictSize); + eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+4, dictSize-4) + 4; + if (ZSTD_isError(eSize)) return eSize; + return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize); + } return 0; } diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index ce54d200d..93e82884c 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -136,6 +136,7 @@ struct ZSTD_DCtx_s ZSTD_parameters params; blockType_t bType; ZSTD_dStage stage; + U32 flagHufTable; const BYTE* litPtr; size_t litBufSize; size_t litSize; @@ -143,7 +144,7 @@ struct ZSTD_DCtx_s BYTE headerBuffer[ZSTD_frameHeaderSize_max]; }; /* typedef'd to ZSTD_DCtx within "zstd_static.h" */ -size_t ZSTD_resetDCtx(ZSTD_DCtx* dctx) +size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) { dctx->expected = ZSTD_frameHeaderSize_min; dctx->stage = ZSTDds_getFrameHeaderSize; @@ -152,6 +153,7 @@ size_t ZSTD_resetDCtx(ZSTD_DCtx* dctx) dctx->vBase = NULL; dctx->dictEnd = NULL; dctx->hufTableX4[0] = HufLog; + dctx->flagHufTable = 0; return 0; } @@ -159,7 +161,7 @@ ZSTD_DCtx* ZSTD_createDCtx(void) { ZSTD_DCtx* dctx = (ZSTD_DCtx*)malloc(sizeof(ZSTD_DCtx)); if (dctx==NULL) return NULL; - ZSTD_resetDCtx(dctx); + ZSTD_decompressBegin(dctx); return dctx; } @@ -169,6 +171,12 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx) return 0; } +void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) +{ + memcpy(dstDCtx, srcDCtx, + sizeof(ZSTD_DCtx) - (BLOCKSIZE+WILDCOPY_OVERLENGTH + ZSTD_frameHeaderSize_max)); /* no need to copy workspace */ +} + /* ************************************************************* * Decompression section @@ -342,6 +350,8 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, U32 lhSize = ((istart[0]) >> 4) & 3; if (lhSize != 1) /* only case supported for now : small litSize, single stream */ return ERROR(corruption_detected); + if (!dctx->flagHufTable) + return ERROR(dictionary_corrupted); /* 2 - 2 - 10 - 10 */ lhSize=3; @@ -631,14 +641,12 @@ FORCE_INLINE size_t ZSTD_execSequence(BYTE* op, *litPtr = litEnd; /* update for next sequence */ /* copy Match */ - if (sequence.offset > (size_t)(oLitEnd - base)) - { + if (sequence.offset > (size_t)(oLitEnd - base)) { /* offset beyond prefix */ if (sequence.offset > (size_t)(oLitEnd - vBase)) return ERROR(corruption_detected); match = dictEnd - (base-match); - if (match + sequence.matchLength <= dictEnd) - { + if (match + sequence.matchLength <= dictEnd) { memmove(oLitEnd, match, sequence.matchLength); return sequenceLength; } @@ -653,8 +661,7 @@ FORCE_INLINE size_t ZSTD_execSequence(BYTE* op, } /* match within prefix */ - if (sequence.offset < 8) - { + if (sequence.offset < 8) { /* close range match, overlap */ const int sub2 = dec64table[sequence.offset]; op[0] = match[0]; @@ -665,24 +672,20 @@ FORCE_INLINE size_t ZSTD_execSequence(BYTE* op, ZSTD_copy4(op+4, match); match -= sub2; } - else - { + else { ZSTD_copy8(op, match); } op += 8; match += 8; - if (oMatchEnd > oend-12) - { - if (op < oend_8) - { + if (oMatchEnd > oend-12) { + if (op < oend_8) { ZSTD_wildcopy(op, match, oend_8 - op); match += oend_8 - op; op = oend_8; } while (op < oMatchEnd) *op++ = *match++; } - else - { + else { ZSTD_wildcopy(op, match, sequence.matchLength-8); /* works even if matchLength < 8 */ } return sequenceLength; @@ -735,8 +738,7 @@ static size_t ZSTD_decompressSequences( FSE_initDState(&(seqState.stateOffb), &(seqState.DStream), DTableOffb); FSE_initDState(&(seqState.stateML), &(seqState.DStream), DTableML); - for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && nbSeq ; ) - { + for ( ; (BIT_reloadDStream(&(seqState.DStream)) <= BIT_DStream_completed) && nbSeq ; ) { size_t oneSeqSize; nbSeq--; ZSTD_decodeSequence(&sequence, &seqState); @@ -764,8 +766,7 @@ static size_t ZSTD_decompressSequences( static void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst) { - if (dst != dctx->previousDstEnd) /* not contiguous */ - { + if (dst != dctx->previousDstEnd) { /* not contiguous */ dctx->dictEnd = dctx->previousDstEnd; dctx->vBase = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base)); dctx->base = dst; @@ -800,10 +801,11 @@ size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, } -size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, +/*! ZSTD_decompress_continueDCtx +* dctx must have been properly initialized */ +static size_t ZSTD_decompress_continueDCtx(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, - const void* src, size_t srcSize, - const void* dict, size_t dictSize) + const void* src, size_t srcSize) { const BYTE* ip = (const BYTE*)src; const BYTE* iend = ip + srcSize; @@ -813,21 +815,6 @@ size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, size_t remainingSize = srcSize; blockProperties_t blockProperties; - /* init */ - ZSTD_resetDCtx(dctx); - if (dict) - { - size_t errorCode = ZSTD_decompress_insertDictionary(dctx, dict, dictSize); - if (ZSTD_isError(errorCode)) return ERROR(dictionary_corrupted); - dctx->dictEnd = dctx->previousDstEnd; - dctx->vBase = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->base)); - dctx->base = dst; - } - else - { - dctx->vBase = dctx->base = dctx->dictEnd = dst; - } - /* Frame Header */ { size_t frameHeaderSize; @@ -888,6 +875,27 @@ size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, } +size_t ZSTD_decompress_usingPreparedDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* refDCtx, + void* dst, size_t maxDstSize, + const void* src, size_t srcSize) +{ + ZSTD_copyDCtx(dctx, refDCtx); + ZSTD_checkContinuity(dctx, dst); + return ZSTD_decompress_continueDCtx(dctx, dst, maxDstSize, src, srcSize); +} + + +size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, + void* dst, size_t maxDstSize, + const void* src, size_t srcSize, + const void* dict, size_t dictSize) +{ + ZSTD_decompressBegin_usingDict(dctx, dict, dictSize); + ZSTD_checkContinuity(dctx, dst); + return ZSTD_decompress_continueDCtx(dctx, dst, maxDstSize, src, srcSize); +} + + size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize) { return ZSTD_decompress_usingDict(dctx, dst, maxDstSize, src, srcSize, NULL, 0); @@ -933,8 +941,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, co dctx->headerSize = ZSTD_decodeFrameHeader_Part1(dctx, src, ZSTD_frameHeaderSize_min); if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize; memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_min); - if (dctx->headerSize > ZSTD_frameHeaderSize_min) - { + if (dctx->headerSize > ZSTD_frameHeaderSize_min) { dctx->expected = dctx->headerSize - ZSTD_frameHeaderSize_min; dctx->stage = ZSTDds_decodeFrameHeader; return 0; @@ -958,13 +965,11 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, co blockProperties_t bp; size_t blockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp); if (ZSTD_isError(blockSize)) return blockSize; - if (bp.blockType == bt_end) - { + if (bp.blockType == bt_end) { dctx->expected = 0; dctx->stage = ZSTDds_getFrameHeaderSize; } - else - { + else { dctx->expected = blockSize; dctx->bType = bp.blockType; dctx->stage = ZSTDds_decompressBlock; @@ -990,7 +995,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, co rSize = 0; break; default: - return ERROR(GENERIC); + return ERROR(GENERIC); /* impossible */ } dctx->stage = ZSTDds_decodeBlockHeader; dctx->expected = ZSTD_blockHeaderSize; @@ -1011,15 +1016,15 @@ static void ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dictSi dctx->previousDstEnd = (const char*)dict + dictSize; } - static size_t ZSTD_loadEntropy(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) { size_t hSize = HUF_readDTableX4(dctx->hufTableX4, dict, dictSize); if (HUF_isError(hSize)) return ERROR(dictionary_corrupted); + dctx->flagHufTable = 1; return hSize; } -size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) { size_t eSize; U32 magic = MEM_readLE32(dict); @@ -1042,3 +1047,18 @@ size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_ return 0; } + +size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) +{ + size_t errorCode; + errorCode = ZSTD_decompressBegin(dctx); + if (ZSTD_isError(errorCode)) return errorCode; + + if (dict && dictSize) { + errorCode = ZSTD_decompress_insertDictionary(dctx, dict, dictSize); + if (ZSTD_isError(errorCode)) return ERROR(dictionary_corrupted); + } + + return 0; +} + diff --git a/lib/zstd_static.h b/lib/zstd_static.h index f99893d71..fd4131ae7 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -92,7 +92,7 @@ ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint ZSTDLIB_API void ZSTD_validateParams(ZSTD_parameters* params); /** ZSTD_compress_usingDict -* Same as ZSTD_compressCCtx(), using a Dictionary content as prefix +* Same as ZSTD_compressCCtx(), loading a Dictionary content. * Note : dict can be NULL, in which case, it's equivalent to ZSTD_compressCCtx() */ ZSTDLIB_API size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, @@ -108,14 +108,24 @@ ZSTDLIB_API size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, const void* dict,size_t dictSize, ZSTD_parameters params); -/** ZSTD_decompress_usingDict +/*! ZSTD_decompress_usingDict * Same as ZSTD_decompressDCtx, using a Dictionary content as prefix * Note : dict can be NULL, in which case, it's equivalent to ZSTD_decompressDCtx() */ -ZSTDLIB_API size_t ZSTD_decompress_usingDict(ZSTD_DCtx* ctx, +ZSTDLIB_API size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize, const void* dict,size_t dictSize); +/*! ZSTD_decompress_usingPreparedDCtx +* Same as ZSTD_decompress_usingDict, but using a reference context preparedDCtx, where dictionary has already been loaded into. +* It avoids reloading the dictionary each time. +* preparedDCtx must have been properly initialized using ZSTD_compressBegin_usingDict(). +* Requires 2 contexts : 1 for reference, which will not be modified, and 1 to run the decompression operation */ +ZSTDLIB_API size_t ZSTD_decompress_usingPreparedDCtx( + ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx, + void* dst, size_t maxDstSize, + const void* src, size_t srcSize); + /* ************************************** * Streaming functions (direct mode) @@ -127,7 +137,7 @@ ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dic ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* ctx, ZSTD_parameters params); ZSTDLIB_API size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* ctx, const void* dict, size_t dictSize); -ZSTDLIB_API size_t ZSTD_duplicateCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx); +ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx); ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize); ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t maxDstSize); @@ -164,9 +174,11 @@ ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t maxDstSiz */ -ZSTDLIB_API size_t ZSTD_resetDCtx(ZSTD_DCtx* dctx); +ZSTDLIB_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx); +ZSTDLIB_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); +ZSTDLIB_API void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx); + ZSTDLIB_API size_t ZSTD_getFrameParams(ZSTD_parameters* params, const void* src, size_t srcSize); -ZSTDLIB_API size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* ctx, const void* src, size_t srcSize); ZSTDLIB_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize); @@ -176,20 +188,19 @@ ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t ma A ZSTD_DCtx object is required to track streaming operations. Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it. - A ZSTD_DCtx object can be re-used multiple times. Use ZSTD_resetDCtx() to return to fresh status. + A ZSTD_DCtx object can be re-used multiple times. - First operation is to retrieve frame parameters, using ZSTD_getFrameParams(). - This function doesn't consume its input. It needs enough input data to properly decode the frame header. + First typical operation is to retrieve frame parameters, using ZSTD_getFrameParams(). + This operation is independent, and just needs enough input data to properly decode the frame header. Objective is to retrieve *params.windowlog, to know minimum amount of memory required during decoding. Result : 0 when successful, it means the ZSTD_parameters structure has been filled. >0 : means there is not enough data into src. Provides the expected size to successfully decode header. - errorCode, which can be tested using ZSTD_isError() (For example, if it's not a ZSTD header) + errorCode, which can be tested using ZSTD_isError() - Then, you can optionally insert a dictionary. - This operation must mimic the compressor behavior, otherwise decompression will fail or be corrupted. + Start decompression, with ZSTD_decompressBegin() or ZSTD_decompressBegin_usingDict() + Alternatively, you can copy a prepared context, using ZSTD_copyDCtx() - Then it's possible to start decompression. - Use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively. + Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively. ZSTD_nextSrcSizeToDecompress() tells how much bytes to provide as 'srcSize' to ZSTD_decompressContinue(). ZSTD_decompressContinue() requires this exact amount of bytes, or it will fail. ZSTD_decompressContinue() needs previous data blocks during decompression, up to (1 << windowlog). @@ -206,23 +217,23 @@ ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t ma /* ************************************** * Block functions ****************************************/ - /*!Block functions produce and decode raw zstd blocks, without frame metadata. - It saves associated header sizes. - But user will have to save and regenerate fields required to regenerate data, such as block sizes. + Frame headers won't be generated. + User will have to save and regenerate fields required to regenerate data, such as block sizes. A few rules to respect : - Uncompressed block size must be <= 128 KB - - Compressing or decompressing require a context structure + - Compressing or decompressing requires a context structure + Use ZSTD_createXCtx() to create them - It is necessary to init context before starting - + compression : ZSTD_compressBegin(), which allows selection of compression level or parameters - + decompression : ZSTD_resetDCtx() - + If you compress multiple blocks without resetting, next blocks will create references to previous ones - - Dictionary can optionally be inserted, using ZSTD_de/compress_insertDictionary() + + compression : ZSTD_compressBegin() + + decompression : ZSTD_decompressBegin() + + variants _usingDict() are also allowed + + copyXCtx() works too - When a block is considered not compressible enough, ZSTD_compressBlock() result will be zero. - + User must test for such outcome and be able to deal with uncompressed data - + ZSTD_decompressBlock() doesn't accept uncompressed data as input + In which case, nothing is produced into `dst`. + + User must test for such outcome and deal directly with uncompressed data + + ZSTD_decompressBlock() doesn't accept uncompressed data as input !! */ size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize); diff --git a/programs/bench.c b/programs/bench.c index 30555660f..f5b6f8d5c 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -227,6 +227,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, void* const resultBuffer = malloc(srcSize); ZSTD_CCtx* refCtx = ZSTD_createCCtx(); ZSTD_CCtx* ctx = ZSTD_createCCtx(); + ZSTD_DCtx* refDCtx = ZSTD_createDCtx(); ZSTD_DCtx* dctx = ZSTD_createDCtx(); U64 crcOrig = XXH64(srcBuffer, srcSize, 0); U32 nbBlocks = 0; @@ -235,7 +236,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, if (strlen(displayName)>17) displayName += strlen(displayName)-17; /* can only display 17 characters */ /* Memory allocation & restrictions */ - if (!compressedBuffer || !resultBuffer || !blockTable || !refCtx || !ctx || !dctx) + if (!compressedBuffer || !resultBuffer || !blockTable || !refCtx || !ctx || !refDCtx || !dctx) EXM_THROW(31, "not enough memory"); /* Init blockTable data */ @@ -298,7 +299,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, ZSTD_compress_insertDictionary(refCtx, dictBuffer, dictBufferSize); for (blockNb=0; blockNb%10i (%5.3f),%6.1f MB/s ,%6.1f MB/s\r", loopNb, displayName, (int)srcSize, (int)cSize, ratio, (double)srcSize / fastestC / 1000., (double)srcSize / fastestD / 1000.); /* CRC Checking */ crcCheck = XXH64(resultBuffer, srcSize, 0); - if (crcOrig!=crcCheck) - { + if (crcOrig!=crcCheck) { size_t u; DISPLAY("\n!!! WARNING !!! %14s : Invalid Checksum : %x != %x\n", displayName, (unsigned)crcOrig, (unsigned)crcCheck); - for (u=0; u u) break; bacc += blockTable[segNb].srcSize; } @@ -365,8 +367,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, bNb = pos / (128 KB); printf("(segment %u, block %u, pos %u) \n", segNb, bNb, pos); break; - } - } + } } break; } #endif @@ -375,7 +376,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, if (crcOrig == crcCheck) DISPLAY("%2i-%-17.17s :%10i ->%10i (%5.3f),%6.1f MB/s ,%6.1f MB/s \n", cLevel, displayName, (int)srcSize, (int)cSize, ratio, (double)srcSize / fastestC / 1000., (double)srcSize / fastestD / 1000.); else - DISPLAY("X \n"); + DISPLAY("\n"); } /* clean up */ @@ -383,6 +384,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, free(resultBuffer); ZSTD_freeCCtx(refCtx); ZSTD_freeCCtx(ctx); + ZSTD_freeDCtx(refDCtx); ZSTD_freeDCtx(dctx); return 0; } diff --git a/programs/fileio.c b/programs/fileio.c index 0d49af2b9..4bab75eae 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -529,8 +529,7 @@ unsigned long long FIO_decompressFrame(dRess_t ress, size_t readSize=alreadyLoaded; /* Main decompression Loop */ - ZBUFF_decompressInit(ress.dctx); - ZBUFF_decompressWithDictionary(ress.dctx, ress.dictBuffer, ress.dictBufferSize); + ZBUFF_decompressInitDictionary(ress.dctx, ress.dictBuffer, ress.dictBufferSize); while (1) { /* Decode */ diff --git a/programs/fuzzer.c b/programs/fuzzer.c index 4058ef24d..b72f7e574 100644 --- a/programs/fuzzer.c +++ b/programs/fuzzer.c @@ -207,7 +207,7 @@ static int basicUnitTests(U32 seed, double compressibility) if (ZSTD_isError(result)) goto _output_error; result = ZSTD_compress_insertDictionary(ctxOrig, CNBuffer, dictSize); if (ZSTD_isError(result)) goto _output_error; - result = ZSTD_duplicateCCtx(ctxDuplicated, ctxOrig); + result = ZSTD_copyCCtx(ctxDuplicated, ctxOrig); if (ZSTD_isError(result)) goto _output_error; DISPLAYLEVEL(4, "OK \n"); @@ -284,7 +284,7 @@ static int basicUnitTests(U32 seed, double compressibility) DISPLAYLEVEL(4, "OK \n"); DISPLAYLEVEL(4, "test%3i : Block decompression test : ", testNb++); - result = ZSTD_resetDCtx(dctx); + result = ZSTD_decompressBegin(dctx); if (ZSTD_isError(result)) goto _output_error; result = ZSTD_decompressBlock(dctx, decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize); if (ZSTD_isError(result)) goto _output_error; @@ -302,9 +302,8 @@ static int basicUnitTests(U32 seed, double compressibility) DISPLAYLEVEL(4, "OK \n"); DISPLAYLEVEL(4, "test%3i : Dictionary Block decompression test : ", testNb++); - result = ZSTD_resetDCtx(dctx); + result = ZSTD_decompressBegin_usingDict(dctx, CNBuffer, dictSize); if (ZSTD_isError(result)) goto _output_error; - ZSTD_decompress_insertDictionary(dctx, CNBuffer, dictSize); result = ZSTD_decompressBlock(dctx, decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize); if (ZSTD_isError(result)) goto _output_error; if (result != blockSize) goto _output_error; @@ -574,7 +573,7 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit CHECK (ZSTD_isError(errorCode), "start streaming error : %s", ZSTD_getErrorName(errorCode)); errorCode = ZSTD_compress_insertDictionary(refCtx, dict, dictSize); CHECK (ZSTD_isError(errorCode), "dictionary insertion error : %s", ZSTD_getErrorName(errorCode)); - errorCode = ZSTD_duplicateCCtx(ctx, refCtx); + errorCode = ZSTD_copyCCtx(ctx, refCtx); CHECK (ZSTD_isError(errorCode), "context duplication error : %s", ZSTD_getErrorName(errorCode)); totalTestSize = 0; cSize = 0; for (n=0; n Date: Tue, 26 Jan 2016 16:31:22 +0100 Subject: [PATCH 08/34] modified streaming compression API --- lib/zstd_buffered.c | 11 +++++------ lib/zstd_buffered.h | 18 ++++++++++-------- lib/zstd_buffered_static.h | 4 ++-- lib/zstd_compress.c | 39 ++++++++++++++++---------------------- lib/zstd_static.h | 28 ++++++++------------------- programs/bench.c | 3 +-- programs/fileio.c | 13 ++++--------- programs/fuzzer.c | 14 ++++---------- programs/zbufftest.c | 6 ++---- 9 files changed, 52 insertions(+), 84 deletions(-) diff --git a/lib/zstd_buffered.c b/lib/zstd_buffered.c index aab83e606..dc7b57490 100644 --- a/lib/zstd_buffered.c +++ b/lib/zstd_buffered.c @@ -119,7 +119,7 @@ size_t ZBUFF_freeCCtx(ZBUFF_CCtx* zbc) #define MIN(a,b) ( ((a)<(b)) ? (a) : (b) ) #define BLOCKSIZE (128 * 1024) /* a bit too "magic", should come from reference */ -size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc, ZSTD_parameters params) +size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc, const void* dict, size_t dictSize, ZSTD_parameters params) { size_t neededInBuffSize; @@ -143,7 +143,7 @@ size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc, ZSTD_parameters params) if (zbc->outBuff == NULL) return ERROR(memory_allocation); } - zbc->outBuffContentSize = ZSTD_compressBegin_advanced(zbc->zc, params); + zbc->outBuffContentSize = ZSTD_compressBegin_advanced(zbc->zc, dict, dictSize, params); if (ZSTD_isError(zbc->outBuffContentSize)) return zbc->outBuffContentSize; zbc->inToCompress = 0; @@ -156,14 +156,13 @@ size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc, ZSTD_parameters params) size_t ZBUFF_compressInit(ZBUFF_CCtx* zbc, int compressionLevel) { - return ZBUFF_compressInit_advanced(zbc, ZSTD_getParams(compressionLevel, 0)); + return ZBUFF_compressInit_advanced(zbc, NULL, 0, ZSTD_getParams(compressionLevel, 0)); } -ZSTDLIB_API size_t ZBUFF_compressWithDictionary(ZBUFF_CCtx* zbc, const void* src, size_t srcSize) +ZSTDLIB_API size_t ZBUFF_compressInitDictionary(ZBUFF_CCtx* zbc, const void* dict, size_t dictSize, int compressionLevel) { - ZSTD_compress_insertDictionary(zbc->zc, src, srcSize); - return 0; + return ZBUFF_compressInit_advanced(zbc, dict, dictSize, ZSTD_getParams(compressionLevel, 0)); } diff --git a/lib/zstd_buffered.h b/lib/zstd_buffered.h index 63101a107..1e8830b1e 100644 --- a/lib/zstd_buffered.h +++ b/lib/zstd_buffered.h @@ -69,7 +69,8 @@ ZSTDLIB_API ZBUFF_CCtx* ZBUFF_createCCtx(void); ZSTDLIB_API size_t ZBUFF_freeCCtx(ZBUFF_CCtx* cctx); ZSTDLIB_API size_t ZBUFF_compressInit(ZBUFF_CCtx* cctx, int compressionLevel); -ZSTDLIB_API size_t ZBUFF_compressWithDictionary(ZBUFF_CCtx* cctx, const void* dict, size_t dictSize); +ZSTDLIB_API size_t ZBUFF_compressInitDictionary(ZBUFF_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel); + ZSTDLIB_API size_t ZBUFF_compressContinue(ZBUFF_CCtx* cctx, void* dst, size_t* maxDstSizePtr, const void* src, size_t* srcSizePtr); ZSTDLIB_API size_t ZBUFF_compressFlush(ZBUFF_CCtx* cctx, void* dst, size_t* maxDstSizePtr); ZSTDLIB_API size_t ZBUFF_compressEnd(ZBUFF_CCtx* cctx, void* dst, size_t* maxDstSizePtr); @@ -79,11 +80,11 @@ ZSTDLIB_API size_t ZBUFF_compressEnd(ZBUFF_CCtx* cctx, void* dst, size_t* maxDst * * A ZBUFF_CCtx object is required to track streaming operation. * Use ZBUFF_createCCtx() and ZBUFF_freeCCtx() to create/release resources. -* Use ZBUFF_compressInit() to start a new compression operation. * ZBUFF_CCtx objects can be reused multiple times. * -* Optionally, a reference to a static dictionary can be created with ZBUFF_compressWithDictionary() -* Note that the dictionary content must remain accessible during the compression process. +* Start by initializing ZBUF_CCtx. +* Use ZBUFF_compressInit() to start a new compression operation. +* Use ZBUFF_compressInitDictionary() for a compression which requires a dictionary. * * Use ZBUFF_compressContinue() repetitively to consume input stream. * *srcSizePtr and *maxDstSizePtr can be any size. @@ -93,9 +94,10 @@ ZSTDLIB_API size_t ZBUFF_compressEnd(ZBUFF_CCtx* cctx, void* dst, size_t* maxDst * @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to improve latency) * or an error code, which can be tested using ZBUFF_isError(). * -* ZBUFF_compressFlush() can be used to instruct ZBUFF to compress and output whatever remains within its buffer. -* Note that it will not output more than *maxDstSizePtr. -* Therefore, some content might still be left into its internal buffer if dst buffer is too small. +* At any moment, it's possible to flush whatever data remains within buffer, using ZBUFF_compressFlush(). +* The nb of bytes written into `dst` will be reported into *maxDstSizePtr. +* Note that the function cannot output more than the size of `dst` buffer (initial value of *maxDstSizePtr). +* Therefore, some content might still be left into internal buffer if dst buffer is too small. * @return : nb of bytes still present into internal buffer (0 if it's empty) * or an error code, which can be tested using ZBUFF_isError(). * @@ -108,7 +110,7 @@ ZSTDLIB_API size_t ZBUFF_compressEnd(ZBUFF_CCtx* cctx, void* dst, size_t* maxDst * or an error code, which can be tested using ZBUFF_isError(). * * Hint : recommended buffer sizes (not compulsory) : ZBUFF_recommendedCInSize / ZBUFF_recommendedCOutSize -* input : ZBUFF_recommendedCInSize==128 KB block size is the internal unit, it improves latency to use this value. +* input : ZBUFF_recommendedCInSize==128 KB block size is the internal unit, it improves latency to use this value (skipped buffering). * output : ZBUFF_recommendedCOutSize==ZSTD_compressBound(128 KB) + 3 + 3 : ensures it's always possible to write/flush/end a full block. Skip some buffering. * By using both, you ensure that input will be entirely consumed, and output will always contain the result. * **************************************************/ diff --git a/lib/zstd_buffered_static.h b/lib/zstd_buffered_static.h index 7d9ee27d2..5052f4c3e 100644 --- a/lib/zstd_buffered_static.h +++ b/lib/zstd_buffered_static.h @@ -45,14 +45,14 @@ extern "C" { /* ************************************* * Includes ***************************************/ -#include "zstd_static.h" +#include "zstd_static.h" /* ZSTD_parameters */ #include "zstd_buffered.h" /* ************************************* * Advanced Streaming functions ***************************************/ -ZSTDLIB_API size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* cctx, ZSTD_parameters params); +ZSTDLIB_API size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params); #if defined (__cplusplus) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 4124e4f2b..8ebd58beb 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -2167,7 +2167,7 @@ static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t return hufHeaderSize; } -size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize) +static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize) { if (dict && dictSize) { @@ -2186,22 +2186,23 @@ size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t di /*! ZSTD_compressBegin_advanced * @return : 0, or an error code */ -size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* ctx, +size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc, + const void* dict, size_t dictSize, ZSTD_parameters params) { size_t errorCode; ZSTD_validateParams(¶ms); - errorCode = ZSTD_resetCCtx_advanced(ctx, params); + errorCode = ZSTD_resetCCtx_advanced(zc, params); if (ZSTD_isError(errorCode)) return errorCode; - MEM_writeLE32(ctx->headerBuffer, ZSTD_MAGICNUMBER); /* Write Header */ - ((BYTE*)ctx->headerBuffer)[4] = (BYTE)(params.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN); - ctx->hbSize = ZSTD_frameHeaderSize_min; - ctx->stage = 0; + MEM_writeLE32(zc->headerBuffer, ZSTD_MAGICNUMBER); /* Write Header */ + ((BYTE*)zc->headerBuffer)[4] = (BYTE)(params.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN); + zc->hbSize = ZSTD_frameHeaderSize_min; + zc->stage = 0; - return 0; + return ZSTD_compress_insertDictionary(zc, dict, dictSize); } @@ -2219,15 +2220,14 @@ ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint) return result; } -/* to do -size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict,size_t dictSize, int compressionLevel) +size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* zc, const void* dict, size_t dictSize, int compressionLevel) { - return 0; -}*/ + return ZSTD_compressBegin_advanced(zc, dict, dictSize, ZSTD_getParams(compressionLevel, 0)); +} -size_t ZSTD_compressBegin(ZSTD_CCtx* ctx, int compressionLevel) +size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel) { - return ZSTD_compressBegin_advanced(ctx, ZSTD_getParams(compressionLevel, 0)); + return ZSTD_compressBegin_advanced(zc, NULL, 0, ZSTD_getParams(compressionLevel, 0)); } @@ -2269,17 +2269,10 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, BYTE* op = ostart; size_t oSize; - /* Header */ - oSize = ZSTD_compressBegin_advanced(ctx, params); + /* Init */ + oSize = ZSTD_compressBegin_advanced(ctx, dict, dictSize, params); if(ZSTD_isError(oSize)) return oSize; - /* dictionary */ - if (dict) - { - oSize = ZSTD_compress_insertDictionary(ctx, dict, dictSize); - if (ZSTD_isError(oSize)) return oSize; - } - /* body (compression) */ oSize = ZSTD_compressContinue (ctx, op, maxDstSize, src, srcSize); if(ZSTD_isError(oSize)) return oSize; diff --git a/lib/zstd_static.h b/lib/zstd_static.h index fd4131ae7..b985ce1e8 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -132,12 +132,8 @@ ZSTDLIB_API size_t ZSTD_decompress_usingPreparedDCtx( ****************************************/ ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict,size_t dictSize, int compressionLevel); -//ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* ctx, const void* dict,size_t dictSize, ZSTD_parameters params); - -ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* ctx, ZSTD_parameters params); - -ZSTDLIB_API size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* ctx, const void* dict, size_t dictSize); -ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx); +ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict,size_t dictSize, ZSTD_parameters params); +ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx); ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize); ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t maxDstSize); @@ -149,18 +145,10 @@ ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t maxDstSiz Use ZSTD_createCCtx() / ZSTD_freeCCtx() to manage it. ZSTD_CCtx object can be re-used multiple times within successive compression operations. - First operation is to start a new frame. - Use ZSTD_compressBegin(). - You may also prefer the advanced derivative ZSTD_compressBegin_advanced(), for finer parameter control. - - It's then possible to add a dictionary with ZSTD_compress_insertDictionary() - Note that dictionary presence is a "hidden" information, - the decoder needs to be aware that it is required for proper decoding, or decoding will fail. - - If you want to compress a lot of messages using same dictionary, - it can be beneficial to duplicate compression context rather than reloading dictionary each time. - In such case, use ZSTD_duplicateCCtx(), which will need an already created ZSTD_CCtx, - in order to duplicate compression context into it. + Start by initializing a context. + Use ZSTD_compressBegin(), or ZSTD_compressBegin_usingDict() for dictionary compression, + or ZSTD_compressBegin_advanced(), for finer parameter control. + It's also possible to duplicate a reference context which has been initialized, using ZSTD_copyCCtx() Then, consume your input using ZSTD_compressContinue(). The interface is synchronous, so all input will be consumed and produce a compressed output. @@ -168,7 +156,7 @@ ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t maxDstSiz Worst case evaluation is provided by ZSTD_compressBound(). Finish a frame with ZSTD_compressEnd(), which will write the epilogue. - Without it, the frame will be considered incomplete by decoders. + Without the epilogue, frames will be considered incomplete by decoder. You can then reuse ZSTD_CCtx to compress some new frame. */ @@ -176,7 +164,7 @@ ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t maxDstSiz ZSTDLIB_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx); ZSTDLIB_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); -ZSTDLIB_API void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx); +ZSTDLIB_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); ZSTDLIB_API size_t ZSTD_getFrameParams(ZSTD_parameters* params, const void* src, size_t srcSize); diff --git a/programs/bench.c b/programs/bench.c index f5b6f8d5c..1f35301f0 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -295,8 +295,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, milliTime = BMK_GetMilliStart(); while (BMK_GetMilliSpan(milliTime) < TIMELOOP) { - ZSTD_compressBegin_advanced(refCtx, ZSTD_getParams(cLevel, dictBufferSize+largestBlockSize)); - ZSTD_compress_insertDictionary(refCtx, dictBuffer, dictBufferSize); + ZSTD_compressBegin_advanced(refCtx, dictBuffer, dictBufferSize, ZSTD_getParams(cLevel, dictBufferSize+largestBlockSize)); for (blockNb=0; blockNb>20)); diff --git a/programs/fuzzer.c b/programs/fuzzer.c index b72f7e574..93a029ecb 100644 --- a/programs/fuzzer.c +++ b/programs/fuzzer.c @@ -203,9 +203,7 @@ static int basicUnitTests(U32 seed, double compressibility) size_t cSizeOrig; DISPLAYLEVEL(4, "test%3i : load dictionary into context : ", testNb++); - result = ZSTD_compressBegin(ctxOrig, 2); - if (ZSTD_isError(result)) goto _output_error; - result = ZSTD_compress_insertDictionary(ctxOrig, CNBuffer, dictSize); + result = ZSTD_compressBegin_usingDict(ctxOrig, CNBuffer, dictSize, 2); if (ZSTD_isError(result)) goto _output_error; result = ZSTD_copyCCtx(ctxDuplicated, ctxOrig); if (ZSTD_isError(result)) goto _output_error; @@ -293,9 +291,7 @@ static int basicUnitTests(U32 seed, double compressibility) /* dictionary block compression */ DISPLAYLEVEL(4, "test%3i : Dictionary Block compression test : ", testNb++); - result = ZSTD_compressBegin(cctx, 5); - if (ZSTD_isError(result)) goto _output_error; - result = ZSTD_compress_insertDictionary(cctx, CNBuffer, dictSize); + result = ZSTD_compressBegin_usingDict(cctx, CNBuffer, dictSize, 5); if (ZSTD_isError(result)) goto _output_error; cSize = ZSTD_compressBlock(cctx, compressedBuffer, ZSTD_compressBound(blockSize), (char*)CNBuffer+dictSize, blockSize); if (ZSTD_isError(cSize)) goto _output_error; @@ -569,10 +565,8 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit dict = srcBuffer + sampleStart; dictSize = sampleSize; - errorCode = ZSTD_compressBegin(refCtx, (FUZ_rand(&lseed) % (20 - (sampleSizeLog/3))) + 1); - CHECK (ZSTD_isError(errorCode), "start streaming error : %s", ZSTD_getErrorName(errorCode)); - errorCode = ZSTD_compress_insertDictionary(refCtx, dict, dictSize); - CHECK (ZSTD_isError(errorCode), "dictionary insertion error : %s", ZSTD_getErrorName(errorCode)); + errorCode = ZSTD_compressBegin_usingDict(refCtx, dict, dictSize, (FUZ_rand(&lseed) % (20 - (sampleSizeLog/3))) + 1); + CHECK (ZSTD_isError(errorCode), "ZSTD_compressBegin_usingDict error : %s", ZSTD_getErrorName(errorCode)); errorCode = ZSTD_copyCCtx(ctx, refCtx); CHECK (ZSTD_isError(errorCode), "context duplication error : %s", ZSTD_getErrorName(errorCode)); totalTestSize = 0; cSize = 0; diff --git a/programs/zbufftest.c b/programs/zbufftest.c index 4c1b7ba4e..a8257dfc0 100644 --- a/programs/zbufftest.c +++ b/programs/zbufftest.c @@ -158,10 +158,9 @@ static int basicUnitTests(U32 seed, double compressibility) /* Basic compression test */ DISPLAYLEVEL(4, "test%3i : compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH); - ZBUFF_compressInit(zc, 1); + ZBUFF_compressInitDictionary(zc, CNBuffer, 128 KB, 1); readSize = CNBufferSize; genSize = compressedBufferSize; - ZBUFF_compressWithDictionary(zc, CNBuffer, 128 KB); result = ZBUFF_compressContinue(zc, compressedBuffer, &genSize, CNBuffer, &readSize); if (ZBUFF_isError(result)) goto _output_error; if (readSize != CNBufferSize) goto _output_error; /* entire input should be consumed */ @@ -317,7 +316,6 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit sampleSizeLog = FUZ_rand(&lseed) % maxSrcLog; maxTestSize = (size_t)1 << sampleSizeLog; maxTestSize += FUZ_rand(&lseed) & (maxTestSize-1); - ZBUFF_compressInit(zc, (FUZ_rand(&lseed) % (20 - (sampleSizeLog/3))) + 1); sampleSizeLog = FUZ_rand(&lseed) % maxSampleLog; sampleSize = (size_t)1 << sampleSizeLog; @@ -325,7 +323,7 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit sampleStart = FUZ_rand(&lseed) % (srcBufferSize - sampleSize); dict = srcBuffer + sampleStart; dictSize = sampleSize; - ZBUFF_compressWithDictionary(zc, dict, dictSize); + ZBUFF_compressInitDictionary(zc, dict, dictSize, (FUZ_rand(&lseed) % (20 - (sampleSizeLog/3))) + 1); totalTestSize = 0; cSize = 0; From fb810d6053a5ae1a5a772015cb5945896bebfe01 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Jan 2016 00:18:06 +0100 Subject: [PATCH 09/34] changed dictionary format --- NEWS | 3 + lib/fse.c | 158 +++++--------- lib/fse.h | 2 +- lib/fse_static.h | 3 +- lib/zstd_compress.c | 467 +++++++++++++++++++----------------------- lib/zstd_decompress.c | 218 ++++++++++++++------ lib/zstd_internal.h | 10 +- programs/bench.c | 21 +- 8 files changed, 437 insertions(+), 445 deletions(-) diff --git a/NEWS b/NEWS index 8aaf02d99..f146eb140 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,6 @@ +v0.5.0 +Changed streaming & dictionary API + v0.4.7 Improved : small compression speed improvement in HC mode Changed : `zstd_decompress.c` has ZSTD_LEGACY_SUPPORT to 0 by default diff --git a/lib/fse.c b/lib/fse.c index e74c1e833..309b28caf 100644 --- a/lib/fse.c +++ b/lib/fse.c @@ -425,10 +425,7 @@ size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog) return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND; /* maxSymbolValue==0 ? use default */ } -static short FSE_abs(short a) -{ - return a<0 ? -a : a; -} +static short FSE_abs(short a) { return a<0 ? -a : a; } static size_t FSE_writeNCount_generic (void* header, size_t headerBufferSize, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, @@ -457,14 +454,11 @@ static size_t FSE_writeNCount_generic (void* header, size_t headerBufferSize, threshold = tableSize; nbBits = tableLog+1; - while (remaining>1) /* stops at 1 */ - { - if (previous0) - { + while (remaining>1) { /* stops at 1 */ + if (previous0) { unsigned start = charnum; while (!normalizedCounter[charnum]) charnum++; - while (charnum >= start+24) - { + while (charnum >= start+24) { start+=24; bitStream += 0xFFFFU << bitCount; if ((!writeIsSafe) && (out > oend-2)) return ERROR(dstSize_tooSmall); /* Buffer overflow */ @@ -473,24 +467,21 @@ static size_t FSE_writeNCount_generic (void* header, size_t headerBufferSize, out+=2; bitStream>>=16; } - while (charnum >= start+3) - { + while (charnum >= start+3) { start+=3; bitStream += 3 << bitCount; bitCount += 2; } bitStream += (charnum-start) << bitCount; bitCount += 2; - if (bitCount>16) - { + if (bitCount>16) { if ((!writeIsSafe) && (out > oend - 2)) return ERROR(dstSize_tooSmall); /* Buffer overflow */ out[0] = (BYTE)bitStream; out[1] = (BYTE)(bitStream>>8); out += 2; bitStream >>= 16; bitCount -= 16; - } - } + } } { short count = normalizedCounter[charnum++]; const short max = (short)((2*threshold-1)-remaining); @@ -504,8 +495,7 @@ static size_t FSE_writeNCount_generic (void* header, size_t headerBufferSize, previous0 = (count==1); while (remaining>=1; } - if (bitCount>16) - { + if (bitCount>16) { if ((!writeIsSafe) && (out > oend - 2)) return ERROR(dstSize_tooSmall); /* Buffer overflow */ out[0] = (BYTE)bitStream; out[1] = (BYTE)(bitStream>>8); @@ -564,27 +554,19 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t threshold = 1<1) && (charnum<=*maxSVPtr)) - { - if (previous0) - { + while ((remaining>1) && (charnum<=*maxSVPtr)) { + if (previous0) { unsigned n0 = charnum; - while ((bitStream & 0xFFFF) == 0xFFFF) - { + while ((bitStream & 0xFFFF) == 0xFFFF) { n0+=24; - if (ip < iend-5) - { + if (ip < iend-5) { ip+=2; bitStream = MEM_readLE32(ip) >> bitCount; - } - else - { + } else { bitStream >>= 16; bitCount+=16; - } - } - while ((bitStream & 3) == 3) - { + } } + while ((bitStream & 3) == 3) { n0+=3; bitStream>>=2; bitCount+=2; @@ -593,8 +575,7 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t bitCount += 2; if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall); while (charnum < n0) normalizedCounter[charnum++] = 0; - if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) - { + if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { ip += bitCount>>3; bitCount &= 7; bitStream = MEM_readLE32(ip) >> bitCount; @@ -606,13 +587,10 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t const short max = (short)((2*threshold-1)-remaining); short count; - if ((bitStream & (threshold-1)) < (U32)max) - { + if ((bitStream & (threshold-1)) < (U32)max) { count = (short)(bitStream & (threshold-1)); bitCount += nbBits-1; - } - else - { + } else { count = (short)(bitStream & (2*threshold-1)); if (count >= threshold) count -= max; bitCount += nbBits; @@ -622,27 +600,20 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t remaining -= FSE_abs(count); normalizedCounter[charnum++] = count; previous0 = !count; - while (remaining < threshold) - { + while (remaining < threshold) { nbBits--; threshold >>= 1; } - { - if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) - { - ip += bitCount>>3; - bitCount &= 7; - } - else - { - bitCount -= (int)(8 * (iend - 4 - ip)); - ip = iend - 4; - } - bitStream = MEM_readLE32(ip) >> (bitCount & 31); + if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) { + ip += bitCount>>3; + bitCount &= 7; + } else { + bitCount -= (int)(8 * (iend - 4 - ip)); + ip = iend - 4; } - } - } + bitStream = MEM_readLE32(ip) >> (bitCount & 31); + } } if (remaining != 1) return ERROR(GENERIC); *maxSVPtr = charnum-1; @@ -723,22 +694,18 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, U32 lowThreshold = (U32)(total >> tableLog); U32 lowOne = (U32)((total * 3) >> (tableLog + 1)); - for (s=0; s<=maxSymbolValue; s++) - { - if (count[s] == 0) - { + for (s=0; s<=maxSymbolValue; s++) { + if (count[s] == 0) { norm[s]=0; continue; } - if (count[s] <= lowThreshold) - { + if (count[s] <= lowThreshold) { norm[s] = -1; distributed++; total -= count[s]; continue; } - if (count[s] <= lowOne) - { + if (count[s] <= lowOne) { norm[s] = 1; distributed++; total -= count[s]; @@ -748,25 +715,20 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, } ToDistribute = (1 << tableLog) - distributed; - if ((total / ToDistribute) > lowOne) - { + if ((total / ToDistribute) > lowOne) { /* risk of rounding to zero */ lowOne = (U32)((total * 3) / (ToDistribute * 2)); - for (s=0; s<=maxSymbolValue; s++) - { - if ((norm[s] == -2) && (count[s] <= lowOne)) - { + for (s=0; s<=maxSymbolValue; s++) { + if ((norm[s] == -2) && (count[s] <= lowOne)) { norm[s] = 1; distributed++; total -= count[s]; continue; - } - } + } } ToDistribute = (1 << tableLog) - distributed; } - if (distributed == maxSymbolValue+1) - { + if (distributed == maxSymbolValue+1) { /* all values are pretty poor; probably incompressible data (should have already been detected); find max, then give all remaining points to max */ @@ -782,10 +744,8 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, U64 const mid = (1ULL << (vStepLog-1)) - 1; U64 const rStep = ((((U64)1<> vStepLog); U32 sEnd = (U32)(end >> vStepLog); @@ -794,9 +754,7 @@ static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, return ERROR(GENERIC); norm[s] = (short)weight; tmpTotal = end; - } - } - } + } } } return 0; } @@ -809,7 +767,7 @@ size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog, /* Sanity checks */ if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG; if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC); /* Unsupported size */ - if (tableLog > FSE_MAX_TABLELOG) return ERROR(GENERIC); /* Unsupported size */ + if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Unsupported size */ if (tableLog < FSE_minTableLog(total, maxSymbolValue)) return ERROR(GENERIC); /* Too small tableLog, compression potentially impossible */ { @@ -823,38 +781,23 @@ size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog, short largestP=0; U32 lowThreshold = (U32)(total >> tableLog); - for (s=0; s<=maxSymbolValue; s++) - { - if (count[s] == total) return 0; - if (count[s] == 0) - { - normalizedCounter[s]=0; - continue; - } - if (count[s] <= lowThreshold) - { + for (s=0; s<=maxSymbolValue; s++) { + if (count[s] == total) return 0; /* rle special case */ + if (count[s] == 0) { normalizedCounter[s]=0; continue; } + if (count[s] <= lowThreshold) { normalizedCounter[s] = -1; stillToDistribute--; - } - else - { + } else { short proba = (short)((count[s]*step) >> scale); - if (proba<8) - { + if (proba<8) { U64 restToBeat = vStep * rtbTable[proba]; proba += (count[s]*step) - ((U64)proba< restToBeat; } - if (proba > largestP) - { - largestP=proba; - largest=s; - } + if (proba > largestP) largestP=proba, largest=s; normalizedCounter[s] = proba; stillToDistribute -= proba; - } - } - if (-stillToDistribute >= (normalizedCounter[largest] >> 1)) - { + } } + if (-stillToDistribute >= (normalizedCounter[largest] >> 1)) { /* corner case, need another normalization method */ size_t errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue); if (FSE_isError(errorCode)) return errorCode; @@ -904,8 +847,7 @@ size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits) tableU16[s] = (U16)(tableSize + s); /* Build Symbol Transformation Table */ - for (s=0; s<=maxSymbolValue; s++) - { + for (s=0; s<=maxSymbolValue; s++) { symbolTT[s].deltaNbBits = nbBits << 16; symbolTT[s].deltaFindState = s-1; } diff --git a/lib/fse.h b/lib/fse.h index dd1190f86..e98f1a54a 100644 --- a/lib/fse.h +++ b/lib/fse.h @@ -46,7 +46,7 @@ extern "C" { #include /* size_t, ptrdiff_t */ -/* ***************************************** +/*-**************************************** * FSE simple functions ******************************************/ size_t FSE_compress(void* dst, size_t maxDstSize, diff --git a/lib/fse_static.h b/lib/fse_static.h index a881e351f..3028a2f40 100644 --- a/lib/fse_static.h +++ b/lib/fse_static.h @@ -223,8 +223,7 @@ static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t /* ***************************************** * Implementation of inlined functions *******************************************/ -typedef struct -{ +typedef struct { int deltaFindState; U32 deltaNbBits; } FSE_symbolCompressionTransform; /* total 8 bytes */ diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 8ebd58beb..2c67c8ae0 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -126,7 +126,10 @@ struct ZSTD_CCtx_s U32* hashTable; U32* contentTable; HUF_CElt* hufTable; - U32 flagHufTable; + U32 flagStaticTables; + FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)]; + FSE_CTable matchlengthCTable [FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)]; + FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)]; }; @@ -158,8 +161,7 @@ void ZSTD_validateParams(ZSTD_parameters* params) if (params->windowLog < ZSTD_WINDOWLOG_MIN) params->windowLog = ZSTD_WINDOWLOG_MIN; /* correct params, to use less memory */ - if ((params->srcSize > 0) && (params->srcSize < (1<srcSize > 0) && (params->srcSize < (1<srcSize)-1) + 1; if (params->windowLog > srcLog) params->windowLog = srcLog; } @@ -188,8 +190,7 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, 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); - if (zc->workSpaceSize < neededSpace) - { + if (zc->workSpaceSize < neededSpace) { free(zc->workSpace); zc->workSpace = malloc(neededSpace); if (zc->workSpace == NULL) return ERROR(memory_allocation); @@ -200,7 +201,7 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, zc->contentTable = zc->hashTable + ((size_t)1 << params.hashLog); zc->seqStore.buffer = zc->contentTable + ((size_t)1 << contentLog); zc->hufTable = (HUF_CElt*)zc->seqStore.buffer; - zc->flagHufTable = 0; + zc->flagStaticTables = 0; zc->seqStore.buffer = (U32*)(zc->seqStore.buffer) + 256; } @@ -253,9 +254,14 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx) dstCCtx->dictLimit = srcCCtx->dictLimit; dstCCtx->lowLimit = srcCCtx->lowLimit; - dstCCtx->flagHufTable = srcCCtx->flagHufTable; - if (dstCCtx->flagHufTable) + /* copy entropy tables */ + dstCCtx->flagStaticTables = srcCCtx->flagStaticTables; + if (dstCCtx->flagStaticTables) { memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4); + memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable)); + memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable)); + memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable)); + } return 0; } @@ -271,8 +277,7 @@ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, U32* table32 = zc->hashTable; U32 index; - for (index=0 ; index < tableSpaceU32 ; index++) - { + for (index=0 ; index < tableSpaceU32 ; index++) { if (table32[index] < reducerValue) table32[index] = 0; else table32[index] -= reducerValue; } @@ -338,15 +343,35 @@ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, 1.2.1) Huff0 block, using sizes from header See Huff0 format - 1.2.2) Raw content + 1.2.2) Huff0 block, using prepared table - 1.2.3) single byte + 1.2.3) Raw content - 1.2.4) _usingDTable variant ? + 1.2.4) single byte 2) Sequences section - TO DO + + - Nb Sequences : 2 bytes, little endian + - Control Token : 1 byte (see below) + - Dumps Length : 1 or 2 bytes (depending on control token) + - Dumps : as stated by dumps length + - Literal Lengths FSE table (as needed depending on encoding method) + - Offset Codes FSE table (as needed depending on encoding method) + - Match Lengths FSE table (as needed depending on encoding method) + + 2.1) Control Token + 8 bits, divided as : + 0-1 : dumpsLength + 2-3 : MatchLength, FSE encoding method + 4-5 : Offset Codes, FSE encoding method + 6-7 : Literal Lengths, FSE encoding method + + FSE encoding method : + FSE_ENCODING_RAW : uncompressed; no header + FSE_ENCODING_RLE : single repeated value; header 1 byte + FSE_ENCODING_STATIC : use prepared table; no header + FSE_ENCODING_DYNAMIC : read NCount */ size_t ZSTD_noCompressBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize) @@ -399,7 +424,7 @@ static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t maxDstSize, const BYTE* const ostart = (BYTE* const)dst; U32 flSize = 1 + (srcSize>31) + (srcSize>4095); - (void)maxDstSize; /* maxDstSize guaranteed to be >=4, hence large enough ? */ + (void)maxDstSize; /* maxDstSize guaranteed to be >=4, hence large enough */ switch(flSize) { @@ -438,14 +463,11 @@ static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc, if (maxDstSize < 4) return ERROR(dstSize_tooSmall); /* not enough space for compression */ - if (zc->flagHufTable && (lhSize==3)) - { + if (zc->flagStaticTables && (lhSize==3)) { hType = IS_PCH; singleStream = 1; clitSize = HUF_compress1X_usingCTable(ostart+lhSize, maxDstSize-lhSize, src, srcSize, zc->hufTable); - } - else - { + } else { clitSize = singleStream ? HUF_compress1X(ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12) : HUF_compress2 (ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12); } @@ -491,11 +513,10 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, U32 count[MaxSeq+1]; S16 norm[MaxSeq+1]; size_t mostFrequent; - U32 max = 255; - U32 tableLog = 11; - U32 CTable_LitLength [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL )]; - U32 CTable_OffsetBits [FSE_CTABLE_SIZE_U32(OffFSELog,MaxOff)]; - U32 CTable_MatchLength[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML )]; + U32 max; + FSE_CTable* CTable_LitLength = zc->litlengthCTable; + FSE_CTable* CTable_OffsetBits = zc->offcodeCTable; + FSE_CTable* CTable_MatchLength = zc->matchlengthCTable; U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */ const BYTE* const op_lit_start = seqStorePtr->litStart; const BYTE* const llTable = seqStorePtr->litLengthStart; @@ -516,7 +537,7 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, { size_t cSize; size_t litSize = seqStorePtr->lit - op_lit_start; - const size_t minLitSize = zc->flagHufTable ? 6 : LITERAL_NOENTROPY; + const size_t minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY; if (litSize <= minLitSize) cSize = ZSTD_noCompressLiterals(op, maxDstSize, op_lit_start, litSize); @@ -535,14 +556,11 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, /* dumps : contains too large lengths */ { size_t dumpsLength = seqStorePtr->dumps - seqStorePtr->dumpsStart; - if (dumpsLength < 512) - { + if (dumpsLength < 512) { op[0] = (BYTE)(dumpsLength >> 8); op[1] = (BYTE)(dumpsLength); op += 2; - } - else - { + } else { op[0] = 2; op[1] = (BYTE)(dumpsLength>>8); op[2] = (BYTE)(dumpsLength); @@ -553,94 +571,86 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, op += dumpsLength; } +#define MIN_SEQ_FOR_DYNAMIC_FSE 64 +#define MAX_SEQ_FOR_STATIC_FSE 1000 + /* CTable for Literal Lengths */ max = MaxLL; mostFrequent = FSE_countFast(count, &max, seqStorePtr->litLengthStart, nbSeq); - if ((mostFrequent == nbSeq) && (nbSeq > 2)) - { + if ((mostFrequent == nbSeq) && (nbSeq > 2)) { *op++ = *(seqStorePtr->litLengthStart); FSE_buildCTable_rle(CTable_LitLength, (BYTE)max); - LLtype = bt_rle; - } - else if ((nbSeq < 64) || (mostFrequent < (nbSeq >> (LLbits-1)))) - { + LLtype = FSE_ENCODING_RLE; + } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) { + LLtype = FSE_ENCODING_STATIC; + } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LLbits-1)))) { FSE_buildCTable_raw(CTable_LitLength, LLbits); - LLtype = bt_raw; - } - else - { + LLtype = FSE_ENCODING_RAW; + } else { size_t NCountSize; - tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max); + U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max); FSE_normalizeCount(norm, tableLog, count, nbSeq, max); NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */ if (FSE_isError(NCountSize)) return ERROR(GENERIC); op += NCountSize; FSE_buildCTable(CTable_LitLength, norm, max, tableLog); - LLtype = bt_compressed; + LLtype = FSE_ENCODING_DYNAMIC; } - /* CTable for Offsets codes */ - { - /* create Offset codes */ - size_t i; - max = MaxOff; - for (i=0; i 2)) - { + max = MaxOff; + mostFrequent = FSE_countFast(count, &max, offCodeTable, nbSeq); + if ((mostFrequent == nbSeq) && (nbSeq > 2)) { *op++ = *offCodeTable; FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max); - Offtype = bt_rle; - } - else if ((nbSeq < 64) || (mostFrequent < (nbSeq >> (Offbits-1)))) - { + Offtype = FSE_ENCODING_RLE; + } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) { + Offtype = FSE_ENCODING_STATIC; + } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (Offbits-1)))) { FSE_buildCTable_raw(CTable_OffsetBits, Offbits); - Offtype = bt_raw; - } - else - { + Offtype = FSE_ENCODING_RAW; + } else { size_t NCountSize; - tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max); + U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max); FSE_normalizeCount(norm, tableLog, count, nbSeq, max); NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */ if (FSE_isError(NCountSize)) return ERROR(GENERIC); op += NCountSize; FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog); - Offtype = bt_compressed; + Offtype = FSE_ENCODING_DYNAMIC; } /* CTable for MatchLengths */ max = MaxML; mostFrequent = FSE_countFast(count, &max, seqStorePtr->matchLengthStart, nbSeq); - if ((mostFrequent == nbSeq) && (nbSeq > 2)) - { + if ((mostFrequent == nbSeq) && (nbSeq > 2)) { *op++ = *seqStorePtr->matchLengthStart; FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max); - MLtype = bt_rle; - } - else if ((nbSeq < 64) || (mostFrequent < (nbSeq >> (MLbits-1)))) - { + MLtype = FSE_ENCODING_RLE; + } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) { + MLtype = FSE_ENCODING_STATIC; + } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (MLbits-1)))) { FSE_buildCTable_raw(CTable_MatchLength, MLbits); - MLtype = bt_raw; - } - else - { + MLtype = FSE_ENCODING_RAW; + } else { size_t NCountSize; - tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max); + U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max); FSE_normalizeCount(norm, tableLog, count, nbSeq, max); NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */ if (FSE_isError(NCountSize)) return ERROR(GENERIC); op += NCountSize; FSE_buildCTable(CTable_MatchLength, norm, max, tableLog); - MLtype = bt_compressed; + MLtype = FSE_ENCODING_DYNAMIC; } seqHead[0] += (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); + zc->flagStaticTables = 0; /* Encoding Sequences */ { @@ -657,14 +667,13 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, FSE_initCState(&stateOffsetBits, CTable_OffsetBits); FSE_initCState(&stateLitLength, CTable_LitLength); - for (i=(int)nbSeq-1; i>=0; i--) - { - BYTE matchLength = mlTable[i]; + for (i=(int)nbSeq-1; i>=0; i--) { + BYTE mlCode = mlTable[i]; U32 offset = offsetTable[i]; BYTE offCode = offCodeTable[i]; /* 32b*/ /* 64b*/ U32 nbBits = (offCode-1) * (!!offCode); BYTE litLength = llTable[i]; /* (7)*/ /* (7)*/ - FSE_encodeSymbol(&blockStream, &stateMatchLength, matchLength); /* 17 */ /* 17 */ + FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 17 */ /* 17 */ if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */ BIT_addBits(&blockStream, offset, nbBits); /* 31 */ /* 42 */ /* 24 bits max in 32-bits mode */ if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */ @@ -699,7 +708,7 @@ MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const B #if 0 static const BYTE* g_start = NULL; if (g_start==NULL) g_start = literals; - if (literals - g_start == 8695) + //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 @@ -709,34 +718,28 @@ MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const B seqStorePtr->lit += litLength; /* literal Length */ - if (litLength >= MaxLL) - { + if (litLength >= MaxLL) { *(seqStorePtr->litLength++) = MaxLL; - if (litLength<255 + MaxLL) + if (litLength<255 + MaxLL) { *(seqStorePtr->dumps++) = (BYTE)(litLength - MaxLL); - else - { + } 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) - { + if (matchCode >= MaxML) { *(seqStorePtr->matchLength++) = MaxML; - if (matchCode < 255+MaxML) + if (matchCode < 255+MaxML) { *(seqStorePtr->dumps++) = (BYTE)(matchCode - MaxML); - else - { + } else { *(seqStorePtr->dumps++) = 255; MEM_writeLE32(seqStorePtr->dumps, (U32)matchCode); seqStorePtr->dumps += 3; - } - } + } } else *(seqStorePtr->matchLength++) = (BYTE)matchCode; } @@ -841,8 +844,7 @@ static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLim { const BYTE* const pStart = pIn; - while ((pInnextToUpdate; const BYTE* const iend = (const BYTE*) end; - while(ip <= iend) - { + while(ip <= iend) { hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base); ip += FILLHASHSTEP; } @@ -947,8 +948,7 @@ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc, /* init */ ZSTD_resetSeqStore(seqStorePtr); - if (ip < lowest+4) - { + if (ip < lowest+4) { hashTable[ZSTD_hashPtr(lowest+1, hBits, mls)] = lowIndex+1; hashTable[ZSTD_hashPtr(lowest+2, hBits, mls)] = lowIndex+2; hashTable[ZSTD_hashPtr(lowest+3, hBits, mls)] = lowIndex+3; @@ -956,8 +956,7 @@ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc, } /* Main Search Loop */ - while (ip < ilimit) /* < instead of <=, because repcode check at (ip+1) */ - { + while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */ size_t mlCode; size_t offset; const size_t h = ZSTD_hashPtr(ip, hBits, mls); @@ -966,17 +965,13 @@ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc, const U32 current = (U32)(ip-base); hashTable[h] = current; /* update hash table */ - if (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)) /* note : by construction, offset_1 <= current */ - { + if (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)) { /* note : by construction, offset_1 <= current */ mlCode = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend); ip++; offset = 0; - } - else - { + } else { if ( (matchIndex <= lowIndex) || - (MEM_read32(match) != MEM_read32(ip)) ) - { + (MEM_read32(match) != MEM_read32(ip)) ) { ip += ((ip-anchor) >> g_searchStrength) + 1; continue; } @@ -992,15 +987,13 @@ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc, ip += mlCode + MINMATCH; anchor = ip; - if (ip <= ilimit) - { + if (ip <= ilimit) { /* Fill Table */ hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2; /* here because current+2 could be > iend-8 */ hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base); /* check immediate repcode */ while ( (ip <= ilimit) - && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) - { + && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) { /* store sequence */ size_t rlCode = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend); size_t tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */ @@ -1009,9 +1002,7 @@ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc, ip += rlCode+MINMATCH; anchor = ip; continue; /* faster when present ... (?) */ - } - } - } + } } } /* Last Literals */ { @@ -1067,18 +1058,15 @@ void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, /* init */ ZSTD_resetSeqStore(seqStorePtr); - { - /* skip first 4 positions to avoid read overflow during repcode match check */ - hashTable[ZSTD_hashPtr(ip+0, hBits, mls)] = (U32)(ip-base+0); - hashTable[ZSTD_hashPtr(ip+1, hBits, mls)] = (U32)(ip-base+1); - hashTable[ZSTD_hashPtr(ip+2, hBits, mls)] = (U32)(ip-base+2); - hashTable[ZSTD_hashPtr(ip+3, hBits, mls)] = (U32)(ip-base+3); - ip += 4; - } + /* skip first 4 positions to avoid read overflow during repcode match check */ + hashTable[ZSTD_hashPtr(ip+0, hBits, mls)] = (U32)(ip-base+0); + hashTable[ZSTD_hashPtr(ip+1, hBits, mls)] = (U32)(ip-base+1); + hashTable[ZSTD_hashPtr(ip+2, hBits, mls)] = (U32)(ip-base+2); + hashTable[ZSTD_hashPtr(ip+3, hBits, mls)] = (U32)(ip-base+3); + ip += 4; /* Main Search Loop */ - while (ip < ilimit) /* < instead of <=, because (ip+1) */ - { + while (ip < ilimit) { /* < instead of <=, because (ip+1) */ const size_t h = ZSTD_hashPtr(ip, hBits, mls); const U32 matchIndex = hashTable[h]; const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base; @@ -1092,15 +1080,12 @@ void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, hashTable[h] = current; /* update hash table */ if ( ((repIndex <= dictLimit-4) || (repIndex >= dictLimit)) - && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) - { + && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend; mlCode = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repMatchEnd, lowPrefixPtr); ip++; offset = 0; - } - else - { + } else { if ( (matchIndex < lowLimit) || (MEM_read32(match) != MEM_read32(ip)) ) { ip += ((ip-anchor) >> g_searchStrength) + 1; continue; } @@ -1108,32 +1093,28 @@ void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend; const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr; mlCode = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iend, matchEnd, lowPrefixPtr); - while ((ip>anchor) && (match>lowMatchPtr) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */ + while ((ip>anchor) && (match>lowMatchPtr) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */ offset = current - matchIndex; offset_2 = offset_1; offset_1 = offset; - } - } + } } /* found a match : store it */ ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset, mlCode); ip += mlCode + MINMATCH; anchor = ip; - if (ip <= ilimit) - { + if (ip <= ilimit) { /* Fill Table */ hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2; hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base); /* check immediate repcode */ - while (ip <= ilimit) - { + while (ip <= ilimit) { U32 current2 = (U32)(ip-base); const U32 repIndex2 = current2 - offset_2; const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2; if ( ((repIndex2 <= dictLimit-4) || (repIndex2 >= dictLimit)) - && (MEM_read32(repMatch2) == MEM_read32(ip)) ) - { + && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend; size_t repLength2 = ZSTD_count_2segments(ip+MINMATCH, repMatch2+MINMATCH, iend, repEnd2, lowPrefixPtr); U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ @@ -1144,9 +1125,7 @@ void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, continue; } break; - } - } - } + } } } /* Last Literals */ { @@ -1213,14 +1192,13 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co hashTable[h] = current; /* Update Hash Table */ - while (nbCompares-- && (matchIndex > windowLow)) - { + 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 */ - if (matchIndex == predictedSmall) - { /* no need to check length, result known */ + if (matchIndex == predictedSmall) { + /* no need to check length, result known */ *smallerPtr = matchIndex; if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */ smallerPtr = nextPtr+1; /* new "smaller" => larger of match */ @@ -1229,8 +1207,7 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co continue; } - if (matchIndex == predictedLarge) - { + if (matchIndex == predictedLarge) { *largerPtr = matchIndex; if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */ largerPtr = nextPtr; @@ -1239,14 +1216,11 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co continue; } - if ((!extDict) || (matchIndex+matchLength >= dictLimit)) - { + 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 - { + } else { match = dictBase + matchIndex; matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart); if (matchIndex+matchLength >= dictLimit) @@ -1259,25 +1233,21 @@ static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, co 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 */ - if (match[matchLength] < ip[matchLength]) /* necessarily within correct buffer */ - { + if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */ /* 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 - { + } 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; return (matchEndIdx > current + 8) ? matchEndIdx - current - 8 : 1; @@ -1326,28 +1296,23 @@ size_t ZSTD_insertBtAndFindBestMatch ( hashTable[h] = current; /* Update Hash Table */ - while (nbCompares-- && (matchIndex > windowLow)) - { + 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)) - { + 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 - { + } 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 > bestLength) { if (matchLength > matchEndIdx - matchIndex) matchEndIdx = matchIndex + (U32)matchLength; if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) ) @@ -1356,17 +1321,14 @@ size_t ZSTD_insertBtAndFindBestMatch ( break; /* drop, to guarantee consistency (miss a little bit of compression) */ } - if (match[matchLength] < ip[matchLength]) - { + 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 - { + } else { /* match is larger than current */ *largerPtr = matchIndex; commonLengthLarger = matchLength; @@ -1472,8 +1434,7 @@ static U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls) const U32 target = (U32)(ip - base); U32 idx = zc->nextToUpdate; - while(idx < target) - { + while(idx < target) { size_t h = ZSTD_hashPtr(base+idx, hashLog, mls); NEXT_IN_CHAIN(idx, chainMask) = hashTable[h]; hashTable[h] = idx; @@ -1511,18 +1472,14 @@ size_t ZSTD_HcFindBestMatch_generic ( /* HC4 match finder */ matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls); - while ((matchIndex>lowLimit) && (nbAttempts)) - { + while ((matchIndex>lowLimit) && (nbAttempts)) { size_t currentMl=0; nbAttempts--; - if ((!extDict) || matchIndex >= dictLimit) - { + if ((!extDict) || matchIndex >= dictLimit) { match = base + matchIndex; if (match[ml] == ip[ml]) /* potentially better */ currentMl = ZSTD_count(ip, match, iLimit); - } - else - { + } 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; @@ -1601,15 +1558,13 @@ void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx, if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE; /* Match Loop */ - while (ip < ilimit) - { + while (ip < ilimit) { size_t matchLength=0; size_t offset=0; const BYTE* start=ip+1; /* check repCode */ - if (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1)) - { + if (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1)) { /* repcode : we take it */ matchLength = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend) + MINMATCH; if (depth==0) goto _storeSequence; @@ -1623,19 +1578,16 @@ void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx, matchLength = ml2, start = ip, offset=offsetFound; } - if (matchLength < MINMATCH) - { + if (matchLength < 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)) - { + if ((ml2 >= MINMATCH) && (gain2 > gain1)) { matchLength = ml2, offset = offset2, start = ip; continue; /* search a better one */ - } - } + } } /* let's find an even better one */ - if ((depth==2) && (ip= MINMATCH) && (gain2 > gain1)) - { + if ((ml2 >= MINMATCH) && (gain2 > gain1)) { matchLength = ml2, offset = offset2, start = ip; continue; - } - } - } + } } } break; /* nothing found : store previous solution */ } /* catch up */ - if (offset) - { + 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; @@ -1699,8 +1643,7 @@ _storeSequence: /* check immediate repcode */ while ( (ip <= ilimit) - && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) - { + && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) { /* store sequence */ matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend); offset = offset_2; @@ -1710,8 +1653,7 @@ _storeSequence: ip += matchLength+MINMATCH; anchor = ip; continue; /* faster when present ... (?) */ - } - } + } } /* Last Literals */ { @@ -1774,8 +1716,7 @@ void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE; /* Match Loop */ - while (ip < ilimit) - { + while (ip < ilimit) { size_t matchLength=0; size_t offset=0; const BYTE* start=ip+1; @@ -1787,14 +1728,12 @@ void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, 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 (MEM_read32(ip+1) == MEM_read32(repMatch)) { /* repcode detected we should take it */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; matchLength = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; if (depth==0) goto _storeSequence; - } - } + } } { /* first search (depth 0) */ @@ -1804,27 +1743,23 @@ void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, matchLength = ml2, start = ip, offset=offsetFound; } - if (matchLength < MINMATCH) - { + if (matchLength < 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= 3) /* intentional overflow */ - if (MEM_read32(ip) == MEM_read32(repMatch)) - { + if (MEM_read32(ip) == MEM_read32(repMatch)) { /* repcode detected */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; @@ -1832,8 +1767,7 @@ void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1); if ((repLength >= MINMATCH) && (gain2 > gain1)) matchLength = repLength, offset = 0, start = ip; - } - } + } } /* search match, depth 1 */ { @@ -1841,27 +1775,22 @@ void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, 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)) - { + if ((ml2 >= MINMATCH) && (gain2 > gain1)) { matchLength = ml2, offset = offset2, start = ip; continue; /* search a better one */ - } - } + } } /* let's find an even better one */ - if ((depth==2) && (ip= 3) /* intentional overflow */ - if (MEM_read32(ip) == MEM_read32(repMatch)) - { + if (MEM_read32(ip) == MEM_read32(repMatch)) { /* repcode detected */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; @@ -1869,8 +1798,7 @@ void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1); if ((repLength >= MINMATCH) && (gain2 > gain1)) matchLength = repLength, offset = 0, start = ip; - } - } + } } /* search match, depth 2 */ { @@ -1878,19 +1806,15 @@ void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, 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) + 7); - if ((ml2 >= MINMATCH) && (gain2 > gain1)) - { + if ((ml2 >= MINMATCH) && (gain2 > gain1)) { matchLength = ml2, offset = offset2, start = ip; continue; - } - } - } + } } } break; /* nothing found : store previous solution */ } /* catch up */ - if (offset) - { + if (offset) { U32 matchIndex = (U32)((start-base) - offset); const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex; const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart; @@ -1907,14 +1831,12 @@ _storeSequence: } /* check immediate repcode */ - while (ip <= ilimit) - { + while (ip <= ilimit) { const U32 repIndex = (U32)((ip-base) - offset_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(ip) == MEM_read32(repMatch)) - { + if (MEM_read32(ip) == MEM_read32(repMatch)) { /* repcode detected we should take it */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; matchLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; @@ -1925,8 +1847,7 @@ _storeSequence: continue; /* faster when present ... (?) */ } break; - } - } + } } /* Last Literals */ { @@ -2161,12 +2082,43 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t dictSize) { /* note : magic number already checked */ + size_t offcodeHeaderSize, matchlengthHeaderSize, litlengthHeaderSize, errorCode; + short offcodeNCount[MaxOff+1]; + unsigned offcodeMaxValue = MaxOff, offcodeLog = OffFSELog; + short matchlengthNCount[MaxML+1]; + unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog; + short litlengthNCount[MaxLL+1]; + unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog; + const size_t hufHeaderSize = HUF_readCTable(zc->hufTable, 255, dict, dictSize); if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted); - zc->flagHufTable = 1; - return hufHeaderSize; + zc->flagStaticTables = 1; + dict = (const char*)dict + hufHeaderSize; + dictSize -= hufHeaderSize; + + offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize); + if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted); + errorCode = FSE_buildCTable(zc->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog); + if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); + dict = (const char*)dict + offcodeHeaderSize; + dictSize -= offcodeHeaderSize; + + matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize); + if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted); + errorCode = FSE_buildCTable(zc->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog); + if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); + dict = (const char*)dict + matchlengthHeaderSize; + dictSize -= matchlengthHeaderSize; + + litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize); + if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted); + errorCode = FSE_buildCTable(zc->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog); + if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); + + return hufHeaderSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize; } + static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize) { if (dict && dictSize) @@ -2240,8 +2192,7 @@ size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t maxDstSize) size_t hbSize = 0; /* empty frame */ - if (zc->stage==0) - { + if (zc->stage==0) { hbSize = zc->hbSize; if (maxDstSize <= hbSize) return ERROR(dstSize_tooSmall); zc->stage = 1; diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 93e82884c..b50e474fb 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -51,7 +51,7 @@ #endif -/* ******************************************************* +/*-******************************************************* * Includes *********************************************************/ #include /* calloc */ @@ -67,7 +67,8 @@ # include "zstd_legacy.h" #endif -/* ******************************************************* + +/*-******************************************************* * Compiler specifics *********************************************************/ #ifdef _MSC_VER /* Visual Studio */ @@ -85,7 +86,7 @@ #endif -/* ************************************* +/*-************************************* * Local types ***************************************/ typedef struct @@ -123,10 +124,10 @@ typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader, struct ZSTD_DCtx_s { - U32 LLTable[FSE_DTABLE_SIZE_U32(LLFSELog)]; - U32 OffTable[FSE_DTABLE_SIZE_U32(OffFSELog)]; - U32 MLTable[FSE_DTABLE_SIZE_U32(MLFSELog)]; - U32 hufTableX4[HUF_DTABLE_SIZE(HufLog)]; + FSE_DTable LLTable[FSE_DTABLE_SIZE_U32(LLFSELog)]; + FSE_DTable OffTable[FSE_DTABLE_SIZE_U32(OffFSELog)]; + FSE_DTable MLTable[FSE_DTABLE_SIZE_U32(MLFSELog)]; + unsigned hufTableX4[HUF_DTABLE_SIZE(HufLog)]; const void* previousDstEnd; const void* base; const void* vBase; @@ -134,9 +135,9 @@ struct ZSTD_DCtx_s size_t expected; size_t headerSize; ZSTD_parameters params; - blockType_t bType; + blockType_t bType; /* used in ZSTD_decompressContinue(), to transfer blockType between header decoding and block decoding stages */ ZSTD_dStage stage; - U32 flagHufTable; + U32 flagStaticTables; const BYTE* litPtr; size_t litBufSize; size_t litSize; @@ -144,6 +145,8 @@ struct ZSTD_DCtx_s BYTE headerBuffer[ZSTD_frameHeaderSize_max]; }; /* typedef'd to ZSTD_DCtx within "zstd_static.h" */ +size_t sizeofDCtx (void) { return sizeof(ZSTD_DCtx); } + size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) { dctx->expected = ZSTD_frameHeaderSize_min; @@ -153,7 +156,7 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) dctx->vBase = NULL; dctx->dictEnd = NULL; dctx->hufTableX4[0] = HufLog; - dctx->flagHufTable = 0; + dctx->flagStaticTables = 0; return 0; } @@ -197,27 +200,66 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) */ /* Block format description - Literal Section - Sequences Section + + Block = Literal Section - Sequences Section + Prerequisite : size of (compressed) block, maximum size of regenerated data + 1) Literal Section - 1.1) Header : up to 5 bytes - flags: + + 1.1) Header : 1-5 bytes + flags: 2 bits 00 compressed by Huff0 - 01 is Raw (uncompressed) - 10 is Rle - 11 unused - Note : using 11 for Huff0 with precomputed table ? + 01 unused + 10 is Raw (uncompressed) + 11 is Rle + Note : using 01 => Huff0 with precomputed table ? Note : delta map ? => compressed ? - Note 2 : 19 bits for sizes, seems a bit larger than necessary - Note 3 : RLE blocks ? + + 1.1.1) Huff0-compressed literal block : 3-5 bytes + srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream + srcSize < 1 KB => 3 bytes (2-2-10-10) + srcSize < 16KB => 4 bytes (2-2-14-14) + else => 5 bytes (2-2-18-18) + big endian convention + + 1.1.2) Raw (uncompressed) literal block header : 1-3 bytes + size : 5 bits: (IS_RAW<<6) + (0<<4) + size + 12 bits: (IS_RAW<<6) + (2<<4) + (size>>8) + size&255 + 20 bits: (IS_RAW<<6) + (3<<4) + (size>>16) + size>>8&255 + size&255 + + 1.1.3) Rle (repeated single byte) literal block header : 1-3 bytes + size : 5 bits: (IS_RLE<<6) + (0<<4) + size + 12 bits: (IS_RLE<<6) + (2<<4) + (size>>8) + size&255 + 20 bits: (IS_RLE<<6) + (3<<4) + (size>>16) + size>>8&255 + size&255 + + 1.1.4) Huff0-compressed literal block, using precomputed CTables : 3-5 bytes + srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream + srcSize < 1 KB => 3 bytes (2-2-10-10) + srcSize < 16KB => 4 bytes (2-2-14-14) + else => 5 bytes (2-2-18-18) + big endian convention + + 1- CTable available (stored into workspace ?) + 2- Small input (fast heuristic ? Full comparison ? depend on clevel ?) + + + 1.2) Literal block content 1.2.1) Huff0 block, using sizes from header See Huff0 format - 1.2.2) Huff0 block, using precomputed DTable - _usingDTable variants + 1.2.2) Huff0 block, using prepared table + + 1.2.3) Raw content + + 1.2.4) single byte - 1.2.3) uncompressed blocks - as the name says (both 2 or 3 bytes variants) 2) Sequences section TO DO @@ -331,7 +373,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, litCSize = ((istart[2] & 3) << 16) + (istart[3] << 8) + istart[4]; break; } - if (litSize > BLOCKSIZE) return ERROR(corruption_detected);; + if (litSize > BLOCKSIZE) return ERROR(corruption_detected); if (HUF_isError(singleStream ? HUF_decompress1X2(dctx->litBuffer, litSize, istart+lhSize, litCSize) : @@ -350,7 +392,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, U32 lhSize = ((istart[0]) >> 4) & 3; if (lhSize != 1) /* only case supported for now : small litSize, single stream */ return ERROR(corruption_detected); - if (!dctx->flagHufTable) + if (!dctx->flagStaticTables) return ERROR(dictionary_corrupted); /* 2 - 2 - 10 - 10 */ @@ -448,14 +490,11 @@ size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLen LLtype = *ip >> 6; Offtype = (*ip >> 4) & 3; MLtype = (*ip >> 2) & 3; - if (*ip & 2) - { + if (*ip & 2) { dumpsLength = ip[2]; dumpsLength += ip[1] << 8; ip += 3; - } - else - { + } else { dumpsLength = ip[1]; dumpsLength += (ip[0] & 1) << 8; ip += 2; @@ -476,13 +515,18 @@ size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLen switch(LLtype) { U32 max; - case bt_rle : + case FSE_ENCODING_RLE : LLlog = 0; - FSE_buildDTable_rle(DTableLL, *ip++); break; - case bt_raw : + FSE_buildDTable_rle(DTableLL, *ip++); + break; + case FSE_ENCODING_RAW : LLlog = LLbits; - FSE_buildDTable_raw(DTableLL, LLbits); break; - default : + FSE_buildDTable_raw(DTableLL, LLbits); + break; + case FSE_ENCODING_STATIC: + break; + case FSE_ENCODING_DYNAMIC : + default : /* impossible */ max = MaxLL; headerSize = FSE_readNCount(norm, &max, &LLlog, ip, iend-ip); if (FSE_isError(headerSize)) return ERROR(GENERIC); @@ -494,15 +538,19 @@ size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLen switch(Offtype) { U32 max; - case bt_rle : + case FSE_ENCODING_RLE : Offlog = 0; if (ip > iend-2) return ERROR(srcSize_wrong); /* min : "raw", hence no header, but at least xxLog bits */ FSE_buildDTable_rle(DTableOffb, *ip++ & MaxOff); /* if *ip > MaxOff, data is corrupted */ break; - case bt_raw : + case FSE_ENCODING_RAW : Offlog = Offbits; - FSE_buildDTable_raw(DTableOffb, Offbits); break; - default : + FSE_buildDTable_raw(DTableOffb, Offbits); + break; + case FSE_ENCODING_STATIC: + break; + case FSE_ENCODING_DYNAMIC : + default : /* impossible */ max = MaxOff; headerSize = FSE_readNCount(norm, &max, &Offlog, ip, iend-ip); if (FSE_isError(headerSize)) return ERROR(GENERIC); @@ -514,22 +562,26 @@ size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLen switch(MLtype) { U32 max; - case bt_rle : + case FSE_ENCODING_RLE : MLlog = 0; if (ip > iend-2) return ERROR(srcSize_wrong); /* min : "raw", hence no header, but at least xxLog bits */ - FSE_buildDTable_rle(DTableML, *ip++); break; - case bt_raw : + FSE_buildDTable_rle(DTableML, *ip++); + break; + case FSE_ENCODING_RAW : MLlog = MLbits; - FSE_buildDTable_raw(DTableML, MLbits); break; - default : + FSE_buildDTable_raw(DTableML, MLbits); + break; + case FSE_ENCODING_STATIC: + break; + case FSE_ENCODING_DYNAMIC : + default : /* impossible */ max = MaxML; headerSize = FSE_readNCount(norm, &max, &MLlog, ip, iend-ip); if (FSE_isError(headerSize)) return ERROR(GENERIC); if (MLlog > MLFSELog) return ERROR(corruption_detected); ip += headerSize; FSE_buildDTable(DTableML, norm, max, MLlog); - } - } + } } return ip-istart; } @@ -564,12 +616,10 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) /* Literal length */ litLength = FSE_decodeSymbol(&(seqState->stateLL), &(seqState->DStream)); prevOffset = litLength ? seq->offset : seqState->prevOffset; - if (litLength == MaxLL) - { + if (litLength == MaxLL) { U32 add = *dumps++; if (add < 255) litLength += add; - else - { + else { litLength = MEM_readLE32(dumps) & 0xFFFFFF; /* no pb : dumps is always followed by seq tables > 1 byte */ dumps += 3; } @@ -595,12 +645,10 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) /* MatchLength */ matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); - if (matchLength == MaxML) - { + if (matchLength == MaxML) { U32 add = *dumps++; if (add < 255) matchLength += add; - else - { + else { matchLength = MEM_readLE32(dumps) & 0xFFFFFF; /* no pb : dumps is always followed by seq tables > 1 byte */ dumps += 3; } @@ -613,6 +661,15 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) seq->offset = offset; seq->matchLength = matchLength; seqState->dumps = dumps; + +#if 0 + { + static U64 totalDecoded = 0; + printf("pos %6u : %3u literals & match %3u bytes at distance %6u \n", + (U32)(totalDecoded), (U32)litLength, (U32)matchLength, (U32)offset); + totalDecoded += litLength + matchLength; + } +#endif } @@ -657,8 +714,7 @@ FORCE_INLINE size_t ZSTD_execSequence(BYTE* op, op = oLitEnd + length1; sequence.matchLength -= length1; match = base; - } - } + } } /* match within prefix */ if (sequence.offset < 8) { @@ -671,8 +727,7 @@ FORCE_INLINE size_t ZSTD_execSequence(BYTE* op, match += dec32table[sequence.offset]; ZSTD_copy4(op+4, match); match -= sub2; - } - else { + } else { ZSTD_copy8(op, match); } op += 8; match += 8; @@ -683,9 +738,9 @@ FORCE_INLINE size_t ZSTD_execSequence(BYTE* op, match += oend_8 - op; op = oend_8; } - while (op < oMatchEnd) *op++ = *match++; - } - else { + while (op < oMatchEnd) + *op++ = *match++; + } else { ZSTD_wildcopy(op, match, sequence.matchLength-8); /* works even if matchLength < 8 */ } return sequenceLength; @@ -718,7 +773,7 @@ static size_t ZSTD_decompressSequences( /* Build Decoding Tables */ errorCode = ZSTD_decodeSeqHeaders(&nbSeq, &dumps, &dumpsLength, DTableLL, DTableML, DTableOffb, - ip, iend-ip); + ip, seqSize); if (ZSTD_isError(errorCode)) return errorCode; ip += errorCode; @@ -757,8 +812,7 @@ static size_t ZSTD_decompressSequences( if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); if (op != litPtr) memcpy(op, litPtr, lastLLSize); op += lastLLSize; - } - } + } } return op-ostart; } @@ -1018,10 +1072,40 @@ static void ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dictSi static size_t ZSTD_loadEntropy(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) { - size_t hSize = HUF_readDTableX4(dctx->hufTableX4, dict, dictSize); + size_t hSize, offcodeHeaderSize, matchlengthHeaderSize, errorCode, litlengthHeaderSize; + short offcodeNCount[MaxOff+1]; + U32 offcodeMaxValue=MaxOff, offcodeLog=OffFSELog; + short matchlengthNCount[MaxML+1]; + unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog; + short litlengthNCount[MaxLL+1]; + unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog; + + hSize = HUF_readDTableX4(dctx->hufTableX4, dict, dictSize); if (HUF_isError(hSize)) return ERROR(dictionary_corrupted); - dctx->flagHufTable = 1; - return hSize; + dict = (const char*)dict + hSize; + dictSize -= hSize; + + offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize); + if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted); + errorCode = FSE_buildDTable(dctx->OffTable, offcodeNCount, offcodeMaxValue, offcodeLog); + if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); + dict = (const char*)dict + offcodeHeaderSize; + dictSize -= offcodeHeaderSize; + + matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize); + if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted); + errorCode = FSE_buildDTable(dctx->MLTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog); + if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); + dict = (const char*)dict + matchlengthHeaderSize; + dictSize -= matchlengthHeaderSize; + + litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize); + if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted); + errorCode = FSE_buildDTable(dctx->LLTable, litlengthNCount, litlengthMaxValue, litlengthLog); + if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); + + dctx->flagStaticTables = 1; + return hSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize; } static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize) diff --git a/lib/zstd_internal.h b/lib/zstd_internal.h index 38bda786e..7eda81366 100644 --- a/lib/zstd_internal.h +++ b/lib/zstd_internal.h @@ -94,6 +94,12 @@ static const size_t ZSTD_frameHeaderSize_min = 5; #define OffFSELog 9 #define MaxSeq MAX(MaxLL, MaxML) +#define FSE_ENCODING_RAW 0 +#define FSE_ENCODING_RLE 1 +#define FSE_ENCODING_STATIC 2 +#define FSE_ENCODING_DYNAMIC 3 + + #define HufLog 12 #define MIN_SEQUENCES_SIZE (2 /*seqNb*/ + 2 /*dumps*/ + 3 /*seqTables*/ + 1 /*bitStream*/) @@ -104,9 +110,9 @@ static const size_t ZSTD_frameHeaderSize_min = 5; typedef enum { bt_compressed, bt_raw, bt_rle, bt_end } blockType_t; -/* ****************************************** +/*-******************************************* * Shared functions to include for inlining -********************************************/ +*********************************************/ static void ZSTD_copy8(void* dst, const void* src) { memcpy(dst, src, 8); } #define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; } diff --git a/programs/bench.c b/programs/bench.c index 1f35301f0..efb9d69f4 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -293,11 +293,10 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, milliTime = BMK_GetMilliStart(); while (BMK_GetMilliStart() == milliTime); milliTime = BMK_GetMilliStart(); - while (BMK_GetMilliSpan(milliTime) < TIMELOOP) - { + while (BMK_GetMilliSpan(milliTime) < TIMELOOP) { ZSTD_compressBegin_advanced(refCtx, dictBuffer, dictBufferSize, ZSTD_getParams(cLevel, dictBufferSize+largestBlockSize)); - for (blockNb=0; blockNb %6u bytes (%08X) \n", + blockNb, (U32)blockTable[blockNb].srcSize, (U32)blockTable[blockNb].cSize, XXH32(blockTable[blockNb].cPtr, blockTable[blockNb].cSize, 0)); } nbLoops++; } @@ -340,7 +343,8 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, blockTable[blockNb].cPtr, blockTable[blockNb].cSize); if (ZSTD_isError(regenSize)) - EXM_THROW(3, "ZSTD_decompress_usingDict() failed : %s", ZSTD_getErrorName(regenSize)); + EXM_THROW(3, "ZSTD_decompress_usingPreparedDCtx() failed on block %u : %s", + blockNb, ZSTD_getErrorName(regenSize)); blockTable[blockNb].resSize = regenSize; } } @@ -364,8 +368,11 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, } pos = (U32)(u - bacc); bNb = pos / (128 KB); - printf("(segment %u, block %u, pos %u) \n", segNb, bNb, pos); + printf("(block %u, sub %u, pos %u) \n", segNb, bNb, pos); break; + } + if (u==srcSize-1) { /* should never happen */ + printf("no difference detected\n"); } } break; } @@ -375,7 +382,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, if (crcOrig == crcCheck) DISPLAY("%2i-%-17.17s :%10i ->%10i (%5.3f),%6.1f MB/s ,%6.1f MB/s \n", cLevel, displayName, (int)srcSize, (int)cSize, ratio, (double)srcSize / fastestC / 1000., (double)srcSize / fastestD / 1000.); else - DISPLAY("\n"); + DISPLAY("%2i-\n", cLevel); } /* clean up */ From e618f8e2210828279536c5af8cd43ec37ddd47b9 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Jan 2016 00:29:58 +0100 Subject: [PATCH 10/34] added dictionary builder utility --- NEWS | 1 + dictBuilder/COPYING | 339 +++++++++++ dictBuilder/Makefile | 67 +++ dictBuilder/config.h | 83 +++ dictBuilder/dibcli.c | 256 +++++++++ dictBuilder/dictBuilder.c | 946 +++++++++++++++++++++++++++++++ dictBuilder/dictBuilder.h | 44 ++ dictBuilder/divsufsort.c | 398 +++++++++++++ dictBuilder/divsufsort.h | 180 ++++++ dictBuilder/divsufsort_private.h | 208 +++++++ dictBuilder/lfs.h | 56 ++ dictBuilder/sssort.c | 815 ++++++++++++++++++++++++++ dictBuilder/trsort.c | 586 +++++++++++++++++++ dictBuilder/utils.c | 381 +++++++++++++ 14 files changed, 4360 insertions(+) create mode 100644 dictBuilder/COPYING create mode 100644 dictBuilder/Makefile create mode 100644 dictBuilder/config.h create mode 100644 dictBuilder/dibcli.c create mode 100644 dictBuilder/dictBuilder.c create mode 100644 dictBuilder/dictBuilder.h create mode 100644 dictBuilder/divsufsort.c create mode 100644 dictBuilder/divsufsort.h create mode 100644 dictBuilder/divsufsort_private.h create mode 100644 dictBuilder/lfs.h create mode 100644 dictBuilder/sssort.c create mode 100644 dictBuilder/trsort.c create mode 100644 dictBuilder/utils.c diff --git a/NEWS b/NEWS index f146eb140..cfbd6867b 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,6 @@ v0.5.0 Changed streaming & dictionary API +New : dictionary builder utility v0.4.7 Improved : small compression speed improvement in HC mode diff --git a/dictBuilder/COPYING b/dictBuilder/COPYING new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/dictBuilder/COPYING @@ -0,0 +1,339 @@ + 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 new file mode 100644 index 000000000..c2ebdb880 --- /dev/null +++ b/dictBuilder/Makefile @@ -0,0 +1,67 @@ +# ########################################################################## +# Dict Builder - Makefile +# Copyright (C) Yann Collet 2015 +# +# 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 : http://code.google.com/p/zstd/ +# - Public forum : https://groups.google.com/forum/#!forum/lz4c +# ########################################################################## + +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: dictBuilder.c dibcli.c divsufsort.c sssort.c trsort.c $(ZSTDDIR)/huff0.c $(ZSTDDIR)/fse.c $(ZSTDDIR)/zstd_decompress.c + $(CC) $(FLAGS) $^ -o $@$(EXT) + +clean: + @rm -f core *.o tmp* result* *.gcda \ + dictBuilder$(EXT) + @echo Cleaning completed + +test: clean dictBuilder + +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/config.h b/dictBuilder/config.h new file mode 100644 index 000000000..c2925d335 --- /dev/null +++ b/dictBuilder/config.h @@ -0,0 +1,83 @@ +/* + * config.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 _CONFIG_H +#define _CONFIG_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 + +/** 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 +*/ + +/** for inline **/ +#ifndef INLINE +# define INLINE inline +#endif + +/** for VC++ warning **/ +#ifdef _MSC_VER +#pragma warning(disable: 4127) +#endif + + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* _CONFIG_H */ diff --git a/dictBuilder/dibcli.c b/dictBuilder/dibcli.c new file mode 100644 index 000000000..50369c220 --- /dev/null +++ b/dictBuilder/dibcli.c @@ -0,0 +1,256 @@ +/* + 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 + - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c +*/ + + +/************************************** +* 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 */ +#include /* exit, calloc, free */ +#include /* strcmp, strlen */ + +#include "dictBuilder.h" + + +/************************************** +* OS-specific Includes +**************************************/ +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) +# include /* _O_BINARY */ +# include /* _setmode, _isatty */ +# define SET_BINARY_MODE(file) _setmode(_fileno(file), _O_BINARY) +# define IS_CONSOLE(stdStream) _isatty(_fileno(stdStream)) +#else +# include /* isatty */ +# define SET_BINARY_MODE(file) +# define IS_CONSOLE(stdStream) isatty(fileno(stdStream)) +#endif + + +/************************************** +* 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(DiB_VERSION_MAJOR) "." EXP_Q(DiB_VERSION_MINOR) "." EXP_Q(DiB_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 selectionLevelDefault = 9; /* determined experimentally */ +static const unsigned maxDictSizeDefault = 110 KB; +static const char* dictFileNameDefault = "dictionary"; + + +/************************************** +* 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 + + +/************************************** +* 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( "--maxdict : limit dictionary to specified size (default : %u) \n", maxDictSizeDefault); + DISPLAY( " -o : name of dictionary file (default: %s) \n", dictFileNameDefault); + 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( " -# : selection level # (default :%u)\n", selectionLevelDefault); + DISPLAY( " -V : display Version number and exit\n"); + DISPLAY( " -v : verbose mode\n"); + DISPLAY( " -q : suppress warnings; specify twice to suppress errors too\n"); + return 0; +} + +static int badusage(const char* programName) +{ + DISPLAYLEVEL(1, "Incorrect parameters\n"); + if (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; + size_t 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 */ + 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")) { 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, "--maxdict")) { nextArgumentIsMaxDict=1; continue; } + + /* Decode commands (note : aggregated commands are allowed) */ + if (argument[0]=='-') { + argument++; + + while (argument[0]!=0) { + /* selection Level */ + if ((*argument>='0') && (*argument<='9')) { + selectionLevel = 0; + while ((*argument >= '0') && (*argument <= '9')) { + selectionLevel *= 10; + selectionLevel += *argument - '0'; + argument++; + } + continue; + } + + switch(argument[0]) + { + /* Display help */ + case 'V': displayOut=stdout; DISPLAY(WELCOME_MESSAGE); return 0; /* Version Only */ + case 'H': + case 'h': displayOut=stdout; return usage_advanced(programName); + + /* Verbose mode */ + case 'v': displayLevel++; if (displayLevel<3) displayLevel=3; argument++; break; + + /* Quiet mode */ + case 'q': 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); + + if (filenameIdx==0) return badusage(programName); + + /* building ... */ + DiB_setDisplayLevel(displayLevel); + operationResult = DiB_trainFiles(dictFileName, maxDictSize, filenameTable, filenameIdx, selectionLevel); + + if (main_pause) waitEnter(); + free((void*)filenameTable); + return operationResult; +} diff --git a/dictBuilder/dictBuilder.c b/dictBuilder/dictBuilder.c new file mode 100644 index 000000000..ed41d7c51 --- /dev/null +++ b/dictBuilder/dictBuilder.c @@ -0,0 +1,946 @@ +/* + dictBuilder.c + 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 +*/ + +/* ************************************** +* 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 + +/* 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 */ +#include /* stat64 */ +#include /* stat64 */ +#include /* clock */ + +#include "mem.h" /* read */ +#include "divsufsort.h" +#include "dictBuilder.h" +#include "zstd_compress.c" +#include "huff0_static.h" + + +/* ************************************* +* Compiler specifics +***************************************/ +#if !defined(S_ISREG) +# define S_ISREG(x) (((x) & S_IFMT) == S_IFREG) +#endif + +#ifdef _MSC_VER +#define snprintf sprintf_s +#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)(3 GB) * MEMMULT; + +#define NOISELENGTH 32 +#define PRIME1 2654435761U +#define PRIME2 2246822519U + +#define MINRATIO 4 + + +/* ************************************* +* console display +***************************************/ +#define DISPLAY(...) fprintf(stderr, __VA_ARGS__) +#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } +static unsigned g_displayLevel = 2; /* 0 : no display; 1: errors; 2: default; 4: full information */ +void DiB_setDisplayLevel(unsigned l) { g_displayLevel=l; } + +#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ + if (DiB_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) +{ + 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_versionNumber (void) { return DiB_VERSION_NUMBER; } + +static unsigned DiB_GetMilliSpan(clock_t nPrevious) +{ + clock_t nCurrent = clock(); + unsigned nSpan = (unsigned)(((nCurrent - nPrevious) * 1000) / CLOCKS_PER_SEC); + return nSpan; +} + + +/* ******************************************************** +* 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_read_ARCH(const void* p) { size_t r; memcpy(&r, p, sizeof(r)); return r; } + +static unsigned DiB_NbCommonBytes (register size_t val) +{ + if (MEM_isLittleEndian()) { + if (MEM_64bits()) { +# if defined(_MSC_VER) && defined(_WIN64) + unsigned long r = 0; + _BitScanForward64( &r, (U64)val ); + return (unsigned)(r>>3); +# elif defined(__GNUC__) && (__GNUC__ >= 3) + 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) + unsigned long r=0; + _BitScanForward( &r, (U32)val ); + return (unsigned)(r>>3); +# elif defined(__GNUC__) && (__GNUC__ >= 3) + 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_64bits()) { +# if defined(_MSC_VER) && defined(_WIN64) + unsigned long r = 0; + _BitScanReverse64( &r, val ); + return (unsigned)(r>>3); +# elif defined(__GNUC__) && (__GNUC__ >= 3) + 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) + unsigned long r = 0; + _BitScanReverse( &r, (unsigned long)val ); + return (unsigned)(r>>3); +# elif defined(__GNUC__) && (__GNUC__ >= 3) + 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 + } } +} + + +/*! DiB_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) +{ + const char* const pStart = (const char*)pIn; + for (;;) { + size_t diff = DiB_read_ARCH(pMatch) ^ DiB_read_ARCH(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); + return (size_t)((const char*)pIn - pStart); + } +} + + +typedef struct { + U32 pos; + U32 length; + U32 savings; +} dictItem; + +void DiB_initDictItem(dictItem* d) +{ + d->pos = 1; + d->length = 0; + d->savings = (U32)(-1); +} + + +#define LLIMIT 64 /* heuristic determined experimentally */ +#define MINMATCHLENGTH 7 /* heuristic determined experimentally */ +static dictItem DiB_analyzePos( + BYTE* doneMarks, + const saidx_t* suffix, U32 start, + const void* buffer, U32 minRatio) +{ + U32 lengthList[LLIMIT] = {0}; + U32 cumulLength[LLIMIT] = {0}; + U32 savings[LLIMIT] = {0}; + const BYTE* b = (const BYTE*)buffer; + size_t length; + size_t maxLength = LLIMIT; + size_t pos = suffix[start]; + U32 end = start; + dictItem solution; + + + /* init */ + memset(&solution, 0, sizeof(solution)); + doneMarks[pos] = 1; + + /* trivial repetition cases */ + if ( (MEM_read16(b+pos+0) == MEM_read16(b+pos+2)) + ||(MEM_read16(b+pos+1) == MEM_read16(b+pos+3)) + ||(MEM_read16(b+pos+2) == MEM_read16(b+pos+4)) ) { + /* skip and mark segment */ + U16 u16 = MEM_read16(b+pos+4); + U32 u, e = 6; + while (MEM_read16(b+pos+e) == u16) e+=2 ; + if (b[pos+e] == b[pos+e-1]) e++; + for (u=1; u=MINMATCHLENGTH); + + /* look backward */ + do { + length = DiB_count(b + pos, b + *(suffix+start-1)); + if (length >=MINMATCHLENGTH) start--; + } while(length >= MINMATCHLENGTH); + + /* exit if not found a minimum nb of repetitions */ + if (end-start < minRatio) { + U32 idx; + for(idx=start; idx= %u at pos %7u ", (U32)(end-start), MINMATCHLENGTH, (U32)pos); + DISPLAYLEVEL(4, "\n"); + + for (searchLength = MINMATCHLENGTH ; ; searchLength++) { + BYTE currentChar = 0; + U32 currentCount = 0; + U32 currentID = refinedStart; + U32 id; + U32 selectedCount = 0; + U32 selectedID = currentID; + for (id =refinedStart; id < refinedEnd; id++) { + if (b[ suffix[id] + searchLength] != currentChar) { + if (currentCount > selectedCount) { + selectedCount = currentCount; + selectedID = currentID; + } + currentID = id; + currentChar = b[ suffix[id] + searchLength]; + currentCount = 0; + } + currentCount ++; + } + if (currentCount > selectedCount) { /* for last */ + selectedCount = currentCount; + selectedID = currentID; + } + + if (selectedCount < minRatio) + break; + //DISPLAYLEVEL(4, "best char at length %u: %02X (seen %u times) (pos %u) \n", searchLength+1, selectedChar, selectedCount, selectedRef); + refinedStart = selectedID; + refinedEnd = refinedStart + selectedCount; + } + + /* evaluate gain based on new ref */ + start = refinedStart; + pos = suffix[refinedStart]; + end = start; + memset(lengthList, 0, sizeof(lengthList)); + + /* look forward */ + do { + end++; + length = DiB_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]); + if (length >= LLIMIT) length = LLIMIT-1; + lengthList[length]++; + if (length >=MINMATCHLENGTH) start--; + } while(length >= MINMATCHLENGTH); + + /* largest useful length */ + memset(cumulLength, 0, sizeof(cumulLength)); + cumulLength[maxLength-1] = lengthList[maxLength-1]; + for (i=maxLength-2; i>=0; i--) + cumulLength[i] = cumulLength[i+1] + lengthList[i]; + + for (i=LLIMIT-1; i>=MINMATCHLENGTH; i--) if (cumulLength[i]>=minRatio) break; + maxLength = i; + + /* reduce maxLength in case of final into repetitive data */ + { + U32 l = maxLength; + BYTE c = b[pos + maxLength-1]; + while (b[pos+l-2]==c) l--; + maxLength = l; + } + if (maxLength < MINMATCHLENGTH) return solution; /* skip : no long-enough solution */ + + /* calculate savings */ + savings[5] = 0; + for (i=MINMATCHLENGTH; i<=(int)maxLength; i++) + savings[i] = savings[i-1] + (lengthList[i] * (i-3)); + + DISPLAYLEVEL(4, "Selected ref at position %u, of length %u : saves %u (ratio: %.2f) \n", + (U32)pos, (U32)maxLength, savings[maxLength], (double)savings[maxLength] / maxLength); + + solution.pos = pos; + solution.length = maxLength; + solution.savings = savings[maxLength]; + + /* mark positions done */ + { + U32 id; + U32 testedPos; + for (id=start; id solution.length) length = solution.length; + } + pEnd = testedPos + length; + for (p=testedPos; ppos; + const U32 max = elt.pos + (elt.length-1); + + /* tail overlap */ + U32 u; for (u=1; u elt.pos) && (table[u].pos < max)) { /* overlap */ + /* append */ + U32 addedLength = table[u].pos - elt.pos; + table[u].length += addedLength; + table[u].pos = elt.pos; + table[u].savings += elt.savings * addedLength / elt.length; /* rough approx */ + table[u].savings += elt.length / 8; /* rough approx */ + elt = table[u]; + while ((u>1) && (table[u-1].savings < elt.savings)) + table[u] = table[u-1], u--; + table[u] = elt; + return u; + } } + + /* front overlap */ + for (u=1; u elt.pos) && (table[u].pos < elt.pos)) { /* overlap */ + /* append */ + int addedLength = (elt.pos + elt.length) - (table[u].pos + table[u].length); + table[u].savings += elt.length / 8; /* rough approx */ + if (addedLength > 0) { /* otherwise, already included */ + table[u].length += addedLength; + table[u].savings += elt.savings * addedLength / elt.length; /* rough approx */ + } + elt = table[u]; + while ((u>1) && (table[u-1].savings < elt.savings)) + table[u] = table[u-1], u--; + table[u] = elt; + return u; + } } + + return 0; +} + + +static void DiB_removeDictItem(dictItem* table, U32 id) +{ + /* convention : first element is nb of elts */ + U32 max = table->pos; + U32 u; + if (!id) return; /* protection, should never happen */ + for (u=id; upos--; +} + + +static void DiB_insertDictItem(dictItem* table, U32 maxSize, dictItem elt) +{ + /* merge if possible */ + U32 mergeId = DiB_checkMerge(table, elt, 0); + if (mergeId) { + U32 newMerge = 1; + while (newMerge) { + newMerge = DiB_checkMerge(table, table[mergeId], mergeId); + if (newMerge) DiB_removeDictItem(table, mergeId); + mergeId = newMerge; + } + return; + } + + /* insert */ + { + U32 current; + U32 nextElt = table->pos; + if (nextElt >= maxSize) nextElt = maxSize-1; + current = nextElt-1; + while (table[current].savings < elt.savings) { + table[current+1] = table[current]; + current--; + } + table[current+1] = elt; + table->pos = nextElt+1; + } +} + + +static U32 DiB_dictSize(const dictItem* dictList) +{ + U32 u, dictSize = 0; + for (u=1; u> shiftRatio; + saint_t errorCode; + + /* init */ + DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */ + if (!suffix0 || !reverseSuffix || !doneMarks || !filePos) + EXM_THROW(1, "not enough memory for DiB_trainBuffer"); + if (minRatio < MINRATIO) minRatio = MINRATIO; + memset(doneMarks, 0, bufferSize+16); + + /* sort */ + DISPLAYLEVEL(2, "sorting %s ...\n", displayName); + errorCode = divsufsort((const sauchar_t*)buffer, suffix, bufferSize); + if (errorCode != 0) EXM_THROW(2, "sort failed"); + suffix[bufferSize] = bufferSize; /* leads into noise */ + suffix0[0] = bufferSize; /* leads into noise */ + { + /* build reverse suffix sort */ + size_t pos; + for (pos=0; pos < bufferSize; pos++) + reverseSuffix[suffix[pos]] = pos; + /* build file pos */ + filePos[0] = 0; + for (pos=1; pospos; /* convention : nb of useful elts within dictList */ + U32 currentSize = 0; + U32 n; for (n=1; n maxDictSize) break; + } + dictList->pos = n; + } + + free(suffix0); + free(reverseSuffix); + free(doneMarks); + free(filePos); +} + + +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); + } +} + + +typedef struct +{ + ZSTD_CCtx* ref; + ZSTD_CCtx* zc; + void* workPlace; /* must be BLOCKSIZE allocated */ +} EStats_ress_t; + + +static void DiB_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; + + if (srcSize > BLOCKSIZE) srcSize = BLOCKSIZE; /* protection vs large samples */ + ZSTD_copyCCtx(esr.zc, esr.ref); + ZSTD_compressBlock(esr.zc, esr.workPlace, BLOCKSIZE, src, srcSize); + + /* count stats */ + for(bytePtr = esr.zc->seqStore.litStart; bytePtr < esr.zc->seqStore.lit; bytePtr++) + countLit[*bytePtr]++; + for(u32Ptr = esr.zc->seqStore.offsetStart; u32Ptr < esr.zc->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++) + matchlengthCount[*bytePtr]++; + for(bytePtr = esr.zc->seqStore.litLengthStart; bytePtr < esr.zc->seqStore.litLength; bytePtr++) + litlengthCount[*bytePtr]++; +} + + +#define OFFCODE_MAX 18 +static size_t DiB_analyzeEntropy(void* dstBuffer, size_t maxDstSize, + const void* srcBuffer, size_t* fileSizes, unsigned nbFiles, + const void* dictBuffer, size_t dictBufferSize) +{ + U32 countLit[256]; + U32 offcodeCount[MaxOff+1]; + HUF_CREATE_STATIC_CTABLE(hufTable, 255); + short offcodeNCount[MaxOff+1]; + U32 matchLengthCount[MaxML+1]; + short matchLengthNCount[MaxML+1]; + U32 litlengthCount[MaxLL+1]; + short litlengthNCount[MaxLL+1]; + EStats_ress_t esr; + ZSTD_parameters params; + U32 u, huffLog = 12, Offlog = OffFSELog, mlLog = MLFSELog, llLog = LLFSELog, total; + size_t pos = 0, errorCode; + size_t eSize = 0; + + /* init */ + for (u=0; u<256; u++) countLit[u]=1; /* any character must be described */ + for (u=0; u<=OFFCODE_MAX; u++) offcodeCount[u]=1; + for (u=0; u<=MaxML; u++) matchLengthCount[u]=1; + for (u=0; u<=MaxLL; u++) litlengthCount[u]=1; + 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"); + params = ZSTD_getParams(5, dictBufferSize + 15 KB); + params.strategy = ZSTD_greedy; + ZSTD_compressBegin_advanced(esr.ref, dictBuffer, dictBufferSize, params); + + /* collect stats on all files */ + for (u=0; u totalSizeToLoad) benchedSize = (size_t)totalSizeToLoad; + if (benchedSize < totalSizeToLoad) + DISPLAY("Not enough memory; training on %u MB only...\n", (unsigned)(benchedSize >> 20)); + + /* Memory allocation & restrictions */ + srcBuffer = malloc(benchedSize+NOISELENGTH); /* + noise */ + if ((!fileSizes) || (!srcBuffer) || (!dictList)) EXM_THROW(12, "not enough memory for DiB_trainFiles"); /* should not happen */ + DiB_initDictItem(dictList); + + /* Load input buffer */ + DiB_loadFiles(srcBuffer, benchedSize, fileSizes, fileNamesTable, nbFiles); + DiB_fillNoise((char*)srcBuffer + benchedSize, NOISELENGTH); /* for end of buffer condition */ + + /* Train */ + snprintf (mfName, sizeof(mfName), " %u files", nbFiles); + if (nbFiles > 1) displayName = mfName; + else displayName = fileNamesTable[0]; + + DiB_trainBuffer(dictList, dictListSize, + srcBuffer, benchedSize, + displayName, + fileSizes, nbFiles, maxDictSize, + shiftRatio); + + /* display best matches */ + if (g_displayLevel>= 3) { + const U32 nb = 25; + U32 u; + U32 dictContentSize = DiB_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++) { + U32 p = dictList[u].pos; + U32 l = dictList[u].length; + 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, (char*)srcBuffer+p, d); + DISPLAYLEVEL(3, "| \n"); + } } + + /* create dictionary */ + { + void* dictContent; + U32 dictContentSize = DiB_dictSize(dictList); + void* dictHeader; + size_t dictHeaderSize, hSize; + BYTE* ptr; + U32 u; + + /* build dict */ + #define EBSIZE (2 KB) + dictHeaderSize = EBSIZE; + dictHeader = malloc(dictHeaderSize); + dictContent = malloc(dictContentSize); + if (!dictHeader || !dictContent) EXM_THROW(2, "not enough memory"); + + /* build dict content */ + ptr = (BYTE*)dictContent + dictContentSize; + + for (u=1; upos; u++) { + U32 l = dictList[u].length; + ptr -= l; + memcpy(ptr, (char*)srcBuffer+dictList[u].pos, l); + } + + /* dictionary header */ + MEM_writeLE32(dictHeader, ZSTD_DICT_MAGIC); + hSize = 4; + dictHeaderSize -= 4; + + /* entropic tables */ + DISPLAYLEVEL(2, "statistics ... \n"); + hSize += DiB_analyzeEntropy((char*)dictHeader+4, dictHeaderSize, + srcBuffer, fileSizes, nbFiles, + dictContent, dictContentSize); + + /* save dict */ + { + size_t dictSize = hSize + dictContentSize; + DISPLAYLEVEL(2, "Save dictionary of size %u into file %s \n", (U32)dictSize, dictFileName); + DiB_saveDict(dictFileName, dictHeader, hSize, dictContent, dictContentSize); + //DiB_saveDict(dictFileName, NULL, 0, dictContent, dictContentSize); // content only + } + /* clean */ + free(dictHeader); + free(dictContent); + } + + /* clean up */ + free(srcBuffer); + free(fileSizes); + free(dictList); + return 0; +} + diff --git a/dictBuilder/dictBuilder.h b/dictBuilder/dictBuilder.h new file mode 100644 index 000000000..76efed293 --- /dev/null +++ b/dictBuilder/dictBuilder.h @@ -0,0 +1,44 @@ +/* + 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 +*/ + +/* ************************************* +* 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); + + +/* ************************************* +* Main functions +***************************************/ +int DiB_trainFiles(const char* dictFileName, unsigned maxDictSize, + const char** fileNamesTable, unsigned nbFiles, + unsigned selectionLevel); + + +void DiB_setDisplayLevel(unsigned l); diff --git a/dictBuilder/divsufsort.c b/dictBuilder/divsufsort.c new file mode 100644 index 000000000..9f64b4f48 --- /dev/null +++ b/dictBuilder/divsufsort.c @@ -0,0 +1,398 @@ +/* + * divsufsort.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" +#ifdef _OPENMP +# include +#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 new file mode 100644 index 000000000..6d3e64870 --- /dev/null +++ b/dictBuilder/divsufsort.h @@ -0,0 +1,180 @@ +/* + * 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 new file mode 100644 index 000000000..dc35063f5 --- /dev/null +++ b/dictBuilder/divsufsort_private.h @@ -0,0 +1,208 @@ +/* + * 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 +# include +#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 new file mode 100644 index 000000000..7ef88f0b4 --- /dev/null +++ b/dictBuilder/lfs.h @@ -0,0 +1,56 @@ +/* + * 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 new file mode 100644 index 000000000..4a18fd2ab --- /dev/null +++ b/dictBuilder/sssort.c @@ -0,0 +1,815 @@ +/* + * 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. + */ + +#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 new file mode 100644 index 000000000..6fe3e67ba --- /dev/null +++ b/dictBuilder/trsort.c @@ -0,0 +1,586 @@ +/* + * 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. + */ + +#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 new file mode 100644 index 000000000..90fb23efa --- /dev/null +++ b/dictBuilder/utils.c @@ -0,0 +1,381 @@ +/* + * 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; +} From 4ddb1f556680242c5e614e0884143e58810eed54 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Jan 2016 03:24:53 +0100 Subject: [PATCH 11/34] optimized counting of small segments --- lib/fse.c | 299 ++++++++++++++++++++++++----------------------- lib/fse.h | 14 +-- lib/fse_static.h | 4 +- 3 files changed, 159 insertions(+), 158 deletions(-) diff --git a/lib/fse.c b/lib/fse.c index 309b28caf..61272a624 100644 --- a/lib/fse.c +++ b/lib/fse.c @@ -141,102 +141,6 @@ typedef U32 DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)]; /* Function templates */ -size_t FSE_count_generic(unsigned* count, unsigned* maxSymbolValuePtr, const FSE_FUNCTION_TYPE* source, size_t sourceSize, unsigned safe) -{ - const FSE_FUNCTION_TYPE* ip = source; - const FSE_FUNCTION_TYPE* const iend = ip+sourceSize; - unsigned maxSymbolValue = *maxSymbolValuePtr; - unsigned max=0; - int s; - - U32 Counting1[FSE_MAX_SYMBOL_VALUE+1] = { 0 }; - U32 Counting2[FSE_MAX_SYMBOL_VALUE+1] = { 0 }; - U32 Counting3[FSE_MAX_SYMBOL_VALUE+1] = { 0 }; - U32 Counting4[FSE_MAX_SYMBOL_VALUE+1] = { 0 }; - - /* safety checks */ - if (!sourceSize) - { - memset(count, 0, (maxSymbolValue + 1) * sizeof(FSE_FUNCTION_TYPE)); - *maxSymbolValuePtr = 0; - return 0; - } - if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(GENERIC); /* maxSymbolValue too large : unsupported */ - if (!maxSymbolValue) maxSymbolValue = FSE_MAX_SYMBOL_VALUE; /* 0 == default */ - - if ((safe) || (sizeof(FSE_FUNCTION_TYPE)>1)) - { - /* check input values, to avoid count table overflow */ - while (ip < iend-3) - { - if (*ip>maxSymbolValue) return ERROR(GENERIC); Counting1[*ip++]++; - if (*ip>maxSymbolValue) return ERROR(GENERIC); Counting2[*ip++]++; - if (*ip>maxSymbolValue) return ERROR(GENERIC); Counting3[*ip++]++; - if (*ip>maxSymbolValue) return ERROR(GENERIC); Counting4[*ip++]++; - } - } - else - { - U32 cached = MEM_read32(ip); ip += 4; - while (ip < iend-15) - { - U32 c = cached; cached = MEM_read32(ip); ip += 4; - Counting1[(BYTE) c ]++; - Counting2[(BYTE)(c>>8) ]++; - Counting3[(BYTE)(c>>16)]++; - Counting4[ c>>24 ]++; - c = cached; cached = MEM_read32(ip); ip += 4; - Counting1[(BYTE) c ]++; - Counting2[(BYTE)(c>>8) ]++; - Counting3[(BYTE)(c>>16)]++; - Counting4[ c>>24 ]++; - c = cached; cached = MEM_read32(ip); ip += 4; - Counting1[(BYTE) c ]++; - Counting2[(BYTE)(c>>8) ]++; - Counting3[(BYTE)(c>>16)]++; - Counting4[ c>>24 ]++; - c = cached; cached = MEM_read32(ip); ip += 4; - Counting1[(BYTE) c ]++; - Counting2[(BYTE)(c>>8) ]++; - Counting3[(BYTE)(c>>16)]++; - Counting4[ c>>24 ]++; - } - ip-=4; - } - - /* finish last symbols */ - while (ipmaxSymbolValue)) return ERROR(GENERIC); Counting1[*ip++]++; } - - for (s=0; s<=(int)maxSymbolValue; s++) - { - count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s]; - if (count[s] > max) max = count[s]; - } - - while (!count[maxSymbolValue]) maxSymbolValue--; - *maxSymbolValuePtr = maxSymbolValue; - return (size_t)max; -} - -/* hidden fast variant (unsafe) */ -size_t FSE_FUNCTION_NAME(FSE_countFast, FSE_FUNCTION_EXTENSION) -(unsigned* count, unsigned* maxSymbolValuePtr, const FSE_FUNCTION_TYPE* source, size_t sourceSize) -{ - return FSE_count_generic(count, maxSymbolValuePtr, source, sourceSize, 0); -} - -size_t FSE_FUNCTION_NAME(FSE_count, FSE_FUNCTION_EXTENSION) -(unsigned* count, unsigned* maxSymbolValuePtr, const FSE_FUNCTION_TYPE* source, size_t sourceSize) -{ - if ((sizeof(FSE_FUNCTION_TYPE)==1) && (*maxSymbolValuePtr >= 255)) - { - *maxSymbolValuePtr = 255; - return FSE_count_generic(count, maxSymbolValuePtr, source, sourceSize, 0); - } - return FSE_count_generic(count, maxSymbolValuePtr, source, sourceSize, 1); -} - - static U32 FSE_tableStep(U32 tableSize) { return (tableSize>>1) + (tableSize>>3) + 3; } size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) @@ -264,35 +168,28 @@ size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned /* symbol start positions */ cumul[0] = 0; - for (i=1; i<=maxSymbolValue+1; i++) - { - if (normalizedCounter[i-1]==-1) /* Low proba symbol */ - { + for (i=1; i<=maxSymbolValue+1; i++) { + if (normalizedCounter[i-1]==-1) { /* Low proba symbol */ cumul[i] = cumul[i-1] + 1; tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(i-1); - } - else + } else { cumul[i] = cumul[i-1] + normalizedCounter[i-1]; - } + } } cumul[maxSymbolValue+1] = tableSize+1; /* Spread symbols */ - for (symbol=0; symbol<=maxSymbolValue; symbol++) - { + for (symbol=0; symbol<=maxSymbolValue; symbol++) { int nbOccurences; - for (nbOccurences=0; nbOccurences highThreshold) position = (position + step) & tableMask; /* Low proba area */ - } - } + } } if (position!=0) return ERROR(GENERIC); /* Must have gone through all positions */ /* Build table */ - for (i=0; i= largeLimit) noLarge=0; symbolNext[s] = normalizedCounter[s]; - } - } + } } /* Spread symbols */ - for (s=0; s<=maxSymbolValue; s++) - { + for (s=0; s<=maxSymbolValue; s++) { int i; - for (i=0; i highThreshold) position = (position + step) & tableMask; /* lowprob area */ - } - } + } } if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ /* Build Decoding table */ { U32 i; - for (i=0; i max) max = count[s]; + + return (size_t)max; +} + + +static size_t FSE_count_parallel(unsigned* count, unsigned* maxSymbolValuePtr, + const void* source, size_t sourceSize, + unsigned checkMax) +{ + const BYTE* ip = (const BYTE*)source; + const BYTE* const iend = ip+sourceSize; + unsigned maxSymbolValue = *maxSymbolValuePtr; + unsigned max=0; + U32 s; + + U32 Counting1[256] = { 0 }; + U32 Counting2[256] = { 0 }; + U32 Counting3[256] = { 0 }; + U32 Counting4[256] = { 0 }; + + /* safety checks */ + if (!sourceSize) { + memset(count, 0, maxSymbolValue + 1); + *maxSymbolValuePtr = 0; + return 0; + } + if (!maxSymbolValue) maxSymbolValue = 255; /* 0 == default */ + + { /* by stripes of 16 bytes */ + U32 cached = MEM_read32(ip); ip += 4; + while (ip < iend-15) { + U32 c = cached; cached = MEM_read32(ip); ip += 4; + Counting1[(BYTE) c ]++; + Counting2[(BYTE)(c>>8) ]++; + Counting3[(BYTE)(c>>16)]++; + Counting4[ c>>24 ]++; + c = cached; cached = MEM_read32(ip); ip += 4; + Counting1[(BYTE) c ]++; + Counting2[(BYTE)(c>>8) ]++; + Counting3[(BYTE)(c>>16)]++; + Counting4[ c>>24 ]++; + c = cached; cached = MEM_read32(ip); ip += 4; + Counting1[(BYTE) c ]++; + Counting2[(BYTE)(c>>8) ]++; + Counting3[(BYTE)(c>>16)]++; + Counting4[ c>>24 ]++; + c = cached; cached = MEM_read32(ip); ip += 4; + Counting1[(BYTE) c ]++; + Counting2[(BYTE)(c>>8) ]++; + Counting3[(BYTE)(c>>16)]++; + Counting4[ c>>24 ]++; + } + ip-=4; + } + + /* finish last symbols */ + while (ipmaxSymbolValue; s--) + { + Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s]; + if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall); + } } + + for (s=0; s<=maxSymbolValue; s++) { + count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s]; + if (count[s] > max) max = count[s]; + } + + while (!count[maxSymbolValue]) maxSymbolValue--; + *maxSymbolValuePtr = maxSymbolValue; + return (size_t)max; +} + +/* fast variant (unsafe : won't check if src contains values beyond count[] limit) */ +size_t FSE_countFast(unsigned* count, unsigned* maxSymbolValuePtr, + const void* source, size_t sourceSize) +{ + if (sourceSize < 1500) return FSE_count_simple(count, maxSymbolValuePtr, source, sourceSize); + return FSE_count_parallel(count, maxSymbolValuePtr, source, sourceSize, 0); +} + +size_t FSE_count(unsigned* count, unsigned* maxSymbolValuePtr, + const void* source, size_t sourceSize) +{ + if (*maxSymbolValuePtr <255) + return FSE_count_parallel(count, maxSymbolValuePtr, source, sourceSize, 1); + *maxSymbolValuePtr = 255; + return FSE_countFast(count, maxSymbolValuePtr, source, sourceSize); +} + + +/*-************************************************************** * FSE Compression Code ****************************************************************/ -/* +/*! FSE_CTable is a variable size structure which contains : U16 tableLog; U16 maxSymbolValue; @@ -657,7 +664,6 @@ void FSE_freeCTable (FSE_CTable* ct) free(ct); } - /* provides the minimum logSize to safely represent a distribution */ static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue) { @@ -872,10 +878,8 @@ size_t FSE_buildCTable_rle (FSE_CTable* ct, BYTE symbolValue) tableU16[1] = 0; /* just in case */ /* Build Symbol Transformation Table */ - { - symbolTT[symbolValue].deltaNbBits = 0; - symbolTT[symbolValue].deltaFindState = 0; - } + symbolTT[symbolValue].deltaNbBits = 0; + symbolTT[symbolValue].deltaFindState = 0; return 0; } @@ -905,15 +909,13 @@ static size_t FSE_compress_usingCTable_generic (void* dst, size_t dstSize, #define FSE_FLUSHBITS(s) (fast ? BIT_flushBitsFast(s) : BIT_flushBits(s)) /* join to even */ - if (srcSize & 1) - { + if (srcSize & 1) { FSE_encodeSymbol(&bitC, &CState1, *--ip); FSE_FLUSHBITS(&bitC); } /* join to mod 4 */ - if ((sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) && (srcSize & 2)) /* test bit 2 */ - { + if ((sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) && (srcSize & 2)) { /* test bit 2 */ FSE_encodeSymbol(&bitC, &CState2, *--ip); FSE_encodeSymbol(&bitC, &CState1, *--ip); FSE_FLUSHBITS(&bitC); @@ -929,8 +931,7 @@ static size_t FSE_compress_usingCTable_generic (void* dst, size_t dstSize, FSE_encodeSymbol(&bitC, &CState1, *--ip); - if (sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) /* this test must be static */ - { + if (sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) { /* this test must be static */ FSE_encodeSymbol(&bitC, &CState2, *--ip); FSE_encodeSymbol(&bitC, &CState1, *--ip); } @@ -1013,7 +1014,7 @@ size_t FSE_compress (void* dst, size_t dstSize, const void* src, size_t srcSize) } -/********************************************************* +/*-******************************************************* * Decompression (Byte symbols) *********************************************************/ size_t FSE_buildDTable_rle (FSE_DTable* dt, BYTE symbolValue) diff --git a/lib/fse.h b/lib/fse.h index e98f1a54a..7e6bfc1a5 100644 --- a/lib/fse.h +++ b/lib/fse.h @@ -124,13 +124,13 @@ or to save and provide normalized distribution using external method. /*! FSE_count(): - Provides the precise count of each symbol within a table 'count' - 'count' is a table of unsigned int, of minimum size (maxSymbolValuePtr[0]+1). - maxSymbolValuePtr[0] will be updated if detected smaller than initially expected - return : the count of the most frequent symbol (which is not identified) - if return == srcSize, there is only one symbol. - if FSE_isError(return), it's an error code. */ -size_t FSE_count(unsigned* count, unsigned* maxSymbolValuePtr, const unsigned char* src, size_t srcSize); + Provides the precise count of each byte within a table 'count' + 'count' is a table of unsigned int, of minimum size (*maxSymbolValuePtr+1). + *maxSymbolValuePtr will be updated if detected smaller than initial value. + @return : the count of the most frequent symbol (which is not identified) + if return == srcSize, there is only one symbol. + Can also return an error code, which can be tested with FSE_isError() */ +size_t FSE_count(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize); /*! FSE_optimalTableLog(): diff --git a/lib/fse_static.h b/lib/fse_static.h index 3028a2f40..eb031639c 100644 --- a/lib/fse_static.h +++ b/lib/fse_static.h @@ -63,8 +63,8 @@ extern "C" { /* ***************************************** * FSE advanced API *******************************************/ -size_t FSE_countFast(unsigned* count, unsigned* maxSymbolValuePtr, const unsigned char* src, size_t srcSize); -/* same as FSE_count(), but blindly trust that all values within src are <= *maxSymbolValuePtr */ +size_t FSE_countFast(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize); +/* same as FSE_count(), but blindly trusts that all byte values within src are <= *maxSymbolValuePtr */ size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits); /* build a fake FSE_CTable, designed to not compress an input, where each symbol uses nbBits */ From b31de73435fb114ca3ba22313321baabf160199f Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Jan 2016 10:30:02 +0100 Subject: [PATCH 12/34] minor API update --- dictBuilder/dibcli.c | 4 ++-- dictBuilder/dictBuilder.c | 9 ++++----- dictBuilder/dictBuilder.h | 24 ++++++++++++++++++------ 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/dictBuilder/dibcli.c b/dictBuilder/dibcli.c index 50369c220..ce4a7ac73 100644 --- a/dictBuilder/dibcli.c +++ b/dictBuilder/dibcli.c @@ -247,8 +247,8 @@ int main(int argCount, const char** argv) if (filenameIdx==0) return badusage(programName); /* building ... */ - DiB_setDisplayLevel(displayLevel); - operationResult = DiB_trainFiles(dictFileName, maxDictSize, filenameTable, filenameIdx, selectionLevel); + DiB_setNotificationLevel(displayLevel); + operationResult = DiB_trainDictionary(dictFileName, maxDictSize, selectionLevel, filenameTable, filenameIdx); if (main_pause) waitEnter(); free((void*)filenameTable); diff --git a/dictBuilder/dictBuilder.c b/dictBuilder/dictBuilder.c index ed41d7c51..fa14ed2ca 100644 --- a/dictBuilder/dictBuilder.c +++ b/dictBuilder/dictBuilder.c @@ -98,8 +98,8 @@ static const size_t maxMemory = (sizeof(size_t)==4) ? (2 GB - 64 MB) : (size_t ***************************************/ #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) #define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } -static unsigned g_displayLevel = 2; /* 0 : no display; 1: errors; 2: default; 4: full information */ -void DiB_setDisplayLevel(unsigned l) { g_displayLevel=l; } +static unsigned g_displayLevel = 0; /* 0 : no display; 1: errors; 2: default; 4: full information */ +void DiB_setNotificationLevel(unsigned l) { g_displayLevel=l; } #define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ if (DiB_GetMilliSpan(g_time) > refreshRate) \ @@ -833,9 +833,8 @@ static void DiB_saveDict(const char* dictFileName, } -int DiB_trainFiles(const char* dictFileName, unsigned maxDictSize, - const char** fileNamesTable, unsigned nbFiles, - unsigned shiftRatio) +int DiB_trainDictionary(const char* dictFileName, unsigned maxDictSize, unsigned shiftRatio, + const char** fileNamesTable, unsigned nbFiles) { void* srcBuffer; size_t benchedSize; diff --git a/dictBuilder/dictBuilder.h b/dictBuilder/dictBuilder.h index 76efed293..74fa2b0c0 100644 --- a/dictBuilder/dictBuilder.h +++ b/dictBuilder/dictBuilder.h @@ -23,7 +23,10 @@ - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c */ -/* ************************************* +/* This library is designed for a single-threaded console application. +* It abruptly exits (exit() function) when it encounters an error condition. */ + +/*-************************************* * Version ***************************************/ #define DiB_VERSION_MAJOR 0 /* for breaking interface changes */ @@ -33,12 +36,21 @@ unsigned DiB_versionNumber (void); -/* ************************************* +/*-************************************* * Main functions ***************************************/ -int DiB_trainFiles(const char* dictFileName, unsigned maxDictSize, - const char** fileNamesTable, unsigned nbFiles, - unsigned selectionLevel); +/*! DiB_trainDictionary + Train a dictionary from a set of files provided by @fileNamesTable + Resulting dictionary is written in file @dictFileName + @result : 0 if fine +*/ +int DiB_trainDictionary(const char* dictFileName, unsigned maxDictSize, unsigned selectivityLevel, + const char** fileNamesTable, unsigned nbFiles); -void DiB_setDisplayLevel(unsigned l); +/*! DiB_setNotificationLevel + Set amount of notification to be displayed on the console. + 0 = no console notification (default). + Note : not thread-safe (use a global constant) +*/ +void DiB_setNotificationLevel(unsigned l); From 9cadd0853c279fab6b27fb4aa465f54f8daeb667 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Jan 2016 15:39:52 +0100 Subject: [PATCH 13/34] add basic tests --- Makefile | 4 + dictBuilder/Makefile | 4 +- dictBuilder/dibcli.c | 2 +- dictBuilder/dictBuilder.c | 24 +- dictBuilder/divsufsort.c | 6 + dictBuilder/sssort.c | 6 + dictBuilder/trsort.c | 6 + lib/huff0.c | 502 +++++++++++++++++--------------------- 8 files changed, 256 insertions(+), 298 deletions(-) diff --git a/Makefile b/Makefile index 88de5d0d2..9ff867fbb 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,7 @@ PRGDIR = programs ZSTDDIR = lib +DICTDIR = dictBuilder # Define nul output ifneq (,$(filter Windows%,$(OS))) @@ -51,6 +52,7 @@ default: zstdprogram all: $(MAKE) -C $(ZSTDDIR) $@ $(MAKE) -C $(PRGDIR) $@ + $(MAKE) -C $(DICTDIR) $@ zstdprogram: $(MAKE) -C $(PRGDIR) @@ -58,6 +60,7 @@ zstdprogram: clean: @$(MAKE) -C $(ZSTDDIR) $@ > $(VOID) @$(MAKE) -C $(PRGDIR) $@ > $(VOID) + @$(MAKE) -C $(DICTDIR) $@ > $(VOID) @echo Cleaning completed @@ -78,6 +81,7 @@ travis-install: test: $(MAKE) -C $(PRGDIR) $@ + $(MAKE) -C $(DICTDIR) $@ cmaketest: cd contrib/cmake ; cmake . ; $(MAKE) diff --git a/dictBuilder/Makefile b/dictBuilder/Makefile index c2ebdb880..e5a4f1aa7 100644 --- a/dictBuilder/Makefile +++ b/dictBuilder/Makefile @@ -55,7 +55,9 @@ clean: dictBuilder$(EXT) @echo Cleaning completed -test: clean dictBuilder +test: dictBuilder + ./dictBuilder * + @rm dictionary clangtest: CC = clang clangtest: CFLAGS += -Werror diff --git a/dictBuilder/dibcli.c b/dictBuilder/dibcli.c index ce4a7ac73..434053482 100644 --- a/dictBuilder/dibcli.c +++ b/dictBuilder/dibcli.c @@ -153,7 +153,7 @@ int main(int argCount, const char** argv) operationResult=0, nextArgumentIsMaxDict=0, nextArgumentIsDictFileName=0; - size_t maxDictSize = maxDictSizeDefault; + unsigned maxDictSize = maxDictSizeDefault; unsigned selectionLevel = selectionLevelDefault; const char** filenameTable = (const char**)malloc(argCount * sizeof(const char*)); /* argCount >= 1 */ unsigned filenameIdx = 0; diff --git a/dictBuilder/dictBuilder.c b/dictBuilder/dictBuilder.c index fa14ed2ca..b41259677 100644 --- a/dictBuilder/dictBuilder.c +++ b/dictBuilder/dictBuilder.c @@ -419,7 +419,7 @@ static dictItem DiB_analyzePos( /* largest useful length */ memset(cumulLength, 0, sizeof(cumulLength)); cumulLength[maxLength-1] = lengthList[maxLength-1]; - for (i=maxLength-2; i>=0; i--) + for (i=(int)(maxLength-2); i>=0; i--) cumulLength[i] = cumulLength[i+1] + lengthList[i]; for (i=LLIMIT-1; i>=MINMATCHLENGTH; i--) if (cumulLength[i]>=minRatio) break; @@ -427,7 +427,7 @@ static dictItem DiB_analyzePos( /* reduce maxLength in case of final into repetitive data */ { - U32 l = maxLength; + U32 l = (U32)maxLength; BYTE c = b[pos + maxLength-1]; while (b[pos+l-2]==c) l--; maxLength = l; @@ -442,8 +442,8 @@ static dictItem DiB_analyzePos( DISPLAYLEVEL(4, "Selected ref at position %u, of length %u : saves %u (ratio: %.2f) \n", (U32)pos, (U32)maxLength, savings[maxLength], (double)savings[maxLength] / maxLength); - solution.pos = pos; - solution.length = maxLength; + solution.pos = (U32)pos; + solution.length = (U32)maxLength; solution.savings = savings[maxLength]; /* mark positions done */ @@ -459,7 +459,7 @@ static dictItem DiB_analyzePos( length = DiB_count(b+pos, b+testedPos); if (length > solution.length) length = solution.length; } - pEnd = testedPos + length; + pEnd = (U32)(testedPos + length); for (p=testedPos; ppos; U32 u; if (!id) return; /* protection, should never happen */ - for (u=id; upos--; } @@ -570,7 +570,7 @@ static U32 DiB_dictSize(const dictItem* dictList) static void DiB_trainBuffer(dictItem* dictList, U32 dictListSize, const void* const buffer, const size_t bufferSize, /* buffer must end with noisy guard band */ const char* displayName, - const size_t* fileSizes, size_t nbFiles, unsigned maxDictSize, + const size_t* fileSizes, unsigned nbFiles, unsigned maxDictSize, U32 shiftRatio) { saidx_t* const suffix0 = (saidx_t*)malloc((bufferSize+2)*sizeof(*suffix0)); @@ -590,19 +590,19 @@ static void DiB_trainBuffer(dictItem* dictList, U32 dictListSize, /* sort */ DISPLAYLEVEL(2, "sorting %s ...\n", displayName); - errorCode = divsufsort((const sauchar_t*)buffer, suffix, bufferSize); + errorCode = divsufsort((const sauchar_t*)buffer, suffix, (saidx_t)bufferSize); if (errorCode != 0) EXM_THROW(2, "sort failed"); - suffix[bufferSize] = bufferSize; /* leads into noise */ - suffix0[0] = bufferSize; /* leads into noise */ + suffix[bufferSize] = (saidx_t)bufferSize; /* leads into noise */ + suffix0[0] = (saidx_t)bufferSize; /* leads into noise */ { /* build reverse suffix sort */ size_t pos; for (pos=0; pos < bufferSize; pos++) - reverseSuffix[suffix[pos]] = pos; + reverseSuffix[suffix[pos]] = (U32)pos; /* build file pos */ filePos[0] = 0; for (pos=1; pos diff --git a/dictBuilder/sssort.c b/dictBuilder/sssort.c index 4a18fd2ab..9e680fbff 100644 --- a/dictBuilder/sssort.c +++ b/dictBuilder/sssort.c @@ -24,6 +24,12 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +/*- Compiler specifics -*/ +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif + +/*- Dependencies -*/ #include "divsufsort_private.h" diff --git a/dictBuilder/trsort.c b/dictBuilder/trsort.c index 6fe3e67ba..b3c5cfa7a 100644 --- a/dictBuilder/trsort.c +++ b/dictBuilder/trsort.c @@ -24,6 +24,12 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +/*- Compiler specifics -*/ +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif + +/*- Dependencies -*/ #include "divsufsort_private.h" diff --git a/lib/huff0.c b/lib/huff0.c index 3e6107673..929bc87b1 100644 --- a/lib/huff0.c +++ b/lib/huff0.c @@ -129,10 +129,8 @@ size_t HUF_writeCTable (void* dst, size_t maxDstSize, size = FSE_compress(op+1, maxDstSize-1, huffWeight, maxSymbolValue); /* don't need last symbol stat : implied */ if (HUF_isError(size)) return size; if (size >= 128) return ERROR(GENERIC); /* should never happen, since maxSymbolValue <= 255 */ - if ((size <= 1) || (size >= maxSymbolValue/2)) - { - if (size==1) /* RLE */ - { + if ((size <= 1) || (size >= maxSymbolValue/2)) { + if (size==1) { /* RLE */ /* only possible case : serie of 1 (because there are at least 2) */ /* can only be 2^n or (2^n-1), otherwise not an huffman tree */ BYTE code; @@ -220,13 +218,11 @@ size_t HUF_readCTable (HUF_CElt* CTable, U32 maxSymbolValue, const void* src, si { /* determine stating value per rank */ U16 min = 0; - for (n=HUF_MAX_TABLELOG; n>0; n--) - { + for (n=HUF_MAX_TABLELOG; n>0; n--) { valPerRank[n] = min; /* get starting value within each rank */ min += nbPerRank[n]; min >>= 1; - } - } + } } for (n=0; n<=maxSymbolValue; n++) CTable[n].val = valPerRank[CTable[n].nbBits]++; /* assign value within rank, symbol order */ } @@ -248,8 +244,7 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) const U32 baseCost = 1 << (largestBits - maxNbBits); U32 n = lastNonNull; - while (huffNode[n].nbBits > maxNbBits) - { + while (huffNode[n].nbBits > maxNbBits) { totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits)); huffNode[n].nbBits = (BYTE)maxNbBits; n --; @@ -268,18 +263,15 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) /* Get pos of last (smallest) symbol per rank */ memset(rankLast, 0xF0, sizeof(rankLast)); - for (pos=n ; pos >= 0; pos--) - { + for (pos=n ; pos >= 0; pos--) { if (huffNode[pos].nbBits >= currentNbBits) continue; currentNbBits = huffNode[pos].nbBits; /* < maxNbBits */ rankLast[maxNbBits-currentNbBits] = pos; } - while (totalCost > 0) - { + while (totalCost > 0) { U32 nBitsToDecrease = BIT_highbit32(totalCost) + 1; - for ( ; nBitsToDecrease > 1; nBitsToDecrease--) - { + for ( ; nBitsToDecrease > 1; nBitsToDecrease--) { U32 highPos = rankLast[nBitsToDecrease]; U32 lowPos = rankLast[nBitsToDecrease-1]; if (highPos == noSymbol) continue; @@ -288,8 +280,7 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) U32 highTotal = huffNode[highPos].count; U32 lowTotal = 2 * huffNode[lowPos].count; if (highTotal <= lowTotal) break; - } - } + } } /* only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !) */ while ((nBitsToDecrease<=HUF_MAX_TABLELOG) && (rankLast[nBitsToDecrease] == noSymbol)) /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */ nBitsToDecrease ++; @@ -299,18 +290,14 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) huffNode[rankLast[nBitsToDecrease]].nbBits ++; if (rankLast[nBitsToDecrease] == 0) /* special case, reached largest symbol */ rankLast[nBitsToDecrease] = noSymbol; - else - { + else { rankLast[nBitsToDecrease]--; if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease) rankLast[nBitsToDecrease] = noSymbol; /* this rank is now empty */ - } - } + } } - while (totalCost < 0) /* Sometimes, cost correction overshoot */ - { - if (rankLast[1] == noSymbol) /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */ - { + while (totalCost < 0) { /* Sometimes, cost correction overshoot */ + if (rankLast[1] == noSymbol) { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */ while (huffNode[n].nbBits == maxNbBits) n--; huffNode[n+1].nbBits--; rankLast[1] = n+1; @@ -320,9 +307,7 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) huffNode[ rankLast[1] + 1 ].nbBits--; rankLast[1]++; totalCost ++; - } - } - } + } } } return maxNbBits; } @@ -339,15 +324,13 @@ static void HUF_sort(nodeElt* huffNode, const U32* count, U32 maxSymbolValue) U32 n; memset(rank, 0, sizeof(rank)); - for (n=0; n<=maxSymbolValue; n++) - { + for (n=0; n<=maxSymbolValue; n++) { U32 r = BIT_highbit32(count[n] + 1); rank[r].base ++; } for (n=30; n>0; n--) rank[n-1].base += rank[n].base; for (n=0; n<32; n++) rank[n].current = rank[n].base; - for (n=0; n<=maxSymbolValue; n++) - { + for (n=0; n<=maxSymbolValue; n++) { U32 c = count[n]; U32 r = BIT_highbit32(c+1) + 1; U32 pos = rank[r].current++; @@ -387,8 +370,7 @@ size_t HUF_buildCTable (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U3 huffNode0[0].count = (U32)(1U<<31); /* create parents */ - while (nodeNb <= nodeRoot) - { + while (nodeNb <= nodeRoot) { U32 n1 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++; U32 n2 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++; huffNode[nodeNb].count = huffNode[n1].count + huffNode[n2].count; @@ -416,8 +398,7 @@ size_t HUF_buildCTable (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U3 { /* determine stating value per rank */ U16 min = 0; - for (n=maxNbBits; n>0; n--) - { + for (n=maxNbBits; n>0; n--) { valPerRank[n] = min; /* get starting value within each rank */ min += nbPerRank[n]; min >>= 1; @@ -476,8 +457,7 @@ size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, si default: ; } - for (; n>0; n-=4) /* note : n&3==0 at this stage */ - { + for (; n>0; n-=4) { /* note : n&3==0 at this stage */ HUF_encodeSymbol(&bitC, ip[n- 1], CTable); HUF_FLUSHBITS_1(&bitC); HUF_encodeSymbol(&bitC, ip[n- 2], CTable); @@ -666,8 +646,7 @@ static size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, /* collect weight stats */ memset(rankStats, 0, (HUF_ABSOLUTEMAX_TABLELOG + 1) * sizeof(U32)); weightTotal = 0; - for (n=0; n= HUF_ABSOLUTEMAX_TABLELOG) return ERROR(corruption_detected); rankStats[huffWeight[n]]++; weightTotal += (1 << huffWeight[n]) >> 1; @@ -676,7 +655,7 @@ static size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, /* get last non-null symbol weight (implied, total must be 2^n) */ tableLog = BIT_highbit32(weightTotal) + 1; if (tableLog > HUF_ABSOLUTEMAX_TABLELOG) return ERROR(corruption_detected); - { + { /* determine last weight */ U32 total = 1 << tableLog; U32 rest = total - weightTotal; U32 verif = 1 << BIT_highbit32(rest); @@ -724,16 +703,14 @@ size_t HUF_readDTableX2 (U16* DTable, const void* src, size_t srcSize) /* Prepare ranks */ nextRankStart = 0; - for (n=1; n<=tableLog; n++) - { + for (n=1; n<=tableLog; n++) { U32 current = nextRankStart; nextRankStart += (rankVal[n] << (n-1)); rankVal[n] = current; } /* fill DTable */ - for (n=0; n> 1; U32 i; @@ -771,8 +748,7 @@ static inline size_t HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* const bitDPtr, B BYTE* const pStart = p; /* up to 4 symbols at a time */ - while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p <= pEnd-4)) - { + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p <= pEnd-4)) { HUF_DECODE_SYMBOLX2_2(p, bitDPtr); HUF_DECODE_SYMBOLX2_1(p, bitDPtr); HUF_DECODE_SYMBOLX2_2(p, bitDPtr); @@ -834,94 +810,91 @@ size_t HUF_decompress4X2_usingDTable( const void* cSrc, size_t cSrcSize, const U16* DTable) { + const BYTE* const istart = (const BYTE*) cSrc; + BYTE* const ostart = (BYTE*) dst; + BYTE* const oend = ostart + dstSize; + const void* const dtPtr = DTable; + const HUF_DEltX2* const dt = ((const HUF_DEltX2*)dtPtr) +1; + const U32 dtLog = DTable[0]; + size_t errorCode; + + /* Check */ if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ - { - const BYTE* const istart = (const BYTE*) cSrc; - BYTE* const ostart = (BYTE*) dst; - BYTE* const oend = ostart + dstSize; - const void* const dtPtr = DTable; - const HUF_DEltX2* const dt = ((const HUF_DEltX2*)dtPtr) +1; - const U32 dtLog = DTable[0]; - size_t errorCode; + /* Init */ + BIT_DStream_t bitD1; + BIT_DStream_t bitD2; + BIT_DStream_t bitD3; + BIT_DStream_t bitD4; + const size_t length1 = MEM_readLE16(istart); + const size_t length2 = MEM_readLE16(istart+2); + const size_t length3 = MEM_readLE16(istart+4); + size_t length4; + const BYTE* const istart1 = istart + 6; /* jumpTable */ + const BYTE* const istart2 = istart1 + length1; + const BYTE* const istart3 = istart2 + length2; + const BYTE* const istart4 = istart3 + length3; + const size_t segmentSize = (dstSize+3) / 4; + BYTE* const opStart2 = ostart + segmentSize; + BYTE* const opStart3 = opStart2 + segmentSize; + BYTE* const opStart4 = opStart3 + segmentSize; + BYTE* op1 = ostart; + BYTE* op2 = opStart2; + BYTE* op3 = opStart3; + BYTE* op4 = opStart4; + U32 endSignal; - /* Init */ - BIT_DStream_t bitD1; - BIT_DStream_t bitD2; - BIT_DStream_t bitD3; - BIT_DStream_t bitD4; - const size_t length1 = MEM_readLE16(istart); - const size_t length2 = MEM_readLE16(istart+2); - const size_t length3 = MEM_readLE16(istart+4); - size_t length4; - const BYTE* const istart1 = istart + 6; /* jumpTable */ - const BYTE* const istart2 = istart1 + length1; - const BYTE* const istart3 = istart2 + length2; - const BYTE* const istart4 = istart3 + length3; - const size_t segmentSize = (dstSize+3) / 4; - BYTE* const opStart2 = ostart + segmentSize; - BYTE* const opStart3 = opStart2 + segmentSize; - BYTE* const opStart4 = opStart3 + segmentSize; - BYTE* op1 = ostart; - BYTE* op2 = opStart2; - BYTE* op3 = opStart3; - BYTE* op4 = opStart4; - U32 endSignal; + length4 = cSrcSize - (length1 + length2 + length3 + 6); + if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ + errorCode = BIT_initDStream(&bitD1, istart1, length1); + if (HUF_isError(errorCode)) return errorCode; + errorCode = BIT_initDStream(&bitD2, istart2, length2); + if (HUF_isError(errorCode)) return errorCode; + errorCode = BIT_initDStream(&bitD3, istart3, length3); + if (HUF_isError(errorCode)) return errorCode; + errorCode = BIT_initDStream(&bitD4, istart4, length4); + if (HUF_isError(errorCode)) return errorCode; - length4 = cSrcSize - (length1 + length2 + length3 + 6); - if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ - errorCode = BIT_initDStream(&bitD1, istart1, length1); - if (HUF_isError(errorCode)) return errorCode; - errorCode = BIT_initDStream(&bitD2, istart2, length2); - if (HUF_isError(errorCode)) return errorCode; - errorCode = BIT_initDStream(&bitD3, istart3, length3); - if (HUF_isError(errorCode)) return errorCode; - errorCode = BIT_initDStream(&bitD4, istart4, length4); - if (HUF_isError(errorCode)) return errorCode; - - /* 16-32 symbols per loop (4-8 symbols per stream) */ + /* 16-32 symbols per loop (4-8 symbols per stream) */ + endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); + for ( ; (endSignal==BIT_DStream_unfinished) && (op4<(oend-7)) ; ) { + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_1(op1, &bitD1); + HUF_DECODE_SYMBOLX2_1(op2, &bitD2); + HUF_DECODE_SYMBOLX2_1(op3, &bitD3); + HUF_DECODE_SYMBOLX2_1(op4, &bitD4); + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_0(op1, &bitD1); + HUF_DECODE_SYMBOLX2_0(op2, &bitD2); + HUF_DECODE_SYMBOLX2_0(op3, &bitD3); + HUF_DECODE_SYMBOLX2_0(op4, &bitD4); endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); - for ( ; (endSignal==BIT_DStream_unfinished) && (op4<(oend-7)) ; ) - { - HUF_DECODE_SYMBOLX2_2(op1, &bitD1); - HUF_DECODE_SYMBOLX2_2(op2, &bitD2); - HUF_DECODE_SYMBOLX2_2(op3, &bitD3); - HUF_DECODE_SYMBOLX2_2(op4, &bitD4); - HUF_DECODE_SYMBOLX2_1(op1, &bitD1); - HUF_DECODE_SYMBOLX2_1(op2, &bitD2); - HUF_DECODE_SYMBOLX2_1(op3, &bitD3); - HUF_DECODE_SYMBOLX2_1(op4, &bitD4); - HUF_DECODE_SYMBOLX2_2(op1, &bitD1); - HUF_DECODE_SYMBOLX2_2(op2, &bitD2); - HUF_DECODE_SYMBOLX2_2(op3, &bitD3); - HUF_DECODE_SYMBOLX2_2(op4, &bitD4); - HUF_DECODE_SYMBOLX2_0(op1, &bitD1); - HUF_DECODE_SYMBOLX2_0(op2, &bitD2); - HUF_DECODE_SYMBOLX2_0(op3, &bitD3); - HUF_DECODE_SYMBOLX2_0(op4, &bitD4); - - endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); - } - - /* check corruption */ - if (op1 > opStart2) return ERROR(corruption_detected); - if (op2 > opStart3) return ERROR(corruption_detected); - if (op3 > opStart4) return ERROR(corruption_detected); - /* note : op4 supposed already verified within main loop */ - - /* finish bitStreams one by one */ - HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog); - HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog); - HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog); - HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog); - - /* check */ - endSignal = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4); - if (!endSignal) return ERROR(corruption_detected); - - /* decoded size */ - return dstSize; } + + /* check corruption */ + if (op1 > opStart2) return ERROR(corruption_detected); + if (op2 > opStart3) return ERROR(corruption_detected); + if (op3 > opStart4) return ERROR(corruption_detected); + /* note : op4 supposed already verified within main loop */ + + /* finish bitStreams one by one */ + HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog); + HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog); + HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog); + HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog); + + /* check */ + endSignal = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4); + if (!endSignal) return ERROR(corruption_detected); + + /* decoded size */ + return dstSize; } @@ -958,8 +931,7 @@ static void HUF_fillDTableX4Level2(HUF_DEltX4* DTable, U32 sizeLog, const U32 co memcpy(rankVal, rankValOrigin, sizeof(rankVal)); /* fill skipped values */ - if (minWeight>1) - { + if (minWeight>1) { U32 i, skipSize = rankVal[minWeight]; MEM_writeLE16(&(DElt.sequence), baseSeq); DElt.nbBits = (BYTE)(consumed); @@ -969,8 +941,7 @@ static void HUF_fillDTableX4Level2(HUF_DEltX4* DTable, U32 sizeLog, const U32 co } /* fill DTable */ - for (s=0; s= minBits) /* enough room for a second symbol */ - { + if (targetLog-nbBits >= minBits) { /* enough room for a second symbol */ U32 sortedRank; int minWeight = nbBits + scaleLog; if (minWeight < 1) minWeight = 1; @@ -1021,9 +990,7 @@ static void HUF_fillDTableX4(HUF_DEltX4* DTable, const U32 targetLog, rankValOrigin[nbBits], minWeight, sortedList+sortedRank, sortedListSize-sortedRank, nbBitsBaseline, symbol); - } - else - { + } else { U32 i; const U32 end = start + length; HUF_DEltX4 DElt; @@ -1068,8 +1035,7 @@ size_t HUF_readDTableX4 (U32* DTable, const void* src, size_t srcSize) /* Get start index of each weight */ { U32 w, nextRankStart = 0; - for (w=1; w<=maxW; w++) - { + for (w=1; w<=maxW; w++) { U32 current = nextRankStart; nextRankStart += rankStats[w]; rankStart[w] = current; @@ -1081,8 +1047,7 @@ size_t HUF_readDTableX4 (U32* DTable, const void* src, size_t srcSize) /* sort symbols by weight */ { U32 s; - for (s=0; s> consumed; - } - } - } + } } } HUF_fillDTableX4(dt, memLog, sortedSymbol, sizeOfSort, @@ -1136,15 +1096,12 @@ static U32 HUF_decodeLastSymbolX4(void* op, BIT_DStream_t* DStream, const HUF_DE const size_t val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ memcpy(op, dt+val, 1); if (dt[val].length==1) BIT_skipBits(DStream, dt[val].nbBits); - else - { - if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) - { + else { + if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) { BIT_skipBits(DStream, dt[val].nbBits); if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8)) DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8); /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */ - } - } + } } return 1; } @@ -1165,8 +1122,7 @@ static inline size_t HUF_decodeStreamX4(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* c BYTE* const pStart = p; /* up to 8 symbols at a time */ - while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p < pEnd-7)) - { + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p < pEnd-7)) { HUF_DECODE_SYMBOLX4_2(p, bitDPtr); HUF_DECODE_SYMBOLX4_1(p, bitDPtr); HUF_DECODE_SYMBOLX4_2(p, bitDPtr); @@ -1282,8 +1238,7 @@ size_t HUF_decompress4X4_usingDTable( /* 16-32 symbols per loop (4-8 symbols per stream) */ endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); - for ( ; (endSignal==BIT_DStream_unfinished) && (op4<(oend-7)) ; ) - { + for ( ; (endSignal==BIT_DStream_unfinished) && (op4<(oend-7)) ; ) { HUF_DECODE_SYMBOLX4_2(op1, &bitD1); HUF_DECODE_SYMBOLX4_2(op2, &bitD2); HUF_DECODE_SYMBOLX4_2(op3, &bitD3); @@ -1363,22 +1318,18 @@ static void HUF_fillDTableX6LevelN(HUF_DDescX6* DDescription, HUF_DSeqX6* DSeque memcpy(rankVal, rankValOrigin[consumed], sizeof(rankVal)); /* fill skipped values */ - if (minWeight>1) - { + if (minWeight>1) { U32 i; const U32 skipSize = rankVal[minWeight]; - for (i = 0; i < skipSize; i++) - { + for (i = 0; i < skipSize; i++) { DSequence[i] = baseSeq; DDescription[i] = DDesc; - } - } + } } /* fill DTable */ DDesc.nbBytes++; symbolStartPos = rankStart[minWeight]; - for (s=symbolStartPos; s= 1 (sorted) */ const int nbBits = nbBitsBaseline - weight; /* >= 1 (by construction) */ @@ -1388,25 +1339,20 @@ static void HUF_fillDTableX6LevelN(HUF_DDescX6* DDescription, HUF_DSeqX6* DSeque baseSeq.byte[level] = symbol; DDesc.nbBits = (BYTE)totalBits; - if ((level<3) && (sizeLog-totalBits >= minBits)) /* enough room for another symbol */ - { + if ((level<3) && (sizeLog-totalBits >= minBits)) { /* enough room for another symbol */ int nextMinWeight = totalBits + scaleLog; if (nextMinWeight < 1) nextMinWeight = 1; HUF_fillDTableX6LevelN(DDescription+start, DSequence+start, sizeLog-nbBits, rankValOrigin, totalBits, nextMinWeight, maxWeight, sortedSymbols, sortedListSize, rankStart, nbBitsBaseline, baseSeq, DDesc); /* recursive (max : level 3) */ - } - else - { + } else { U32 i; const U32 end = start + length; - for (i = start; i < end; i++) - { + for (i = start; i < end; i++) { DDescription[i] = DDesc; DSequence[i] = baseSeq; - } - } + } } rankVal[weight] += length; } } @@ -1440,8 +1386,7 @@ size_t HUF_readDTableX6 (U32* DTable, const void* src, size_t srcSize) /* Get start index of each weight */ { U32 w, nextRankStart = 0; - for (w=1; w<=maxW; w++) - { + for (w=1; w<=maxW; w++) { U32 current = nextRankStart; nextRankStart += rankStats[w]; rankStart[w] = current; @@ -1453,8 +1398,7 @@ size_t HUF_readDTableX6 (U32* DTable, const void* src, size_t srcSize) /* sort symbols by weight */ { U32 s; - for (s=0; s> consumed; - } - } - } + } } } /* fill tables */ { @@ -1520,15 +1459,13 @@ static U32 HUF_decodeLastSymbolsX6(void* op, const U32 maxL, BIT_DStream_t* DStr { const size_t val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ U32 length = dd[val].nbBytes; - if (length <= maxL) - { + if (length <= maxL) { memcpy(op, ds+val, length); BIT_skipBits(DStream, dd[val].nbBits); return length; } memcpy(op, ds+val, maxL); - if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) - { + if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) { BIT_skipBits(DStream, dd[val].nbBits); if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8)) DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8); /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */ @@ -1557,8 +1494,7 @@ static inline size_t HUF_decodeStreamX6(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* c BYTE* const pStart = p; /* up to 16 symbols at a time */ - while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p <= pEnd-16)) - { + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p <= pEnd-16)) { HUF_DECODE_SYMBOLX6_2(p, bitDPtr); HUF_DECODE_SYMBOLX6_1(p, bitDPtr); HUF_DECODE_SYMBOLX6_2(p, bitDPtr); @@ -1623,97 +1559,95 @@ size_t HUF_decompress4X6_usingDTable( const void* cSrc, size_t cSrcSize, const U32* DTable) { + const BYTE* const istart = (const BYTE*) cSrc; + BYTE* const ostart = (BYTE*) dst; + BYTE* const oend = ostart + dstSize; + + const U32 dtLog = DTable[0]; + const void* const ddPtr = DTable+1; + const HUF_DDescX6* dd = (const HUF_DDescX6*)ddPtr; + const void* const dsPtr = DTable + 1 + ((size_t)1<<(dtLog-1)); + const HUF_DSeqX6* ds = (const HUF_DSeqX6*)dsPtr; + size_t errorCode; + + /* Check */ if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ - { - const BYTE* const istart = (const BYTE*) cSrc; - BYTE* const ostart = (BYTE*) dst; - BYTE* const oend = ostart + dstSize; + /* Init */ + BIT_DStream_t bitD1; + BIT_DStream_t bitD2; + BIT_DStream_t bitD3; + BIT_DStream_t bitD4; + const size_t length1 = MEM_readLE16(istart); + const size_t length2 = MEM_readLE16(istart+2); + const size_t length3 = MEM_readLE16(istart+4); + size_t length4; + const BYTE* const istart1 = istart + 6; /* jumpTable */ + const BYTE* const istart2 = istart1 + length1; + const BYTE* const istart3 = istart2 + length2; + const BYTE* const istart4 = istart3 + length3; + const size_t segmentSize = (dstSize+3) / 4; + BYTE* const opStart2 = ostart + segmentSize; + BYTE* const opStart3 = opStart2 + segmentSize; + BYTE* const opStart4 = opStart3 + segmentSize; + BYTE* op1 = ostart; + BYTE* op2 = opStart2; + BYTE* op3 = opStart3; + BYTE* op4 = opStart4; + U32 endSignal; - const U32 dtLog = DTable[0]; - const void* const ddPtr = DTable+1; - const HUF_DDescX6* dd = (const HUF_DDescX6*)ddPtr; - const void* const dsPtr = DTable + 1 + ((size_t)1<<(dtLog-1)); - const HUF_DSeqX6* ds = (const HUF_DSeqX6*)dsPtr; - size_t errorCode; + length4 = cSrcSize - (length1 + length2 + length3 + 6); + if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ + errorCode = BIT_initDStream(&bitD1, istart1, length1); + if (HUF_isError(errorCode)) return errorCode; + errorCode = BIT_initDStream(&bitD2, istart2, length2); + if (HUF_isError(errorCode)) return errorCode; + errorCode = BIT_initDStream(&bitD3, istart3, length3); + if (HUF_isError(errorCode)) return errorCode; + errorCode = BIT_initDStream(&bitD4, istart4, length4); + if (HUF_isError(errorCode)) return errorCode; - /* Init */ - BIT_DStream_t bitD1; - BIT_DStream_t bitD2; - BIT_DStream_t bitD3; - BIT_DStream_t bitD4; - const size_t length1 = MEM_readLE16(istart); - const size_t length2 = MEM_readLE16(istart+2); - const size_t length3 = MEM_readLE16(istart+4); - size_t length4; - const BYTE* const istart1 = istart + 6; /* jumpTable */ - const BYTE* const istart2 = istart1 + length1; - const BYTE* const istart3 = istart2 + length2; - const BYTE* const istart4 = istart3 + length3; - const size_t segmentSize = (dstSize+3) / 4; - BYTE* const opStart2 = ostart + segmentSize; - BYTE* const opStart3 = opStart2 + segmentSize; - BYTE* const opStart4 = opStart3 + segmentSize; - BYTE* op1 = ostart; - BYTE* op2 = opStart2; - BYTE* op3 = opStart3; - BYTE* op4 = opStart4; - U32 endSignal; + /* 16-64 symbols per loop (4-16 symbols per stream) */ + endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); + for ( ; (op3 <= opStart4) && (endSignal==BIT_DStream_unfinished) && (op4<=(oend-16)) ; ) { + HUF_DECODE_SYMBOLX6_2(op1, &bitD1); + HUF_DECODE_SYMBOLX6_2(op2, &bitD2); + HUF_DECODE_SYMBOLX6_2(op3, &bitD3); + HUF_DECODE_SYMBOLX6_2(op4, &bitD4); + HUF_DECODE_SYMBOLX6_1(op1, &bitD1); + HUF_DECODE_SYMBOLX6_1(op2, &bitD2); + HUF_DECODE_SYMBOLX6_1(op3, &bitD3); + HUF_DECODE_SYMBOLX6_1(op4, &bitD4); + HUF_DECODE_SYMBOLX6_2(op1, &bitD1); + HUF_DECODE_SYMBOLX6_2(op2, &bitD2); + HUF_DECODE_SYMBOLX6_2(op3, &bitD3); + HUF_DECODE_SYMBOLX6_2(op4, &bitD4); + HUF_DECODE_SYMBOLX6_0(op1, &bitD1); + HUF_DECODE_SYMBOLX6_0(op2, &bitD2); + HUF_DECODE_SYMBOLX6_0(op3, &bitD3); + HUF_DECODE_SYMBOLX6_0(op4, &bitD4); - length4 = cSrcSize - (length1 + length2 + length3 + 6); - if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ - errorCode = BIT_initDStream(&bitD1, istart1, length1); - if (HUF_isError(errorCode)) return errorCode; - errorCode = BIT_initDStream(&bitD2, istart2, length2); - if (HUF_isError(errorCode)) return errorCode; - errorCode = BIT_initDStream(&bitD3, istart3, length3); - if (HUF_isError(errorCode)) return errorCode; - errorCode = BIT_initDStream(&bitD4, istart4, length4); - if (HUF_isError(errorCode)) return errorCode; - - /* 16-64 symbols per loop (4-16 symbols per stream) */ endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); - for ( ; (op3 <= opStart4) && (endSignal==BIT_DStream_unfinished) && (op4<=(oend-16)) ; ) - { - HUF_DECODE_SYMBOLX6_2(op1, &bitD1); - HUF_DECODE_SYMBOLX6_2(op2, &bitD2); - HUF_DECODE_SYMBOLX6_2(op3, &bitD3); - HUF_DECODE_SYMBOLX6_2(op4, &bitD4); - HUF_DECODE_SYMBOLX6_1(op1, &bitD1); - HUF_DECODE_SYMBOLX6_1(op2, &bitD2); - HUF_DECODE_SYMBOLX6_1(op3, &bitD3); - HUF_DECODE_SYMBOLX6_1(op4, &bitD4); - HUF_DECODE_SYMBOLX6_2(op1, &bitD1); - HUF_DECODE_SYMBOLX6_2(op2, &bitD2); - HUF_DECODE_SYMBOLX6_2(op3, &bitD3); - HUF_DECODE_SYMBOLX6_2(op4, &bitD4); - HUF_DECODE_SYMBOLX6_0(op1, &bitD1); - HUF_DECODE_SYMBOLX6_0(op2, &bitD2); - HUF_DECODE_SYMBOLX6_0(op3, &bitD3); - HUF_DECODE_SYMBOLX6_0(op4, &bitD4); - - endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); - } - - /* check corruption */ - if (op1 > opStart2) return ERROR(corruption_detected); - if (op2 > opStart3) return ERROR(corruption_detected); - if (op3 > opStart4) return ERROR(corruption_detected); - /* note : op4 supposed already verified within main loop */ - - /* finish bitStreams one by one */ - HUF_decodeStreamX6(op1, &bitD1, opStart2, DTable, dtLog); - HUF_decodeStreamX6(op2, &bitD2, opStart3, DTable, dtLog); - HUF_decodeStreamX6(op3, &bitD3, opStart4, DTable, dtLog); - HUF_decodeStreamX6(op4, &bitD4, oend, DTable, dtLog); - - /* check */ - endSignal = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4); - if (!endSignal) return ERROR(corruption_detected); - - /* decoded size */ - return dstSize; } + + /* check corruption */ + if (op1 > opStart2) return ERROR(corruption_detected); + if (op2 > opStart3) return ERROR(corruption_detected); + if (op3 > opStart4) return ERROR(corruption_detected); + /* note : op4 supposed already verified within main loop */ + + /* finish bitStreams one by one */ + HUF_decodeStreamX6(op1, &bitD1, opStart2, DTable, dtLog); + HUF_decodeStreamX6(op2, &bitD2, opStart3, DTable, dtLog); + HUF_decodeStreamX6(op3, &bitD3, opStart4, DTable, dtLog); + HUF_decodeStreamX6(op4, &bitD4, oend, DTable, dtLog); + + /* check */ + endSignal = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4); + if (!endSignal) return ERROR(corruption_detected); + + /* decoded size */ + return dstSize; } From 863ec40f1e163969a072453dbec9b1bdec5bce3f Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 28 Jan 2016 17:56:33 +0100 Subject: [PATCH 14/34] minor compression speed improvement --- dictBuilder/dictBuilder.c | 18 +++------ lib/fse.c | 9 ++--- lib/zstd_buffered.c | 66 +++++++++++-------------------- lib/zstd_compress.c | 83 ++++++++++++++++----------------------- 4 files changed, 66 insertions(+), 110 deletions(-) diff --git a/dictBuilder/dictBuilder.c b/dictBuilder/dictBuilder.c index b41259677..8bb100573 100644 --- a/dictBuilder/dictBuilder.c +++ b/dictBuilder/dictBuilder.c @@ -1,5 +1,5 @@ /* - dictBuilder.c + dictBuilder - dictionary builder for LZ algorithms Copyright (C) Yann Collet 2016 GPL v2 License @@ -20,7 +20,6 @@ You can contact the author at : - zstd source repository : https://github.com/Cyan4973/zstd - - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c */ /* ************************************** @@ -40,13 +39,8 @@ # define _LARGEFILE64_SOURCE #endif -/* S_ISREG & gettimeofday() are not supported by MSVC */ -#if defined(_MSC_VER) || defined(_WIN32) -# define BMK_LEGACY_TIMER 1 -#endif - -/* ************************************* +/*-************************************* * Includes ***************************************/ #include /* malloc, free */ @@ -75,7 +69,7 @@ #endif -/* ************************************* +/*-************************************* * Constants ***************************************/ #define KB *(1 <<10) @@ -93,8 +87,8 @@ static const size_t maxMemory = (sizeof(size_t)==4) ? (2 GB - 64 MB) : (size_t #define MINRATIO 4 -/* ************************************* -* console display +/*-************************************* +* Console display ***************************************/ #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) #define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } @@ -121,7 +115,7 @@ void DiB_printHex(U32 dlevel, const void* ptr, size_t length) } -/* ************************************* +/*-************************************* * Exceptions ***************************************/ #ifndef DEBUG diff --git a/lib/fse.c b/lib/fse.c index 61272a624..1f382ed10 100644 --- a/lib/fse.c +++ b/lib/fse.c @@ -1052,8 +1052,7 @@ size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits) /* Build Decoding Table */ DTableH->tableLog = (U16)nbBits; DTableH->fastMode = 1; - for (s=0; s<=maxSymbolValue; s++) - { + for (s=0; s<=maxSymbolValue; s++) { dinfo[s].newState = 0; dinfo[s].symbol = (BYTE)s; dinfo[s].nbBits = (BYTE)nbBits; @@ -1087,8 +1086,7 @@ FORCE_INLINE size_t FSE_decompress_usingDTable_generic( #define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD) /* 4 symbols per loop */ - for ( ; (BIT_reloadDStream(&bitD)==BIT_DStream_unfinished) && (op sizeof(bitD.bitContainer)*8) /* This test must be static */ @@ -1109,8 +1107,7 @@ FORCE_INLINE size_t FSE_decompress_usingDTable_generic( /* tail */ /* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */ - while (1) - { + while (1) { if ( (BIT_reloadDStream(&bitD)>BIT_DStream_completed) || (op==omax) || (BIT_endOfDStream(&bitD) && (fast || FSE_endOfDState(&state1))) ) break; diff --git a/lib/zstd_buffered.c b/lib/zstd_buffered.c index dc7b57490..2a8df235d 100644 --- a/lib/zstd_buffered.c +++ b/lib/zstd_buffered.c @@ -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) @@ -127,16 +127,14 @@ size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc, const void* dict, size_t dic neededInBuffSize = (size_t)1 << params.windowLog; /* allocate buffers */ - if (zbc->inBuffSize < neededInBuffSize) - { + if (zbc->inBuffSize < neededInBuffSize) { zbc->inBuffSize = neededInBuffSize; free(zbc->inBuff); /* should not be necessary */ zbc->inBuff = (char*)malloc(neededInBuffSize); if (zbc->inBuff == NULL) return ERROR(memory_allocation); } zbc->blockSize = MIN(BLOCKSIZE, zbc->inBuffSize); - if (zbc->outBuffSize < ZSTD_compressBound(zbc->blockSize)+1) - { + if (zbc->outBuffSize < ZSTD_compressBound(zbc->blockSize)+1) { zbc->outBuffSize = ZSTD_compressBound(zbc->blockSize)+1; free(zbc->outBuff); /* should not be necessary */ zbc->outBuff = (char*)malloc(zbc->outBuffSize); @@ -188,8 +186,7 @@ static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc, char* op = ostart; char* const oend = ostart + *maxDstSizePtr; - while (notDone) - { + while (notDone) { switch(zbc->stage) { case ZBUFFcs_init: return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */ @@ -201,9 +198,9 @@ static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc, size_t loaded = ZBUFF_limitCopy(zbc->inBuff + zbc->inBuffPos, toLoad, ip, iend-ip); zbc->inBuffPos += loaded; ip += loaded; - if ( (zbc->inBuffPos==zbc->inToCompress) || (!flush && (toLoad != loaded)) ) - { notDone = 0; break; } /* not enough input to get a full block : stop there, wait for more */ - } + if ( (zbc->inBuffPos==zbc->inToCompress) || (!flush && (toLoad != loaded)) ) { + notDone = 0; break; /* not enough input to get a full block : stop there, wait for more */ + } } /* compress current block (note : this stage cannot be stopped in the middle) */ { void* cDst; @@ -235,8 +232,7 @@ static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc, size_t flushed = ZBUFF_limitCopy(op, oend-op, zbc->outBuff + zbc->outBuffFlushedSize, toFlush); op += flushed; zbc->outBuffFlushedSize += flushed; - if (toFlush!=flushed) - { notDone = 0; break; } /* not enough space within dst to store compressed block : stop there */ + if (toFlush!=flushed) { notDone = 0; break; } /* not enough space within dst to store compressed block : stop there */ zbc->outBuffContentSize = 0; zbc->outBuffFlushedSize = 0; zbc->stage = ZBUFFcs_load; @@ -259,7 +255,9 @@ static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc, size_t ZBUFF_compressContinue(ZBUFF_CCtx* zbc, void* dst, size_t* maxDstSizePtr, const void* src, size_t* srcSizePtr) -{ return ZBUFF_compressContinue_generic(zbc, dst, maxDstSizePtr, src, srcSizePtr, 0); } +{ + return ZBUFF_compressContinue_generic(zbc, dst, maxDstSizePtr, src, srcSizePtr, 0); +} @@ -387,11 +385,9 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt char* const oend = ostart + *maxDstSizePtr; U32 notDone = 1; - while (notDone) - { + while (notDone) { switch(zbc->stage) { - case ZBUFFds_init : return ERROR(init_missing); @@ -400,8 +396,7 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt { size_t headerSize = ZSTD_getFrameParams(&(zbc->params), src, *srcSizePtr); if (ZSTD_isError(headerSize)) return headerSize; - if (headerSize) - { + if (headerSize) { /* not enough input to decode header : tell how many bytes would be necessary */ memcpy(zbc->headerBuffer+zbc->hPos, src, *srcSizePtr); zbc->hPos += *srcSizePtr; @@ -423,8 +418,7 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt 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; @@ -437,23 +431,19 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt { 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->hPos) - { + } } + if (zbc->hPos) { /* some data already loaded into headerBuffer : transfer into inBuff */ memcpy(zbc->inBuff, zbc->headerBuffer, zbc->hPos); zbc->inPos = zbc->hPos; @@ -466,14 +456,12 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt case ZBUFFds_read: { size_t neededInSize = ZSTD_nextSrcSizeToDecompress(zbc->zc); - if (neededInSize==0) /* end of frame */ - { + if (neededInSize==0) { /* end of frame */ zbc->stage = ZBUFFds_init; notDone = 0; break; } - if ((size_t)(iend-ip) >= neededInSize) - { + if ((size_t)(iend-ip) >= neededInSize) { /* directly decode from src */ size_t decodedSize = ZSTD_decompressContinue(zbc->zc, zbc->outBuff + zbc->outStart, zbc->outBuffSize - zbc->outStart, @@ -509,16 +497,14 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt zbc->outEnd = zbc->outStart + decodedSize; zbc->stage = ZBUFFds_flush; // break; /* ZBUFFds_flush follows */ - } - } + } } case ZBUFFds_flush: { size_t toFlushSize = zbc->outEnd - zbc->outStart; size_t flushedSize = ZBUFF_limitCopy(op, oend-op, zbc->outBuff + zbc->outStart, toFlushSize); op += flushedSize; zbc->outStart += flushedSize; - if (flushedSize == toFlushSize) - { + if (flushedSize == toFlushSize) { zbc->stage = ZBUFFds_read; if (zbc->outStart + BLOCKSIZE > zbc->outBuffSize) zbc->outStart = zbc->outEnd = 0; @@ -529,8 +515,7 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt break; } default: return ERROR(GENERIC); /* impossible */ - } - } + } } *srcSizePtr = ip-istart; *maxDstSizePtr = op-ostart; @@ -545,11 +530,6 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt - - - - - /* ************************************* * Tool functions ***************************************/ diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 2c67c8ae0..31eb15912 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -1,6 +1,6 @@ /* ZSTD HC - High Compression Mode of Zstandard - Copyright (C) 2015, Yann Collet. + Copyright (C) 2015-2016, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -181,29 +181,25 @@ void ZSTD_validateParams(ZSTD_parameters* params) static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, ZSTD_parameters params) -{ - /* note : params considered validated here */ +{ /* note : params considered validated here */ const size_t blockSize = MIN(BLOCKSIZE, (size_t)1 << params.windowLog); - /* 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); - if (zc->workSpaceSize < neededSpace) { - free(zc->workSpace); - zc->workSpace = malloc(neededSpace); - if (zc->workSpace == NULL) return ERROR(memory_allocation); - zc->workSpaceSize = neededSpace; - } - memset(zc->workSpace, 0, tableSpace ); /* reset only tables */ - zc->hashTable = (U32*)(zc->workSpace); - zc->contentTable = zc->hashTable + ((size_t)1 << params.hashLog); - zc->seqStore.buffer = zc->contentTable + ((size_t)1 << contentLog); - zc->hufTable = (HUF_CElt*)zc->seqStore.buffer; - zc->flagStaticTables = 0; - zc->seqStore.buffer = (U32*)(zc->seqStore.buffer) + 256; + 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); + if (zc->workSpaceSize < neededSpace) { + free(zc->workSpace); + zc->workSpace = malloc(neededSpace); + if (zc->workSpace == NULL) return ERROR(memory_allocation); + zc->workSpaceSize = neededSpace; } + memset(zc->workSpace, 0, tableSpace ); /* reset only tables */ + zc->hashTable = (U32*)(zc->workSpace); + zc->contentTable = zc->hashTable + ((size_t)1 << params.hashLog); + zc->seqStore.buffer = zc->contentTable + ((size_t)1 << contentLog); + zc->hufTable = (HUF_CElt*)zc->seqStore.buffer; + zc->flagStaticTables = 0; + zc->seqStore.buffer = (U32*)(zc->seqStore.buffer) + 256; zc->nextToUpdate = 1; zc->nextSrc = NULL; @@ -256,7 +252,7 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx) /* copy entropy tables */ dstCCtx->flagStaticTables = srcCCtx->flagStaticTables; - if (dstCCtx->flagStaticTables) { + if (srcCCtx->flagStaticTables) { memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4); memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable)); memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable)); @@ -267,7 +263,7 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx) } -/** ZSTD_reduceIndex +/*! ZSTD_reduceIndex * rescale indexes to avoid future overflow (indexes are U32) */ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue) @@ -284,7 +280,7 @@ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, } -/* ******************************************************* +/*-******************************************************* * Block entropic compression *********************************************************/ @@ -553,7 +549,7 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, MEM_writeLE16(op, (U16)nbSeq); op+=2; seqHead = op; - /* dumps : contains too large lengths */ + /* dumps : contains rests of large lengths */ { size_t dumpsLength = seqStorePtr->dumps - seqStorePtr->dumpsStart; if (dumpsLength < 512) { @@ -773,10 +769,8 @@ static unsigned ZSTD_highbit(U32 val) static unsigned ZSTD_NbCommonBytes (register size_t val) { - if (MEM_isLittleEndian()) - { - if (MEM_64bits()) - { + if (MEM_isLittleEndian()) { + if (MEM_64bits()) { # if defined(_MSC_VER) && defined(_WIN64) unsigned long r = 0; _BitScanForward64( &r, (U64)val ); @@ -787,9 +781,7 @@ static unsigned ZSTD_NbCommonBytes (register size_t val) 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 */ - { + } else { /* 32 bits */ # if defined(_MSC_VER) unsigned long r=0; _BitScanForward( &r, (U32)val ); @@ -801,11 +793,8 @@ static unsigned ZSTD_NbCommonBytes (register size_t val) return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; # endif } - } - else /* Big Endian CPU */ - { - if (MEM_64bits()) - { + } else { /* Big Endian CPU */ + if (MEM_64bits()) { # if defined(_MSC_VER) && defined(_WIN64) unsigned long r = 0; _BitScanReverse64( &r, val ); @@ -820,9 +809,7 @@ static unsigned ZSTD_NbCommonBytes (register size_t val) r += (!val); return r; # endif - } - else /* 32 bits */ - { + } else { /* 32 bits */ # if defined(_MSC_VER) unsigned long r = 0; _BitScanReverse( &r, (unsigned long)val ); @@ -835,8 +822,7 @@ static unsigned ZSTD_NbCommonBytes (register size_t val) r += (!val); return r; # endif - } - } + } } } @@ -874,24 +860,23 @@ static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE -/* ************************************* +/*-************************************* * Hashes ***************************************/ - static const U32 prime4bytes = 2654435761U; -static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; } +static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; } static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); } static const U64 prime5bytes = 889523592379ULL; -static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)((u * prime5bytes) << (64-40) >> (64-h)) ; } +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 const U64 prime6bytes = 227718039650203ULL; -static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)((u * prime6bytes) << (64-48) >> (64-h)) ; } +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 const U64 prime7bytes = 58295818150454627ULL; -static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)((u * prime7bytes) << (64-56) >> (64-h)) ; } +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_hashPtr(const void* p, U32 hBits, U32 mls) @@ -906,10 +891,10 @@ static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) } } + /* ************************************* * Fast Scan ***************************************/ - #define FILLHASHSTEP 3 static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls) { From f5229e0cd8a9b7f1121c3c848e301b0354ce3dad Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 29 Jan 2016 02:45:26 +0100 Subject: [PATCH 15/34] added fast sampling mode --- dictBuilder/dibcli.c | 102 +++++++++++++----------------- dictBuilder/dictBuilder.c | 129 +++++++++++++++++++++++++++----------- dictBuilder/dictBuilder.h | 13 ++-- 3 files changed, 144 insertions(+), 100 deletions(-) diff --git a/dictBuilder/dibcli.c b/dictBuilder/dibcli.c index 434053482..121620943 100644 --- a/dictBuilder/dibcli.c +++ b/dictBuilder/dibcli.c @@ -20,43 +20,19 @@ You can contact the author at : - zstd source repository : https://github.com/Cyan4973/zstd - - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c */ - -/************************************** -* 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 */ #include /* exit, calloc, free */ #include /* strcmp, strlen */ +#include /* fprintf, getchar */ #include "dictBuilder.h" -/************************************** -* OS-specific Includes -**************************************/ -#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) -# include /* _O_BINARY */ -# include /* _setmode, _isatty */ -# define SET_BINARY_MODE(file) _setmode(_fileno(file), _O_BINARY) -# define IS_CONSOLE(stdStream) _isatty(_fileno(stdStream)) -#else -# include /* isatty */ -# define SET_BINARY_MODE(file) -# define IS_CONSOLE(stdStream) isatty(fileno(stdStream)) -#endif - - -/************************************** +/*-************************************ * Constants **************************************/ #define PROGRAM_DESCRIPTION "Dictionary builder" @@ -72,21 +48,22 @@ #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(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 +#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 @@ -101,7 +78,7 @@ static unsigned displayLevel = 2; // 0 : no display // 1: errors // 2 : + re } -/************************************** +/*-************************************ * Command Line **************************************/ static int usage(const char* programName) @@ -110,8 +87,8 @@ static int usage(const char* programName) DISPLAY( " %s [arg] [filenames]\n", programName); DISPLAY( "\n"); DISPLAY( "Arguments :\n"); - DISPLAY( "--maxdict : limit dictionary to specified size (default : %u) \n", maxDictSizeDefault); 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; } @@ -122,8 +99,10 @@ static int usage_advanced(const char* programName) usage(programName); DISPLAY( "\n"); DISPLAY( "Advanced arguments :\n"); - DISPLAY( " -# : selection level # (default :%u)\n", selectionLevelDefault); 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 warnings; specify twice to suppress errors too\n"); return 0; @@ -132,7 +111,7 @@ static int usage_advanced(const char* programName) static int badusage(const char* programName) { DISPLAYLEVEL(1, "Incorrect parameters\n"); - if (displayLevel >= 1) usage(programName); + if (g_displayLevel >= 1) usage(programName); return 1; } @@ -153,6 +132,7 @@ int main(int argCount, const char** argv) 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 */ @@ -161,7 +141,7 @@ int main(int argCount, const char** argv) const char* dictFileName = dictFileNameDefault; /* init */ - displayOut = stderr; /* unfortunately, cannot be set at declaration */ + 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; } } @@ -190,40 +170,44 @@ 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, "--verbose")) { displayLevel=4; continue; } - if (!strcmp(argument, "--quiet")) { displayLevel--; continue; } + 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=0; cLevel=1; continue; } /* Decode commands (note : aggregated commands are allowed) */ if (argument[0]=='-') { argument++; while (argument[0]!=0) { - /* selection Level */ - if ((*argument>='0') && (*argument<='9')) { - selectionLevel = 0; - while ((*argument >= '0') && (*argument <= '9')) { - selectionLevel *= 10; - selectionLevel += *argument - '0'; - argument++; - } - continue; - } - switch(argument[0]) { /* Display help */ - case 'V': displayOut=stdout; DISPLAY(WELCOME_MESSAGE); return 0; /* Version Only */ + case 'V': g_displayOut=stdout; DISPLAY(WELCOME_MESSAGE); return 0; /* Version Only */ case 'H': - case 'h': displayOut=stdout; return usage_advanced(programName); + 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': displayLevel++; if (displayLevel<3) displayLevel=3; argument++; break; + case 'v': g_displayLevel++; if (g_displayLevel<3) g_displayLevel=3; argument++; break; /* Quiet mode */ - case 'q': displayLevel--; argument++; break; + case 'q': g_displayLevel--; argument++; break; /* dictionary name */ case 'o': nextArgumentIsDictFileName=1; argument++; break; @@ -247,8 +231,8 @@ int main(int argCount, const char** argv) if (filenameIdx==0) return badusage(programName); /* building ... */ - DiB_setNotificationLevel(displayLevel); - operationResult = DiB_trainDictionary(dictFileName, maxDictSize, selectionLevel, filenameTable, filenameIdx); + DiB_setNotificationLevel(g_displayLevel); + operationResult = DiB_trainDictionary(dictFileName, maxDictSize, selectionLevel, cLevel, filenameTable, filenameIdx); if (main_pause) waitEnter(); free((void*)filenameTable); diff --git a/dictBuilder/dictBuilder.c b/dictBuilder/dictBuilder.c index 8bb100573..4abae9fd4 100644 --- a/dictBuilder/dictBuilder.c +++ b/dictBuilder/dictBuilder.c @@ -51,6 +51,7 @@ #include /* clock */ #include "mem.h" /* read */ +#include "error_private.h" #include "divsufsort.h" #include "dictBuilder.h" #include "zstd_compress.c" @@ -85,6 +86,7 @@ static const size_t maxMemory = (sizeof(size_t)==4) ? (2 GB - 64 MB) : (size_t #define PRIME2 2246822519U #define MINRATIO 4 +static const U32 g_compressionLevel_default = 5; /*-************************************* @@ -714,6 +716,7 @@ static void DiB_countEStats(EStats_ress_t esr, #define OFFCODE_MAX 18 static size_t DiB_analyzeEntropy(void* dstBuffer, size_t maxDstSize, + unsigned compressionLevel, const void* srcBuffer, size_t* fileSizes, unsigned nbFiles, const void* dictBuffer, size_t dictBufferSize) { @@ -740,7 +743,8 @@ static size_t DiB_analyzeEntropy(void* dstBuffer, size_t maxDstSize, esr.zc = ZSTD_createCCtx(); esr.workPlace = malloc(BLOCKSIZE); if (!esr.ref || !esr.zc || !esr.workPlace) EXM_THROW(30, "Not enough memory"); - params = ZSTD_getParams(5, dictBufferSize + 15 KB); + if (compressionLevel==0) compressionLevel=g_compressionLevel_default; + params = ZSTD_getParams(compressionLevel, dictBufferSize + 15 KB); params.strategy = ZSTD_greedy; ZSTD_compressBegin_advanced(esr.ref, dictBuffer, dictBufferSize, params); @@ -827,8 +831,49 @@ static void DiB_saveDict(const char* dictFileName, } -int DiB_trainDictionary(const char* dictFileName, unsigned maxDictSize, unsigned shiftRatio, - const char** fileNamesTable, unsigned nbFiles) +#define DIB_FASTSEGMENTSIZE 64 +/*! DiB_fastSampling (based on an idea 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 + or an error Code (if @dictSize or @samplesSize too small) +*/ +static size_t DiB_fastSampling(void* dictBuffer, size_t dictSize, + const void* samplesBuffer, size_t samplesSize) +{ + char* dstPtr = (char*)dictBuffer + dictSize; + const char* srcPtr = (const char*)samplesBuffer; + size_t nbSegments = dictSize / DIB_FASTSEGMENTSIZE; + size_t segNb, interSize; + + if (nbSegments <= 2) return ERROR(srcSize_wrong); + if (samplesSize < dictSize) return ERROR(srcSize_wrong); + + /* first and last segments are part of dictionary, in case they contain interesting header/footer */ + dstPtr -= DIB_FASTSEGMENTSIZE; + memcpy(dstPtr, srcPtr, DIB_FASTSEGMENTSIZE); + dstPtr -= DIB_FASTSEGMENTSIZE; + memcpy(dstPtr, srcPtr+samplesSize-DIB_FASTSEGMENTSIZE, DIB_FASTSEGMENTSIZE); + + /* regularly copy a segment */ + interSize = (samplesSize - nbSegments*DIB_FASTSEGMENTSIZE) / (nbSegments-1); + srcPtr += DIB_FASTSEGMENTSIZE; + for (segNb=2; segNb < nbSegments; segNb++) { + srcPtr += interSize; + dstPtr -= DIB_FASTSEGMENTSIZE; + memcpy(dstPtr, srcPtr, DIB_FASTSEGMENTSIZE); + srcPtr += DIB_FASTSEGMENTSIZE; + } + + return nbSegments * DIB_FASTSEGMENTSIZE; +} + + +int DiB_trainDictionary(const char* dictFileName, unsigned maxDictSize, + unsigned shiftRatio, unsigned compressionLevel, + const char** fileNamesTable, unsigned nbFiles) { void* srcBuffer; size_t benchedSize; @@ -852,42 +897,44 @@ int DiB_trainDictionary(const char* dictFileName, unsigned maxDictSize, unsigned /* Load input buffer */ DiB_loadFiles(srcBuffer, benchedSize, fileSizes, fileNamesTable, nbFiles); - DiB_fillNoise((char*)srcBuffer + benchedSize, NOISELENGTH); /* for end of buffer condition */ + DiB_fillNoise((char*)srcBuffer + benchedSize, NOISELENGTH); /* guard band, for end of buffer condition */ - /* Train */ - snprintf (mfName, sizeof(mfName), " %u files", nbFiles); - if (nbFiles > 1) displayName = mfName; - else displayName = fileNamesTable[0]; + if (shiftRatio>0) + { + /* analyze samples */ + snprintf (mfName, sizeof(mfName), " %u files", nbFiles); + if (nbFiles > 1) displayName = mfName; + else displayName = fileNamesTable[0]; - DiB_trainBuffer(dictList, dictListSize, - srcBuffer, benchedSize, - displayName, - fileSizes, nbFiles, maxDictSize, - shiftRatio); + DiB_trainBuffer(dictList, dictListSize, + srcBuffer, benchedSize, + displayName, + fileSizes, nbFiles, maxDictSize, + shiftRatio); - /* display best matches */ - if (g_displayLevel>= 3) { - const U32 nb = 25; - U32 u; - U32 dictContentSize = DiB_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++) { - U32 p = dictList[u].pos; - U32 l = dictList[u].length; - 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, (char*)srcBuffer+p, d); - DISPLAYLEVEL(3, "| \n"); - } } + /* display best matches */ + if (g_displayLevel>= 3) { + const U32 nb = 25; + U32 u; + U32 dictContentSize = DiB_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++) { + U32 p = dictList[u].pos; + U32 l = dictList[u].length; + 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, (char*)srcBuffer+p, d); + DISPLAYLEVEL(3, "| \n"); + } } } /* create dictionary */ { void* dictContent; U32 dictContentSize = DiB_dictSize(dictList); void* dictHeader; - size_t dictHeaderSize, hSize; + size_t dictHeaderSize, hSize, addedContentLength; BYTE* ptr; U32 u; @@ -895,18 +942,27 @@ int DiB_trainDictionary(const char* dictFileName, unsigned maxDictSize, unsigned #define EBSIZE (2 KB) dictHeaderSize = EBSIZE; dictHeader = malloc(dictHeaderSize); - dictContent = malloc(dictContentSize); + dictContent = malloc(maxDictSize); if (!dictHeader || !dictContent) EXM_THROW(2, "not enough memory"); /* build dict content */ - ptr = (BYTE*)dictContent + dictContentSize; - + ptr = (BYTE*)dictContent + maxDictSize; for (u=1; upos; u++) { U32 l = dictList[u].length; ptr -= l; memcpy(ptr, (char*)srcBuffer+dictList[u].pos, l); } + /* fast dict content mode */ + if (shiftRatio==0) { + addedContentLength = ptr-(BYTE*)dictContent; + DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */ + DISPLAYLEVEL(2, "Adding %u KB from fast sampling \n", (U32)(addedContentLength>>10)); + addedContentLength = DiB_fastSampling(dictContent, addedContentLength, srcBuffer, benchedSize); + if (!ERR_isError(addedContentLength)) + ptr -= addedContentLength, dictContentSize += addedContentLength; + } + /* dictionary header */ MEM_writeLE32(dictHeader, ZSTD_DICT_MAGIC); hSize = 4; @@ -915,14 +971,15 @@ int DiB_trainDictionary(const char* dictFileName, unsigned maxDictSize, unsigned /* entropic tables */ DISPLAYLEVEL(2, "statistics ... \n"); hSize += DiB_analyzeEntropy((char*)dictHeader+4, dictHeaderSize, - srcBuffer, fileSizes, nbFiles, - dictContent, dictContentSize); + compressionLevel, + srcBuffer, fileSizes, nbFiles, + ptr, dictContentSize); /* save dict */ { size_t dictSize = hSize + dictContentSize; DISPLAYLEVEL(2, "Save dictionary of size %u into file %s \n", (U32)dictSize, dictFileName); - DiB_saveDict(dictFileName, dictHeader, hSize, dictContent, dictContentSize); + DiB_saveDict(dictFileName, dictHeader, hSize, ptr, dictContentSize); //DiB_saveDict(dictFileName, NULL, 0, dictContent, dictContentSize); // content only } /* clean */ diff --git a/dictBuilder/dictBuilder.h b/dictBuilder/dictBuilder.h index 74fa2b0c0..3c52c7daa 100644 --- a/dictBuilder/dictBuilder.h +++ b/dictBuilder/dictBuilder.h @@ -24,7 +24,7 @@ */ /* This library is designed for a single-threaded console application. -* It abruptly exits (exit() function) when it encounters an error condition. */ +* It exit() and printf() into stderr when it encounters an error condition. */ /*-************************************* * Version @@ -37,14 +37,17 @@ unsigned DiB_versionNumber (void); /*-************************************* -* Main functions +* Public functions ***************************************/ /*! DiB_trainDictionary Train a dictionary from a set of files provided by @fileNamesTable - Resulting dictionary is written in file @dictFileName - @result : 0 if fine + Resulting dictionary is written in file @dictFileName. + @selectivityLevel change criteria for insertion into the dictionary (more => bigger selection => larger dictionary) + @compressionLevel can be used to target a specific compression level of zstd. 0 means "default". + @result : 0 == ok */ -int DiB_trainDictionary(const char* dictFileName, unsigned maxDictSize, unsigned selectivityLevel, +int DiB_trainDictionary(const char* dictFileName, unsigned maxDictSize, + unsigned selectivityLevel, unsigned compressionLevel, const char** fileNamesTable, unsigned nbFiles); From c8383350625a733e9d0d71ab3bf1f0e76ecc8cbc Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 29 Jan 2016 15:25:11 +0100 Subject: [PATCH 16/34] added warning message (too few samples) --- dictBuilder/dibcli.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dictBuilder/dibcli.c b/dictBuilder/dibcli.c index 121620943..f91c3cbe5 100644 --- a/dictBuilder/dibcli.c +++ b/dictBuilder/dibcli.c @@ -228,7 +228,14 @@ int main(int argCount, const char** argv) /* 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 ... */ DiB_setNotificationLevel(g_displayLevel); From 82516192e7d4a0435e163226ffdd0f30798a7b2a Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 29 Jan 2016 16:48:10 +0100 Subject: [PATCH 17/34] minor cosmetic refactoring --- dictBuilder/dibcli.c | 4 ++-- dictBuilder/dictBuilder.c | 32 +++++++------------------------- 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/dictBuilder/dibcli.c b/dictBuilder/dibcli.c index f91c3cbe5..3ca6854db 100644 --- a/dictBuilder/dibcli.c +++ b/dictBuilder/dibcli.c @@ -102,9 +102,9 @@ static int usage_advanced(const char* programName) 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( " -S# : dictionary selectivity level (default: %u)\n", selectionLevelDefault); DISPLAY( " -v : verbose mode\n"); - DISPLAY( " -q : suppress warnings; specify twice to suppress errors too\n"); + DISPLAY( " -q : suppress notifications; specify twice to suppress errors too\n"); return 0; } diff --git a/dictBuilder/dictBuilder.c b/dictBuilder/dictBuilder.c index 4abae9fd4..ca3f66f17 100644 --- a/dictBuilder/dictBuilder.c +++ b/dictBuilder/dictBuilder.c @@ -310,7 +310,6 @@ static dictItem DiB_analyzePos( U32 end = start; dictItem solution; - /* init */ memset(&solution, 0, sizeof(solution)); doneMarks[pos] = 1; @@ -385,7 +384,6 @@ static dictItem DiB_analyzePos( if (selectedCount < minRatio) break; - //DISPLAYLEVEL(4, "best char at length %u: %02X (seen %u times) (pos %u) \n", searchLength+1, selectedChar, selectedCount, selectedRef); refinedStart = selectedID; refinedEnd = refinedStart + selectedCount; } @@ -602,34 +600,18 @@ static void DiB_trainBuffer(dictItem* dictList, U32 dictListSize, } DISPLAYLEVEL(2, "finding patterns ... \n"); - DISPLAYLEVEL(4, "minimum ratio : %u \n", minRatio); + DISPLAYLEVEL(3, "minimum ratio : %u \n", minRatio); { U32 cursor; for (cursor=0; cursor < bufferSize; ) { dictItem solution; - if (doneMarks[cursor]) { cursor++; continue; } solution = DiB_analyzePos(doneMarks, suffix, reverseSuffix[cursor], buffer, minRatio); if (solution.length==0) { cursor++; continue; } DiB_insertDictItem(dictList, dictListSize, solution); cursor += solution.length; DISPLAYUPDATE(2, "\r%4.2f %% \r", (double)cursor / bufferSize * 100); - } - -#if 0 - /* 2nd scan */ - for (cursor=0; cursor < bufferSize; cursor++ ) - { - dictItem solution; - - if (doneMarks[cursor]) continue; - solution = DiB_analyzePos(doneMarks, suffix, reverseSuffix[cursor], buffer, minRatio); - if (solution.length==0) continue; - DiB_insertDictItem(dictList, dictListSize, solution); - DISPLAYUPDATE(2, "\r%4.2f %% \r", (double)cursor / bufferSize * 100); - } -#endif - } + } } /* limit dictionary size */ { @@ -879,7 +861,7 @@ int DiB_trainDictionary(const char* dictFileName, unsigned maxDictSize, size_t benchedSize; size_t* fileSizes = (size_t*)malloc(nbFiles * sizeof(size_t)); unsigned long long totalSizeToLoad = DiB_getTotalFileSize(fileNamesTable, nbFiles); - const U32 dictListSize = DICTLISTSIZE; + const U32 dictListSize = MAX( MAX(DICTLISTSIZE, nbFiles), maxDictSize/16); dictItem* dictList = (dictItem*)malloc(dictListSize * sizeof(*dictList)); char mfName[20] = {0}; const char* displayName = NULL; @@ -888,7 +870,7 @@ int DiB_trainDictionary(const char* dictFileName, unsigned maxDictSize, benchedSize = DiB_findMaxMem(totalSizeToLoad * MEMMULT) / MEMMULT; if ((unsigned long long)benchedSize > totalSizeToLoad) benchedSize = (size_t)totalSizeToLoad; if (benchedSize < totalSizeToLoad) - DISPLAY("Not enough memory; training on %u MB only...\n", (unsigned)(benchedSize >> 20)); + DISPLAYLEVEL(1, "Not enough memory; training on %u MB only...\n", (unsigned)(benchedSize >> 20)); /* Memory allocation & restrictions */ srcBuffer = malloc(benchedSize+NOISELENGTH); /* + noise */ @@ -899,9 +881,9 @@ int DiB_trainDictionary(const char* dictFileName, unsigned maxDictSize, DiB_loadFiles(srcBuffer, benchedSize, fileSizes, fileNamesTable, nbFiles); DiB_fillNoise((char*)srcBuffer + benchedSize, NOISELENGTH); /* guard band, for end of buffer condition */ + /* analyze sequences (non-fast mode) */ if (shiftRatio>0) { - /* analyze samples */ snprintf (mfName, sizeof(mfName), " %u files", nbFiles); if (nbFiles > 1) displayName = mfName; else displayName = fileNamesTable[0]; @@ -953,8 +935,8 @@ int DiB_trainDictionary(const char* dictFileName, unsigned maxDictSize, memcpy(ptr, (char*)srcBuffer+dictList[u].pos, l); } - /* fast dict content mode */ - if (shiftRatio==0) { + /* fast mode dict content */ + if (shiftRatio==0) { /* note could also be used to complete a dictionary, but not necessarily better */ addedContentLength = ptr-(BYTE*)dictContent; DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */ DISPLAYLEVEL(2, "Adding %u KB from fast sampling \n", (U32)(addedContentLength>>10)); From fd416f1eaf752ab70472d4f6fff5fc32ebaf86b5 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 30 Jan 2016 03:14:15 +0100 Subject: [PATCH 18/34] added : ZSTD_compress_usingPreparedCCtx() --- NEWS | 2 +- lib/zstd_compress.c | 148 +++++++++++++++++++++++++++++++++++++++----- lib/zstd_static.h | 126 ++++++------------------------------- programs/bench.c | 47 ++++---------- 4 files changed, 168 insertions(+), 155 deletions(-) diff --git a/NEWS b/NEWS index cfbd6867b..ed414e23a 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,6 @@ v0.5.0 -Changed streaming & dictionary API New : dictionary builder utility +Changed : streaming & dictionary API v0.4.7 Improved : small compression speed improvement in HC mode diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 31eb15912..bc78d2dd2 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -2143,20 +2143,6 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc, } -/** ZSTD_getParams -* return ZSTD_parameters structure for a selected compression level and srcSize. -* srcSizeHint value is optional, select 0 if not known */ -ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint) -{ - ZSTD_parameters result; - 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; - result = ZSTD_defaultParameters[tableID][compressionLevel]; - result.srcSize = srcSizeHint; - return result; -} - size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* zc, const void* dict, size_t dictSize, int compressionLevel) { return ZSTD_compressBegin_advanced(zc, dict, dictSize, ZSTD_getParams(compressionLevel, 0)); @@ -2195,6 +2181,24 @@ size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t maxDstSize) return 3+hbSize; } + +size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, + void* dst, size_t maxDstSize, + const void* src, size_t srcSize) +{ + size_t outSize; + size_t errorCode = ZSTD_copyCCtx(cctx, preparedCCtx); + if (ZSTD_isError(errorCode)) return errorCode; + errorCode = ZSTD_compressContinue(cctx, dst, maxDstSize, src, srcSize); + if (ZSTD_isError(errorCode)) return errorCode; + outSize = errorCode; + errorCode = ZSTD_compressEnd(cctx, (char*)dst+outSize, maxDstSize-outSize); + if (ZSTD_isError(errorCode)) return errorCode; + outSize += errorCode; + return outSize; +} + + size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize, @@ -2243,3 +2247,119 @@ size_t ZSTD_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSi return result; } + +/*- Pre-defined compression levels -*/ + +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 */ + { 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, 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 */ +}, +{ /* 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 */ +}, +{ /* 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 */ +}, +{ /* 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 */ +}, +}; + +/*! ZSTD_getParams +* @return ZSTD_parameters structure for a selected compression level and srcSize. +* @srcSizeHint value is optional, select 0 if not known */ +ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint) +{ + ZSTD_parameters result; + 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; + result = ZSTD_defaultParameters[tableID][compressionLevel]; + result.srcSize = srcSizeHint; + return result; +} + diff --git a/lib/zstd_static.h b/lib/zstd_static.h index b985ce1e8..de2212d9d 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -82,16 +82,16 @@ typedef struct /* ************************************* * Advanced functions ***************************************/ -/** ZSTD_getParams -* return ZSTD_parameters structure for a selected compression level and srcSize. -* srcSizeHint value is optional, select 0 if not known */ +/*! ZSTD_getParams +* @return ZSTD_parameters structure for a selected compression level and srcSize. +* @srcSizeHint value is optional, select 0 if not known */ ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint); -/** ZSTD_validateParams +/*! ZSTD_validateParams * correct params value to remain within authorized range */ ZSTDLIB_API void ZSTD_validateParams(ZSTD_parameters* params); -/** ZSTD_compress_usingDict +/*! ZSTD_compress_usingDict * Same as ZSTD_compressCCtx(), loading a Dictionary content. * Note : dict can be NULL, in which case, it's equivalent to ZSTD_compressCCtx() */ ZSTDLIB_API size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, @@ -100,7 +100,7 @@ ZSTDLIB_API size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, const void* dict,size_t dictSize, int compressionLevel); -/** ZSTD_compress_advanced +/*! ZSTD_compress_advanced * Same as ZSTD_compress_usingDict(), with fine-tune control of each compression parameter */ ZSTDLIB_API size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, @@ -108,6 +108,18 @@ ZSTDLIB_API size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, const void* dict,size_t dictSize, ZSTD_parameters params); +/*! ZSTD_compress_usingPreparedDCtx +* Same as ZSTD_compress_usingDict, but using a reference context preparedCCtx, where dictionary has been loaded. +* It avoids reloading the dictionary each time. +* preparedCCtx must have been properly initialized using ZSTD_compressBegin_usingDict() or ZSTD_compressBegin_advanced() +* Requires 2 contexts : 1 for reference, which will not be modified, and 1 to run the compression operation */ +ZSTDLIB_API size_t ZSTD_compress_usingPreparedCCtx( + ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, + void* dst, size_t maxDstSize, + const void* src, size_t srcSize); + +/*- Advanced Decompression functions -*/ + /*! ZSTD_decompress_usingDict * Same as ZSTD_decompressDCtx, using a Dictionary content as prefix * Note : dict can be NULL, in which case, it's equivalent to ZSTD_decompressDCtx() */ @@ -117,9 +129,9 @@ ZSTDLIB_API size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, const void* dict,size_t dictSize); /*! ZSTD_decompress_usingPreparedDCtx -* Same as ZSTD_decompress_usingDict, but using a reference context preparedDCtx, where dictionary has already been loaded into. +* Same as ZSTD_decompress_usingDict, but using a reference context preparedDCtx, where dictionary has been loaded. * It avoids reloading the dictionary each time. -* preparedDCtx must have been properly initialized using ZSTD_compressBegin_usingDict(). +* preparedDCtx must have been properly initialized using ZSTD_decompressBegin_usingDict(). * Requires 2 contexts : 1 for reference, which will not be modified, and 1 to run the decompression operation */ ZSTDLIB_API size_t ZSTD_decompress_usingPreparedDCtx( ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx, @@ -233,104 +245,6 @@ size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const ***************************************/ #define ZSTD_MAX_CLEVEL 20 ZSTDLIB_API unsigned ZSTD_maxCLevel (void); -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 */ - { 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, 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 */ -}, -{ /* 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 */ -}, -{ /* 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 */ -}, -{ /* 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 */ -}, -}; /* ************************************* diff --git a/programs/bench.c b/programs/bench.c index efb9d69f4..b7f367d0c 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -245,13 +245,11 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, const char* srcPtr = (const char*)srcBuffer; char* cPtr = (char*)compressedBuffer; char* resPtr = (char*)resultBuffer; - for (fileNb=0; fileNb largestBlockSize) largestBlockSize = thisBlockSize; - } - } - } + } } } /* warmimg up memory */ RDG_genBuffer(compressedBuffer, maxCompressedSize, 0.10, 0.50, 1); @@ -279,8 +275,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, U64 crcCheck = 0; DISPLAY("\r%79s\r", ""); - for (loopNb = 1; loopNb <= nbIterations; loopNb++) - { + for (loopNb = 1; loopNb <= nbIterations; loopNb++) { int nbLoops; int milliTime; U32 blockNb; @@ -295,23 +290,12 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, milliTime = BMK_GetMilliStart(); while (BMK_GetMilliSpan(milliTime) < TIMELOOP) { ZSTD_compressBegin_advanced(refCtx, dictBuffer, dictBufferSize, ZSTD_getParams(cLevel, dictBufferSize+largestBlockSize)); - //ZSTD_compressBegin_advanced(refCtx, dictBuffer, dictBufferSize, ZSTD_getParams(cLevel, 0)); for (blockNb=0; blockNb %6u bytes (%08X) \n", - blockNb, (U32)blockTable[blockNb].srcSize, (U32)blockTable[blockNb].cSize, XXH32(blockTable[blockNb].cPtr, blockTable[blockNb].cSize, 0)); } nbLoops++; } @@ -324,7 +308,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, ratio = (double)srcSize / (double)cSize; DISPLAY("%2i-%-17.17s :%10i ->%10i (%5.3f),%6.1f MB/s\r", loopNb, displayName, (int)srcSize, (int)cSize, ratio, (double)srcSize / fastestC / 1000.); -#if 1 +#if 0 /* Decompression */ memset(resultBuffer, 0xD6, srcSize); /* warm result buffer */ @@ -405,12 +389,10 @@ static size_t BMK_findMaxMem(U64 requiredMem) requiredMem += 2 * step; if (requiredMem > maxMemory) requiredMem = maxMemory; - while (!testmem) - { + while (!testmem) { requiredMem -= step; testmem = (BYTE*)malloc((size_t)requiredMem); } - free(testmem); return (size_t)(requiredMem - step); } @@ -420,8 +402,7 @@ static void BMK_benchCLevel(void* srcBuffer, size_t benchedSize, const size_t* fileSizes, unsigned nbFiles, const void* dictBuffer, size_t dictBufferSize) { - if (cLevel < 0) - { + if (cLevel < 0) { int l; for (l=1; l <= -cLevel; l++) BMK_benchMem(srcBuffer, benchedSize, @@ -453,8 +434,7 @@ static void BMK_loadFiles(void* buffer, size_t bufferSize, size_t pos = 0; unsigned n; - for (n=0; n 64 MB) EXM_THROW(10, "dictionary file %s too large", dictFileName); dictBufferSize = (size_t)dictFileSize; From f5fa09e5acb09aa3865e8a36d18e148e31bc301d Mon Sep 17 00:00:00 2001 From: Christophe Chevalier Date: Sat, 30 Jan 2016 21:12:37 +0100 Subject: [PATCH 19/34] Added VS2013 project for dictBuilder - fixed strings.h vs string.h include - fixed INLINE/FORCE_INLINE defines --- dictBuilder/divsufsort_private.h | 6 +- dictBuilder/sssort.c | 23 +++ dictBuilder/trsort.c | 23 +++ visual/2013/dictBuilder/dictBuilder.vcxproj | 182 ++++++++++++++++++ .../dictBuilder/dictBuilder.vcxproj.filters | 75 ++++++++ visual/2013/zstd.sln | 10 + visual/2013/zstdlib/zstdlib.vcxproj | 2 + visual/2013/zstdlib/zstdlib.vcxproj.filters | 6 + 8 files changed, 326 insertions(+), 1 deletion(-) create mode 100644 visual/2013/dictBuilder/dictBuilder.vcxproj create mode 100644 visual/2013/dictBuilder/dictBuilder.vcxproj.filters diff --git a/dictBuilder/divsufsort_private.h b/dictBuilder/divsufsort_private.h index dc35063f5..0a18f6d28 100644 --- a/dictBuilder/divsufsort_private.h +++ b/dictBuilder/divsufsort_private.h @@ -50,7 +50,11 @@ extern "C" { # include #endif #if HAVE_STRINGS_H -# include +# ifdef _WIN32 +# include +# else +# include +# endif #endif #if HAVE_INTTYPES_H # include diff --git a/dictBuilder/sssort.c b/dictBuilder/sssort.c index 9e680fbff..07cb5bd1b 100644 --- a/dictBuilder/sssort.c +++ b/dictBuilder/sssort.c @@ -29,6 +29,29 @@ #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" diff --git a/dictBuilder/trsort.c b/dictBuilder/trsort.c index b3c5cfa7a..9e21e68ec 100644 --- a/dictBuilder/trsort.c +++ b/dictBuilder/trsort.c @@ -29,6 +29,29 @@ #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" diff --git a/visual/2013/dictBuilder/dictBuilder.vcxproj b/visual/2013/dictBuilder/dictBuilder.vcxproj new file mode 100644 index 000000000..ad69449f6 --- /dev/null +++ b/visual/2013/dictBuilder/dictBuilder.vcxproj @@ -0,0 +1,182 @@ +ï»ż + + + + 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 + + + + + + + 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 new file mode 100644 index 000000000..a38cc30e9 --- /dev/null +++ b/visual/2013/dictBuilder/dictBuilder.vcxproj.filters @@ -0,0 +1,75 @@ +ï»ż + + + + {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/zstd.sln b/visual/2013/zstd.sln index 4f2447fbb..c132ddda6 100644 --- a/visual/2013/zstd.sln +++ b/visual/2013/zstd.sln @@ -11,6 +11,8 @@ 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 @@ -51,6 +53,14 @@ 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/zstdlib/zstdlib.vcxproj b/visual/2013/zstdlib/zstdlib.vcxproj index a580048b6..05a03ab8d 100644 --- a/visual/2013/zstdlib/zstdlib.vcxproj +++ b/visual/2013/zstdlib/zstdlib.vcxproj @@ -27,6 +27,8 @@ + + diff --git a/visual/2013/zstdlib/zstdlib.vcxproj.filters b/visual/2013/zstdlib/zstdlib.vcxproj.filters index 8600c5f4f..e4bdf7dbf 100644 --- a/visual/2013/zstdlib/zstdlib.vcxproj.filters +++ b/visual/2013/zstdlib/zstdlib.vcxproj.filters @@ -68,6 +68,12 @@ Header Files + + Header Files + + + Header Files + From e93d6ced17e6ecbd8b07cb5edd0f6046d5faa0ae Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 31 Jan 2016 00:58:06 +0100 Subject: [PATCH 20/34] minor compression gain --- lib/fse.c | 15 +++++-------- lib/fse_static.h | 24 +++++++++++++++++++++ lib/zstd_compress.c | 49 +++++++++++++++++++++++++++---------------- lib/zstd_decompress.c | 46 ++++++++++++++++++++++------------------ lib/zstd_internal.h | 2 +- programs/bench.c | 16 +++++++------- 6 files changed, 95 insertions(+), 57 deletions(-) diff --git a/lib/fse.c b/lib/fse.c index 1f382ed10..606dcbcc3 100644 --- a/lib/fse.c +++ b/lib/fse.c @@ -205,7 +205,7 @@ size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned break; case -1: case 1: - symbolTT[s].deltaNbBits = tableLog << 16; + symbolTT[s].deltaNbBits = (tableLog << 16) - (1<>= 16; bitCount -= 16; - } - } + } } /* flush remaining bitStream */ if ((!writeIsSafe) && (out > oend - 2)) return ERROR(dstSize_tooSmall); /* Buffer overflow */ @@ -596,8 +592,7 @@ static size_t FSE_count_parallel(unsigned* count, unsigned* maxSymbolValuePtr, while (ipmaxSymbolValue; s--) - { + for (s=255; s>maxSymbolValue; s--) { Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s]; if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall); } } @@ -854,7 +849,7 @@ size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits) /* Build Symbol Transformation Table */ for (s=0; s<=maxSymbolValue; s++) { - symbolTT[s].deltaNbBits = nbBits << 16; + symbolTT[s].deltaNbBits = (nbBits << 16) - (1 << nbBits); symbolTT[s].deltaFindState = s-1; } diff --git a/lib/fse_static.h b/lib/fse_static.h index eb031639c..ca303db84 100644 --- a/lib/fse_static.h +++ b/lib/fse_static.h @@ -239,6 +239,19 @@ MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct) statePtr->stateLog = tableLog; } +MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol) +{ + FSE_initCState(statePtr, ct); + { + const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol]; + const U16* stateTable = (const U16*)(statePtr->stateTable); + U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1<<15)) >> 16); + statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits; + statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState]; + + } +} + MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, U32 symbol) { const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol]; @@ -277,6 +290,17 @@ MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, con DStatePtr->table = dt + 1; } +MEM_STATIC size_t FSE_getStateValue(FSE_DState_t* DStatePtr) +{ + return DStatePtr->state; +} + +MEM_STATIC BYTE FSE_peakSymbol(FSE_DState_t* DStatePtr) +{ + const FSE_decode_t DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + return DInfo.symbol; +} + MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) { const FSE_decode_t DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index bc78d2dd2..eb3031dcb 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -547,9 +547,13 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, if ((oend-op) < MIN_SEQUENCES_SIZE) return ERROR(dstSize_tooSmall); MEM_writeLE16(op, (U16)nbSeq); op+=2; - seqHead = op; + + if (nbSeq==0) goto _check_compressibility; /* dumps : contains rests of large lengths */ + if ((oend-op) < 3 /* dumps */ + 1 /*seqHead*/) + return ERROR(dstSize_tooSmall); + seqHead = op; { size_t dumpsLength = seqStorePtr->dumps - seqStorePtr->dumpsStart; if (dumpsLength < 512) { @@ -572,9 +576,9 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, /* CTable for Literal Lengths */ max = MaxLL; - mostFrequent = FSE_countFast(count, &max, seqStorePtr->litLengthStart, nbSeq); + mostFrequent = FSE_countFast(count, &max, llTable, nbSeq); if ((mostFrequent == nbSeq) && (nbSeq > 2)) { - *op++ = *(seqStorePtr->litLengthStart); + *op++ = llTable[0]; FSE_buildCTable_rle(CTable_LitLength, (BYTE)max); LLtype = FSE_ENCODING_RLE; } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) { @@ -584,8 +588,10 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, LLtype = FSE_ENCODING_RAW; } else { size_t NCountSize; + size_t nbSeq_1 = nbSeq; U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max); - FSE_normalizeCount(norm, tableLog, count, nbSeq, max); + if (count[llTable[nbSeq-1]]>1) { count[llTable[nbSeq-1]]--; nbSeq_1--; } + FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max); NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */ if (FSE_isError(NCountSize)) return ERROR(GENERIC); op += NCountSize; @@ -603,7 +609,7 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, max = MaxOff; mostFrequent = FSE_countFast(count, &max, offCodeTable, nbSeq); if ((mostFrequent == nbSeq) && (nbSeq > 2)) { - *op++ = *offCodeTable; + *op++ = offCodeTable[0]; FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max); Offtype = FSE_ENCODING_RLE; } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) { @@ -613,8 +619,10 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, Offtype = FSE_ENCODING_RAW; } else { size_t NCountSize; + size_t nbSeq_1 = nbSeq; U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max); - FSE_normalizeCount(norm, tableLog, count, nbSeq, max); + if (count[offCodeTable[nbSeq-1]]>1) { count[offCodeTable[nbSeq-1]]--; nbSeq_1--; } + FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max); NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */ if (FSE_isError(NCountSize)) return ERROR(GENERIC); op += NCountSize; @@ -624,9 +632,9 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, /* CTable for MatchLengths */ max = MaxML; - mostFrequent = FSE_countFast(count, &max, seqStorePtr->matchLengthStart, nbSeq); + mostFrequent = FSE_countFast(count, &max, mlTable, nbSeq); if ((mostFrequent == nbSeq) && (nbSeq > 2)) { - *op++ = *seqStorePtr->matchLengthStart; + *op++ = *mlTable; FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max); MLtype = FSE_ENCODING_RLE; } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) { @@ -659,22 +667,26 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, errorCode = BIT_initCStream(&blockStream, op, oend-op); if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); /* not enough space remaining */ - FSE_initCState(&stateMatchLength, CTable_MatchLength); - FSE_initCState(&stateOffsetBits, CTable_OffsetBits); - FSE_initCState(&stateLitLength, CTable_LitLength); - for (i=(int)nbSeq-1; i>=0; i--) { + /* first symbols */ + FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlTable[nbSeq-1]); + FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, offCodeTable[nbSeq-1]); + FSE_initCState2(&stateLitLength, CTable_LitLength, llTable[nbSeq-1]); + BIT_addBits(&blockStream, offsetTable[nbSeq-1], offCodeTable[nbSeq-1] ? (offCodeTable[nbSeq-1]-1) : 0); + BIT_flushBits(&blockStream); + + for (i=(int)nbSeq-2; i>=0; i--) { BYTE mlCode = mlTable[i]; U32 offset = offsetTable[i]; BYTE offCode = offCodeTable[i]; /* 32b*/ /* 64b*/ - U32 nbBits = (offCode-1) * (!!offCode); + U32 nbBits = (offCode-1) + (!offCode); BYTE litLength = llTable[i]; /* (7)*/ /* (7)*/ FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 17 */ /* 17 */ if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */ - BIT_addBits(&blockStream, offset, nbBits); /* 31 */ /* 42 */ /* 24 bits max in 32-bits mode */ - if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */ - FSE_encodeSymbol(&blockStream, &stateOffsetBits, offCode); /* 16 */ /* 51 */ FSE_encodeSymbol(&blockStream, &stateLitLength, litLength); /* 26 */ /* 61 */ + FSE_encodeSymbol(&blockStream, &stateOffsetBits, offCode); /* 16 */ /* 51 */ + if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */ + BIT_addBits(&blockStream, offset, nbBits); /* 31 */ /* 42 */ /* 24 bits max in 32-bits mode */ BIT_flushBits(&blockStream); /* 7 */ /* 7 */ } @@ -688,14 +700,15 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, } /* check compressibility */ +_check_compressibility: if ((size_t)(op-ostart) >= maxCSize) return 0; return op - ostart; } -/** ZSTD_storeSeq - Store a sequence (literal length, literals, offset code and match length) into seqStore_t +/*! ZSTD_storeSeq + Store a sequence (literal length, literals, offset code and match length code) into seqStore_t @offsetCode : distance to match, or 0 == repCode @matchCode : matchLength - MINMATCH */ diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index b50e474fb..cdc7d3074 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -426,7 +426,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, break; } - if (litSize+WILDCOPY_OVERLENGTH > srcSize) /* risk reading beyond src buffer with wildcopy */ + if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) /* risk reading beyond src buffer with wildcopy */ { if (litSize > srcSize-lhSize) return ERROR(corruption_detected); memcpy(dctx->litBuffer, istart+lhSize, litSize); @@ -483,10 +483,12 @@ size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLen size_t dumpsLength; /* check */ - if (srcSize < 5) return ERROR(srcSize_wrong); + if (srcSize < MIN_SEQUENCES_SIZE) return ERROR(srcSize_wrong); /* SeqHead */ *nbSeq = MEM_readLE16(ip); ip+=2; + if (*nbSeq==0) return 2; + LLtype = *ip >> 6; Offtype = (*ip >> 4) & 3; MLtype = (*ip >> 2) & 3; @@ -589,8 +591,8 @@ size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLen typedef struct { size_t litLength; - size_t offset; size_t matchLength; + size_t offset; } seq_t; typedef struct { @@ -603,7 +605,6 @@ typedef struct { const BYTE* dumpsEnd; } seqState_t; - static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) { size_t litLength; @@ -614,7 +615,7 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) const BYTE* const de = seqState->dumpsEnd; /* Literal length */ - litLength = FSE_decodeSymbol(&(seqState->stateLL), &(seqState->DStream)); + litLength = FSE_peakSymbol(&(seqState->stateLL)); prevOffset = litLength ? seq->offset : seqState->prevOffset; if (litLength == MaxLL) { U32 add = *dumps++; @@ -632,17 +633,20 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) 1 /*fake*/, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, /*fake*/ 1, 1, 1, 1, 1 }; - U32 offsetCode, nbBits; - offsetCode = FSE_decodeSymbol(&(seqState->stateOffb), &(seqState->DStream)); /* <= maxOff, by table construction */ - if (MEM_32bits()) BIT_reloadDStream(&(seqState->DStream)); - nbBits = offsetCode - 1; + U32 offsetCode = FSE_peakSymbol(&(seqState->stateOffb)); /* <= maxOff, by table construction */ + U32 nbBits = offsetCode - 1; if (offsetCode==0) nbBits = 0; /* cmove */ offset = offsetPrefix[offsetCode] + BIT_readBits(&(seqState->DStream), nbBits); if (MEM_32bits()) BIT_reloadDStream(&(seqState->DStream)); - if (offsetCode==0) offset = prevOffset; /* cmove */ + if (offsetCode==0) offset = prevOffset; /* repcode, cmove */ if (offsetCode | !litLength) seqState->prevOffset = seq->offset; /* cmove */ + FSE_decodeSymbol(&(seqState->stateOffb), &(seqState->DStream)); /* update */ } + /* Literal length update */ + FSE_decodeSymbol(&(seqState->stateLL), &(seqState->DStream)); /* update */ + if (MEM_32bits()) BIT_reloadDStream(&(seqState->DStream)); + /* MatchLength */ matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); if (matchLength == MaxML) { @@ -778,7 +782,7 @@ static size_t ZSTD_decompressSequences( ip += errorCode; /* Regen sequences */ - { + if (nbSeq) { seq_t sequence; seqState_t seqState; @@ -803,16 +807,18 @@ static size_t ZSTD_decompressSequences( } /* check if reached exact end */ - if ( !BIT_endOfDStream(&(seqState.DStream)) ) return ERROR(corruption_detected); /* DStream should be entirely and exactly consumed; otherwise data is corrupted */ + if (nbSeq) + return ERROR(corruption_detected); /* DStream should be entirely and exactly consumed; otherwise data is corrupted */ + } - /* last literal segment */ - { - size_t lastLLSize = litEnd - litPtr; - if (litPtr > litEnd) return ERROR(corruption_detected); - if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); - if (op != litPtr) memcpy(op, litPtr, lastLLSize); - op += lastLLSize; - } } + /* last literal segment */ + { + size_t lastLLSize = litEnd - litPtr; + if (litPtr > litEnd) return ERROR(corruption_detected); /* too many literals already used */ + if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); + memcpy(op, litPtr, lastLLSize); + op += lastLLSize; + } return op-ostart; } diff --git a/lib/zstd_internal.h b/lib/zstd_internal.h index 7eda81366..0b993b1e8 100644 --- a/lib/zstd_internal.h +++ b/lib/zstd_internal.h @@ -102,7 +102,7 @@ static const size_t ZSTD_frameHeaderSize_min = 5; #define HufLog 12 -#define MIN_SEQUENCES_SIZE (2 /*seqNb*/ + 2 /*dumps*/ + 3 /*seqTables*/ + 1 /*bitStream*/) +#define MIN_SEQUENCES_SIZE 2 /*seqNb*/ #define MIN_CBLOCK_SIZE (1 /*litCSize*/ + MIN_SEQUENCES_SIZE) #define WILDCOPY_OVERLENGTH 8 diff --git a/programs/bench.c b/programs/bench.c index b7f367d0c..d24991431 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -308,7 +308,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, ratio = (double)srcSize / (double)cSize; DISPLAY("%2i-%-17.17s :%10i ->%10i (%5.3f),%6.1f MB/s\r", loopNb, displayName, (int)srcSize, (int)cSize, ratio, (double)srcSize / fastestC / 1000.); -#if 0 +#if 1 /* Decompression */ memset(resultBuffer, 0xD6, srcSize); /* warm result buffer */ @@ -317,18 +317,17 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, while (BMK_GetMilliStart() == milliTime); milliTime = BMK_GetMilliStart(); - ZSTD_decompressBegin_usingDict(refDCtx, dictBuffer, dictBufferSize); for ( ; BMK_GetMilliSpan(milliTime) < TIMELOOP; nbLoops++) { + ZSTD_decompressBegin_usingDict(refDCtx, dictBuffer, dictBufferSize); for (blockNb=0; blockNb%10i (%5.3f),%6.1f MB/s ,%6.1f MB/s\r", loopNb, displayName, (int)srcSize, (int)cSize, ratio, (double)srcSize / fastestC / 1000., (double)srcSize / fastestD / 1000.); /* CRC Checking */ +_findError: crcCheck = XXH64(resultBuffer, srcSize, 0); if (crcOrig!=crcCheck) { size_t u; From 61e16ce07c023af170e55344becc6164124ed153 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 31 Jan 2016 02:04:15 +0100 Subject: [PATCH 21/34] minor optimization for small files --- lib/fse.c | 9 ++++++--- lib/zstd_compress.c | 23 ++++++++--------------- lib/zstd_decompress.c | 27 ++++++++++++++++----------- lib/zstd_internal.h | 4 ++-- 4 files changed, 32 insertions(+), 31 deletions(-) diff --git a/lib/fse.c b/lib/fse.c index 606dcbcc3..986a0da15 100644 --- a/lib/fse.c +++ b/lib/fse.c @@ -848,9 +848,12 @@ size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits) tableU16[s] = (U16)(tableSize + s); /* Build Symbol Transformation Table */ - for (s=0; s<=maxSymbolValue; s++) { - symbolTT[s].deltaNbBits = (nbBits << 16) - (1 << nbBits); - symbolTT[s].deltaFindState = s-1; + { + const U32 deltaNbBits = (nbBits << 16) - (1 << nbBits); + for (s=0; s<=maxSymbolValue; s++) { + symbolTT[s].deltaNbBits = deltaNbBits; + symbolTT[s].deltaFindState = s-1; + } } return 0; diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index eb3031dcb..37550e6b7 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -544,10 +544,11 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, } /* Sequences Header */ - if ((oend-op) < MIN_SEQUENCES_SIZE) - return ERROR(dstSize_tooSmall); - MEM_writeLE16(op, (U16)nbSeq); op+=2; - + if ((oend-op) < MIN_SEQUENCES_SIZE) return ERROR(dstSize_tooSmall); + if (nbSeq < 128) *op++ = (BYTE)nbSeq; + else { + op[0] = (nbSeq>>8) + 128; op[1] = (BYTE)nbSeq; op+=2; + } if (nbSeq==0) goto _check_compressibility; /* dumps : contains rests of large lengths */ @@ -946,12 +947,7 @@ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc, /* init */ ZSTD_resetSeqStore(seqStorePtr); - if (ip < lowest+4) { - hashTable[ZSTD_hashPtr(lowest+1, hBits, mls)] = lowIndex+1; - hashTable[ZSTD_hashPtr(lowest+2, hBits, mls)] = lowIndex+2; - hashTable[ZSTD_hashPtr(lowest+3, hBits, mls)] = lowIndex+3; - ip = lowest+4; - } + if (ip < lowest+REPCODE_STARTVALUE) ip = lowest+REPCODE_STARTVALUE; /* Main Search Loop */ while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */ @@ -1056,12 +1052,9 @@ void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, /* init */ ZSTD_resetSeqStore(seqStorePtr); - /* skip first 4 positions to avoid read overflow during repcode match check */ + /* skip first position to avoid read overflow during repcode match check */ hashTable[ZSTD_hashPtr(ip+0, hBits, mls)] = (U32)(ip-base+0); - hashTable[ZSTD_hashPtr(ip+1, hBits, mls)] = (U32)(ip-base+1); - hashTable[ZSTD_hashPtr(ip+2, hBits, mls)] = (U32)(ip-base+2); - hashTable[ZSTD_hashPtr(ip+3, hBits, mls)] = (U32)(ip-base+3); - ip += 4; + ip += REPCODE_STARTVALUE; /* Main Search Loop */ while (ip < ilimit) { /* < instead of <=, because (ip+1) */ diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index cdc7d3074..96ba89365 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -273,7 +273,8 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) static size_t ZSTD_decodeFrameHeader_Part1(ZSTD_DCtx* zc, const void* src, size_t srcSize) { U32 magicNumber; - if (srcSize != ZSTD_frameHeaderSize_min) return ERROR(srcSize_wrong); + if (srcSize != ZSTD_frameHeaderSize_min) + return ERROR(srcSize_wrong); magicNumber = MEM_readLE32(src); if (magicNumber != ZSTD_MAGICNUMBER) return ERROR(prefix_unknown); zc->headerSize = ZSTD_frameHeaderSize_min; @@ -300,7 +301,8 @@ size_t ZSTD_getFrameParams(ZSTD_parameters* params, const void* src, size_t srcS static size_t ZSTD_decodeFrameHeader_Part2(ZSTD_DCtx* zc, const void* src, size_t srcSize) { size_t result; - if (srcSize != zc->headerSize) return ERROR(srcSize_wrong); + if (srcSize != zc->headerSize) + return ERROR(srcSize_wrong); result = ZSTD_getFrameParams(&(zc->params), src, srcSize); if ((MEM_32bits()) && (zc->params.windowLog > 25)) return ERROR(frameParameter_unsupportedBy32bitsImplementation); return result; @@ -313,7 +315,8 @@ size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bp BYTE headerFlags; U32 cSize; - if (srcSize < 3) return ERROR(srcSize_wrong); + if (srcSize < 3) + return ERROR(srcSize_wrong); headerFlags = *in; cSize = in[2] + (in[1]<<8) + ((in[0] & 7)<<16); @@ -335,7 +338,7 @@ static size_t ZSTD_copyRawBlock(void* dst, size_t maxDstSize, const void* src, s } -/** ZSTD_decodeLiteralsBlock +/*! ZSTD_decodeLiteralsBlock @return : nb of bytes read from src (< srcSize ) */ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, const void* src, size_t srcSize) /* note : srcSize < BLOCKSIZE */ @@ -426,8 +429,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, break; } - if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) /* risk reading beyond src buffer with wildcopy */ - { + if (lhSize+litSize+WILDCOPY_OVERLENGTH > srcSize) { /* risk reading beyond src buffer with wildcopy */ if (litSize > srcSize-lhSize) return ERROR(corruption_detected); memcpy(dctx->litBuffer, istart+lhSize, litSize); dctx->litPtr = dctx->litBuffer; @@ -483,11 +485,14 @@ size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLen size_t dumpsLength; /* check */ - if (srcSize < MIN_SEQUENCES_SIZE) return ERROR(srcSize_wrong); + if (srcSize < MIN_SEQUENCES_SIZE) + return ERROR(srcSize_wrong); /* SeqHead */ - *nbSeq = MEM_readLE16(ip); ip+=2; - if (*nbSeq==0) return 2; + *nbSeq = *ip++; + if (*nbSeq==0) return 1; + if (*nbSeq >= 128) + *nbSeq = ((nbSeq[0]-128)<<8) + *ip++; LLtype = *ip >> 6; Offtype = (*ip >> 4) & 3; @@ -787,10 +792,10 @@ static size_t ZSTD_decompressSequences( seqState_t seqState; memset(&sequence, 0, sizeof(sequence)); - sequence.offset = 4; + sequence.offset = REPCODE_STARTVALUE; seqState.dumps = dumps; seqState.dumpsEnd = dumps + dumpsLength; - seqState.prevOffset = 4; + seqState.prevOffset = REPCODE_STARTVALUE; errorCode = BIT_initDStream(&(seqState.DStream), ip, iend-ip); if (ERR_isError(errorCode)) return ERROR(corruption_detected); FSE_initDState(&(seqState.stateLL), &(seqState.DStream), DTableLL); diff --git a/lib/zstd_internal.h b/lib/zstd_internal.h index 0b993b1e8..f34fb282f 100644 --- a/lib/zstd_internal.h +++ b/lib/zstd_internal.h @@ -81,7 +81,7 @@ static const size_t ZSTD_frameHeaderSize_min = 5; #define IS_RLE 3 #define MINMATCH 4 -#define REPCODE_STARTVALUE 4 +#define REPCODE_STARTVALUE 1 #define MLbits 7 #define LLbits 6 @@ -102,7 +102,7 @@ static const size_t ZSTD_frameHeaderSize_min = 5; #define HufLog 12 -#define MIN_SEQUENCES_SIZE 2 /*seqNb*/ +#define MIN_SEQUENCES_SIZE 1 /* seqNb */ #define MIN_CBLOCK_SIZE (1 /*litCSize*/ + MIN_SEQUENCES_SIZE) #define WILDCOPY_OVERLENGTH 8 From 35f7de52c8dc9c5d414eaae9c0300f0b5f875609 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 31 Jan 2016 02:51:03 +0100 Subject: [PATCH 22/34] fixed Visual warnings --- dictBuilder/dibcli.c | 9 +++++++++ dictBuilder/dictBuilder.c | 2 +- lib/zstd_compress.c | 4 ++-- lib/zstd_decompress.c | 3 +-- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/dictBuilder/dibcli.c b/dictBuilder/dibcli.c index 3ca6854db..f93e9707a 100644 --- a/dictBuilder/dibcli.c +++ b/dictBuilder/dibcli.c @@ -22,6 +22,15 @@ - 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 **************************************/ diff --git a/dictBuilder/dictBuilder.c b/dictBuilder/dictBuilder.c index ca3f66f17..fed9b18df 100644 --- a/dictBuilder/dictBuilder.c +++ b/dictBuilder/dictBuilder.c @@ -79,7 +79,7 @@ #define DICTLISTSIZE 10000 #define MEMMULT 11 -static const size_t maxMemory = (sizeof(size_t)==4) ? (2 GB - 64 MB) : (size_t)(3 GB) * MEMMULT; +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/zstd_compress.c b/lib/zstd_compress.c index 37550e6b7..6e3d6ca5a 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -457,7 +457,7 @@ static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc, U32 hType = IS_HUF; size_t clitSize; - if (maxDstSize < 4) return ERROR(dstSize_tooSmall); /* not enough space for compression */ + if (maxDstSize < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */ if (zc->flagStaticTables && (lhSize==3)) { hType = IS_PCH; @@ -547,7 +547,7 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, if ((oend-op) < MIN_SEQUENCES_SIZE) return ERROR(dstSize_tooSmall); if (nbSeq < 128) *op++ = (BYTE)nbSeq; else { - op[0] = (nbSeq>>8) + 128; op[1] = (BYTE)nbSeq; op+=2; + op[0] = (BYTE)((nbSeq>>8) + 128); op[1] = (BYTE)nbSeq; op+=2; } if (nbSeq==0) goto _check_compressibility; diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 96ba89365..6061c8741 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -812,8 +812,7 @@ static size_t ZSTD_decompressSequences( } /* check if reached exact end */ - if (nbSeq) - return ERROR(corruption_detected); /* DStream should be entirely and exactly consumed; otherwise data is corrupted */ + if (nbSeq) return ERROR(corruption_detected); } /* last literal segment */ From 7682e49d0a4c5d5b725962c82d0762da9e32eba8 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 31 Jan 2016 23:45:35 +0100 Subject: [PATCH 23/34] added buffer interface to dictBuilder --- dictBuilder/dibcli.c | 13 ++- dictBuilder/dictBuilder.c | 234 ++++++++++++++++++++++---------------- dictBuilder/dictBuilder.h | 55 +++++++-- 3 files changed, 193 insertions(+), 109 deletions(-) diff --git a/dictBuilder/dibcli.c b/dictBuilder/dibcli.c index f93e9707a..8566c6245 100644 --- a/dictBuilder/dibcli.c +++ b/dictBuilder/dibcli.c @@ -184,7 +184,7 @@ int main(int argCount, const char** argv) 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=0; cLevel=1; continue; } + if (!strcmp(argument, "--fast")) { selectionLevel=1; cLevel=1; continue; } /* Decode commands (note : aggregated commands are allowed) */ if (argument[0]=='-') { @@ -247,8 +247,15 @@ int main(int argCount, const char** argv) } /* building ... */ - DiB_setNotificationLevel(g_displayLevel); - operationResult = DiB_trainDictionary(dictFileName, maxDictSize, selectionLevel, cLevel, filenameTable, filenameIdx); + { + DiB_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); diff --git a/dictBuilder/dictBuilder.c b/dictBuilder/dictBuilder.c index fed9b18df..944853fbb 100644 --- a/dictBuilder/dictBuilder.c +++ b/dictBuilder/dictBuilder.c @@ -43,14 +43,14 @@ /*-************************************* * Includes ***************************************/ -#include /* malloc, free */ -#include /* memset */ -#include /* fprintf, fopen, ftello64 */ -#include /* stat64 */ -#include /* stat64 */ -#include /* clock */ +#include /* malloc, free */ +#include /* memset */ +#include /* fprintf, fopen, ftello64 */ +#include /* stat64 */ +#include /* stat64 */ +#include /* clock */ -#include "mem.h" /* read */ +#include "mem.h" /* read */ #include "error_private.h" #include "divsufsort.h" #include "dictBuilder.h" @@ -58,17 +58,13 @@ #include "huff0_static.h" -/* ************************************* +/*-************************************* * Compiler specifics ***************************************/ #if !defined(S_ISREG) # define S_ISREG(x) (((x) & S_IFMT) == S_IFREG) #endif -#ifdef _MSC_VER -#define snprintf sprintf_s -#endif - /*-************************************* * Constants @@ -87,6 +83,9 @@ static const size_t maxMemory = (sizeof(size_t) == 4) ? (2 GB - 64 MB) : ((size_ #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; /*-************************************* @@ -146,6 +145,10 @@ static unsigned DiB_GetMilliSpan(clock_t nPrevious) return nSpan; } +unsigned DiB_isError(size_t errorCode) { return ERR_isError(errorCode); } + +const char* DiB_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); } + /* ******************************************************** * File related operations @@ -563,9 +566,8 @@ static U32 DiB_dictSize(const dictItem* dictList) static void DiB_trainBuffer(dictItem* dictList, U32 dictListSize, const void* const buffer, const size_t bufferSize, /* buffer must end with noisy guard band */ - const char* displayName, - const size_t* fileSizes, unsigned nbFiles, unsigned maxDictSize, - U32 shiftRatio) + const size_t* fileSizes, unsigned nbFiles, + U32 shiftRatio, unsigned maxDictSize) { saidx_t* const suffix0 = (saidx_t*)malloc((bufferSize+2)*sizeof(*suffix0)); saidx_t* const suffix = suffix0+1; @@ -583,7 +585,7 @@ static void DiB_trainBuffer(dictItem* dictList, U32 dictListSize, memset(doneMarks, 0, bufferSize+16); /* sort */ - DISPLAYLEVEL(2, "sorting %s ...\n", displayName); + 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 */ @@ -699,7 +701,7 @@ static void DiB_countEStats(EStats_ress_t esr, #define OFFCODE_MAX 18 static size_t DiB_analyzeEntropy(void* dstBuffer, size_t maxDstSize, unsigned compressionLevel, - const void* srcBuffer, size_t* fileSizes, unsigned nbFiles, + const void* srcBuffer, const size_t* fileSizes, unsigned nbFiles, const void* dictBuffer, size_t dictBufferSize) { U32 countLit[256]; @@ -793,8 +795,7 @@ static size_t DiB_analyzeEntropy(void* dstBuffer, size_t maxDstSize, static void DiB_saveDict(const char* dictFileName, - const void* buff1, size_t buff1Size, - const void* buff2, size_t buff2Size) + const void* buff, size_t buffSize) { FILE* f; size_t n; @@ -802,11 +803,8 @@ static void DiB_saveDict(const char* dictFileName, f = fopen(dictFileName, "wb"); if (f==NULL) EXM_THROW(3, "cannot open %s ", dictFileName); - n = fwrite(buff1, 1, buff1Size, f); - if (n!=buff1Size) EXM_THROW(4, "%s : write error", dictFileName) - - n = fwrite(buff2, 1, buff2Size, f); - if (n!=buff2Size) EXM_THROW(4, "%s : write error", 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) @@ -853,46 +851,35 @@ static size_t DiB_fastSampling(void* dictBuffer, size_t dictSize, } -int DiB_trainDictionary(const char* dictFileName, unsigned maxDictSize, - unsigned shiftRatio, unsigned compressionLevel, - const char** fileNamesTable, unsigned nbFiles) +static size_t DiB_trainFromBuffer_internal( + void* dictBuffer, size_t maxDictSize, + const void* samplesBuffer, const size_t* sampleSizes, unsigned nbSamples, + DiB_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); - const U32 dictListSize = MAX( MAX(DICTLISTSIZE, nbFiles), maxDictSize/16); + const U32 dictListSize = MAX( MAX(DICTLISTSIZE, nbSamples), maxDictSize/16); dictItem* dictList = (dictItem*)malloc(dictListSize * sizeof(*dictList)); - char mfName[20] = {0}; - const char* displayName = NULL; + unsigned selectivity = params.selectivityLevel; + unsigned compressionLevel = params.compressionLevel; + size_t targetDictSize = maxDictSize - g_provision_entropySize; + size_t sBuffSize; + size_t dictSize = 0; + + /* checks */ + if (maxDictSize <= g_provision_entropySize + g_min_fast_dictContent) return ERROR(dstSize_tooSmall); /* 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) || (!dictList)) EXM_THROW(12, "not enough memory for DiB_trainFiles"); /* should not happen */ + { unsigned u; for (u=0, sBuffSize=0; u0) - { - snprintf (mfName, sizeof(mfName), " %u files", nbFiles); - if (nbFiles > 1) displayName = mfName; - else displayName = fileNamesTable[0]; - + /* select stripes */ + if (selectivity>1) { DiB_trainBuffer(dictList, dictListSize, - srcBuffer, benchedSize, - displayName, - fileSizes, nbFiles, maxDictSize, - shiftRatio); + samplesBuffer, sBuffSize, + sampleSizes, nbSamples, + selectivity, targetDictSize); /* display best matches */ if (g_displayLevel>= 3) { @@ -907,72 +894,127 @@ int DiB_trainDictionary(const char* dictFileName, unsigned maxDictSize, 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, (char*)srcBuffer+p, d); + DiB_printHex(3, (const char*)samplesBuffer+p, d); DISPLAYLEVEL(3, "| \n"); } } } /* create dictionary */ { - void* dictContent; U32 dictContentSize = DiB_dictSize(dictList); - void* dictHeader; - size_t dictHeaderSize, hSize, addedContentLength; + size_t hSize; BYTE* ptr; U32 u; - /* build dict */ - #define EBSIZE (2 KB) - dictHeaderSize = EBSIZE; - dictHeader = malloc(dictHeaderSize); - dictContent = malloc(maxDictSize); - if (!dictHeader || !dictContent) EXM_THROW(2, "not enough memory"); - /* build dict content */ - ptr = (BYTE*)dictContent + maxDictSize; + ptr = (BYTE*)dictBuffer + maxDictSize; for (u=1; upos; u++) { U32 l = dictList[u].length; ptr -= l; - memcpy(ptr, (char*)srcBuffer+dictList[u].pos, l); + if (ptr<(BYTE*)dictBuffer) return ERROR(GENERIC); /* should not happen */ + memcpy(ptr, (const char*)samplesBuffer+dictList[u].pos, l); } /* fast mode dict content */ - if (shiftRatio==0) { /* note could also be used to complete a dictionary, but not necessarily better */ - addedContentLength = ptr-(BYTE*)dictContent; - DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */ - DISPLAYLEVEL(2, "Adding %u KB from fast sampling \n", (U32)(addedContentLength>>10)); - addedContentLength = DiB_fastSampling(dictContent, addedContentLength, srcBuffer, benchedSize); - if (!ERR_isError(addedContentLength)) - ptr -= addedContentLength, dictContentSize += addedContentLength; + 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 = DiB_fastSampling((char*)dictBuffer + g_provision_entropySize, + targetDictSize, samplesBuffer, sBuffSize); } - /* dictionary header */ - MEM_writeLE32(dictHeader, ZSTD_DICT_MAGIC); + /* dictionary header */ + MEM_writeLE32(dictBuffer, ZSTD_DICT_MAGIC); hSize = 4; - dictHeaderSize -= 4; /* entropic tables */ + DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */ DISPLAYLEVEL(2, "statistics ... \n"); - hSize += DiB_analyzeEntropy((char*)dictHeader+4, dictHeaderSize, + hSize += DiB_analyzeEntropy((char*)dictBuffer+4, maxDictSize-4, compressionLevel, - srcBuffer, fileSizes, nbFiles, - ptr, dictContentSize); + samplesBuffer, sampleSizes, nbSamples, + (char*)dictBuffer + maxDictSize - dictContentSize, dictContentSize); - /* save dict */ - { - size_t dictSize = hSize + dictContentSize; - DISPLAYLEVEL(2, "Save dictionary of size %u into file %s \n", (U32)dictSize, dictFileName); - DiB_saveDict(dictFileName, dictHeader, hSize, ptr, dictContentSize); - //DiB_saveDict(dictFileName, NULL, 0, dictContent, dictContentSize); // content only - } - /* clean */ - free(dictHeader); - free(dictContent); + if (hSize + dictContentSize < maxDictSize) + memmove((char*)dictBuffer + hSize, (char*)dictBuffer + maxDictSize - dictContentSize, dictContentSize); + dictSize = MIN(maxDictSize, hSize+dictContentSize); } /* clean up */ - free(srcBuffer); - free(fileSizes); free(dictList); - return 0; + return dictSize; } + +/* 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 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; +} diff --git a/dictBuilder/dictBuilder.h b/dictBuilder/dictBuilder.h index 3c52c7daa..a022583eb 100644 --- a/dictBuilder/dictBuilder.h +++ b/dictBuilder/dictBuilder.h @@ -26,6 +26,9 @@ /* 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 ***************************************/ @@ -36,24 +39,56 @@ 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_trainDictionary - Train a dictionary from a set of files provided by @fileNamesTable - Resulting dictionary is written in file @dictFileName. - @selectivityLevel change criteria for insertion into the dictionary (more => bigger selection => larger dictionary) - @compressionLevel can be used to target a specific compression level of zstd. 0 means "default". - @result : 0 == ok +/*! 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() */ -int DiB_trainDictionary(const char* dictFileName, unsigned maxDictSize, - unsigned selectivityLevel, unsigned compressionLevel, - const char** fileNamesTable, unsigned nbFiles); +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. - 0 = no console notification (default). + default initial value : 0 = no console notification. Note : not thread-safe (use a global constant) */ void DiB_setNotificationLevel(unsigned l); + + +#endif From b35c4648bf73dcedf95a4a2117a97f28b2aefb84 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 1 Feb 2016 00:03:10 +0100 Subject: [PATCH 24/34] fixed clang warnings --- dictBuilder/dictBuilder.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dictBuilder/dictBuilder.c b/dictBuilder/dictBuilder.c index 944853fbb..d8b2bdb30 100644 --- a/dictBuilder/dictBuilder.c +++ b/dictBuilder/dictBuilder.c @@ -856,7 +856,7 @@ static size_t DiB_trainFromBuffer_internal( const void* samplesBuffer, const size_t* sampleSizes, unsigned nbSamples, DiB_params_t params) { - const U32 dictListSize = MAX( MAX(DICTLISTSIZE, nbSamples), maxDictSize/16); + const U32 dictListSize = MAX( MAX(DICTLISTSIZE, nbSamples), (U32)(maxDictSize/16)); dictItem* dictList = (dictItem*)malloc(dictListSize * sizeof(*dictList)); unsigned selectivity = params.selectivityLevel; unsigned compressionLevel = params.compressionLevel; @@ -879,7 +879,7 @@ static size_t DiB_trainFromBuffer_internal( DiB_trainBuffer(dictList, dictListSize, samplesBuffer, sBuffSize, sampleSizes, nbSamples, - selectivity, targetDictSize); + selectivity, (U32)targetDictSize); /* display best matches */ if (g_displayLevel>= 3) { @@ -918,7 +918,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 = DiB_fastSampling((char*)dictBuffer + g_provision_entropySize, + dictContentSize = (U32)DiB_fastSampling((char*)dictBuffer + g_provision_entropySize, targetDictSize, samplesBuffer, sBuffSize); } From 82d71fe89f223ce0fe5deb640780533db5bc2781 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 2 Feb 2016 00:29:00 +0100 Subject: [PATCH 25/34] added wildcard '*' expansion in DictBuilder under Visual --- visual/2013/dictBuilder/dictBuilder.vcxproj | 1 + 1 file changed, 1 insertion(+) diff --git a/visual/2013/dictBuilder/dictBuilder.vcxproj b/visual/2013/dictBuilder/dictBuilder.vcxproj index ad69449f6..0260102b5 100644 --- a/visual/2013/dictBuilder/dictBuilder.vcxproj +++ b/visual/2013/dictBuilder/dictBuilder.vcxproj @@ -99,6 +99,7 @@ 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) From 2ce4923238348cec3535aafaeec687ebb1fa4f30 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 2 Feb 2016 14:36:49 +0100 Subject: [PATCH 26/34] modified buffer management rules --- lib/zstd_compress.c | 62 ++++++++++++++++++++------------------------- programs/bench.c | 3 ++- programs/datagen.c | 42 ++++++++++++------------------ programs/fileio.c | 59 +++++++++++++----------------------------- 4 files changed, 63 insertions(+), 103 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 6e3d6ca5a..7252d750b 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -114,6 +114,7 @@ struct ZSTD_CCtx_s U32 dictLimit; /* below that point, need extDict */ U32 lowLimit; /* below that point, no more data */ U32 nextToUpdate; /* index from which to continue dictionary update */ + U32 loadedDictEnd; U32 stage; ZSTD_parameters params; void* workSpace; @@ -217,6 +218,7 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, zc->seqStore.dumpsStart = zc->seqStore.matchLengthStart + (blockSize>>2); zc->hbSize = 0; zc->stage = 0; + zc->loadedDictEnd = 0; return 0; } @@ -906,7 +908,7 @@ static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) } -/* ************************************* +/*-************************************* * Fast Scan ***************************************/ #define FILLHASHSTEP 3 @@ -916,7 +918,7 @@ static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls) const U32 hBits = zc->params.hashLog; const BYTE* const base = zc->base; const BYTE* ip = base + zc->nextToUpdate; - const BYTE* const iend = (const BYTE*) end; + const BYTE* const iend = ((const BYTE*)end) - 8; while(ip <= iend) { hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base); @@ -1885,47 +1887,41 @@ static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t maxDstSize, const void* src, size_t srcSize) { ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.strategy, zc->lowLimit < zc->dictLimit); - if (srcSize < MIN_CBLOCK_SIZE+3) return 0; /* don't even attempt compression below a certain srcSize */ + if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) return 0; /* don't even attempt compression below a certain srcSize */ blockCompressor(zc, src, srcSize); return ZSTD_compressSequences(zc, dst, maxDstSize, srcSize); } -static size_t ZSTD_compress_generic (ZSTD_CCtx* ctxPtr, +static size_t ZSTD_compress_generic (ZSTD_CCtx* zc, void* dst, size_t maxDstSize, const void* src, size_t srcSize) { - size_t blockSize = ctxPtr->blockSize; + size_t blockSize = zc->blockSize; size_t remaining = srcSize; const BYTE* ip = (const BYTE*)src; BYTE* const ostart = (BYTE*)dst; BYTE* op = ostart; - const U32 maxDist = 1 << ctxPtr->params.windowLog; + const U32 maxDist = 1 << zc->params.windowLog; - while (remaining) - { + while (remaining) { size_t cSize; - if (maxDstSize < 3 + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */ + if (maxDstSize < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */ if (remaining < blockSize) blockSize = remaining; - if ((U32)(ip+blockSize - (ctxPtr->base + ctxPtr->lowLimit)) > maxDist) - { - /* respect windowLog contract */ - ctxPtr->lowLimit = (U32)(ip+blockSize - ctxPtr->base) - maxDist; - if (ctxPtr->dictLimit < ctxPtr->lowLimit) ctxPtr->dictLimit = ctxPtr->lowLimit; + if ((U32)(ip+blockSize - zc->base) > zc->loadedDictEnd + maxDist) { /* enforce maxDist */ + zc->lowLimit = (U32)(ip+blockSize - zc->base) - maxDist; + if (zc->dictLimit < zc->lowLimit) zc->dictLimit = zc->lowLimit; } - cSize = ZSTD_compressBlock_internal(ctxPtr, op+3, maxDstSize-3, ip, blockSize); + cSize = ZSTD_compressBlock_internal(zc, op+ZSTD_blockHeaderSize, maxDstSize-ZSTD_blockHeaderSize, ip, blockSize); if (ZSTD_isError(cSize)) return cSize; - if (cSize == 0) - { - cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, blockSize); /* block is not compressible */ + if (cSize == 0) { /* block is not compressible */ + cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, blockSize); if (ZSTD_isError(cSize)) return cSize; - } - else - { + } else { op[0] = (BYTE)(cSize>>16); op[1] = (BYTE)(cSize>>8); op[2] = (BYTE)cSize; @@ -1951,8 +1947,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc, const BYTE* const ip = (const BYTE*) src; size_t hbSize = 0; - if (frame && (zc->stage==0)) - { + if (frame && (zc->stage==0)) { hbSize = zc->hbSize; if (dstSize <= hbSize) return ERROR(dstSize_tooSmall); zc->stage = 1; @@ -1962,8 +1957,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc, } /* Check if blocks follow each other */ - if (src != zc->nextSrc) - { + if (src != zc->nextSrc) { /* not contiguous */ size_t delta = zc->nextSrc - ip; zc->lowLimit = zc->dictLimit; @@ -1975,8 +1969,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc, } /* preemptive overflow correction */ - if (zc->lowLimit > (1<<30)) - { + if (zc->lowLimit > (1<<30)) { U32 btplus = (zc->params.strategy == ZSTD_btlazy2); U32 contentMask = (1 << (zc->params.contentLog - btplus)) - 1; U32 newLowLimit = zc->lowLimit & contentMask; /* preserve position % contentSize */ @@ -1991,8 +1984,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc, } /* if input and dictionary overlap : reduce dictionary (presumed modified by input) */ - if ((ip+srcSize > zc->dictBase + zc->lowLimit) && (ip < zc->dictBase + zc->dictLimit)) - { + if ((ip+srcSize > zc->dictBase + zc->lowLimit) && (ip < zc->dictBase + zc->dictLimit)) { zc->lowLimit = (U32)(ip + srcSize - zc->dictBase); if (zc->lowLimit > zc->dictLimit) zc->lowLimit = zc->dictLimit; } @@ -2034,6 +2026,7 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t zc->dictBase = zc->base; zc->base += ip - zc->nextSrc; zc->nextToUpdate = zc->dictLimit; + zc->loadedDictEnd = (U32)(iend - zc->base); zc->nextSrc = iend; if (srcSize <= 8) return 0; @@ -2041,7 +2034,7 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t switch(zc->params.strategy) { case ZSTD_fast: - ZSTD_fillHashTable (zc, iend-8, zc->params.searchLength); + ZSTD_fillHashTable (zc, iend, zc->params.searchLength); break; case ZSTD_greedy: @@ -2052,13 +2045,13 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t case ZSTD_btlazy2: ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength); - zc->nextToUpdate = (U32)(iend - zc->base); break; default: return ERROR(GENERIC); /* strategy doesn't exist; impossible */ } + zc->nextToUpdate = zc->loadedDictEnd; return 0; } @@ -2112,8 +2105,7 @@ static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize) { - if (dict && dictSize) - { + if (dict && (dictSize>4)) { U32 magic = MEM_readLE32(dict); size_t eSize; if (magic != ZSTD_DICT_MAGIC) @@ -2151,7 +2143,7 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc, size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* zc, const void* dict, size_t dictSize, int compressionLevel) { - return ZSTD_compressBegin_advanced(zc, dict, dictSize, ZSTD_getParams(compressionLevel, 0)); + return ZSTD_compressBegin_advanced(zc, dict, dictSize, ZSTD_getParams(compressionLevel, 128 KB)); } size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel) @@ -2235,7 +2227,7 @@ size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize, const void* dict, size_t dictSize, int compressionLevel) { - return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, dict, dictSize, ZSTD_getParams(compressionLevel, srcSize+dictSize)); + return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, dict, dictSize, ZSTD_getParams(compressionLevel, srcSize)); } size_t ZSTD_compressCCtx (ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel) diff --git a/programs/bench.c b/programs/bench.c index d24991431..1c776c4e6 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -212,6 +212,7 @@ typedef struct } blockParam_t; #define MIN(a,b) ((a)<(b) ? (a) : (b)) +#define MAX(a,b) ((a)>(b) ? (a) : (b)) static int BMK_benchMem(const void* srcBuffer, size_t srcSize, const char* displayName, int cLevel, @@ -289,7 +290,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, while (BMK_GetMilliStart() == milliTime); milliTime = BMK_GetMilliStart(); while (BMK_GetMilliSpan(milliTime) < TIMELOOP) { - ZSTD_compressBegin_advanced(refCtx, dictBuffer, dictBufferSize, ZSTD_getParams(cLevel, dictBufferSize+largestBlockSize)); + ZSTD_compressBegin_advanced(refCtx, dictBuffer, dictBufferSize, ZSTD_getParams(cLevel, MAX(dictBufferSize, largestBlockSize))); for (blockNb=0; blockNb /* malloc */ @@ -31,7 +31,7 @@ #include /* memcpy */ -/************************************** +/*-************************************ * Basic Types **************************************/ #if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */ @@ -50,7 +50,7 @@ #endif -/************************************** +/*-************************************ * OS-specific Includes **************************************/ #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) @@ -62,7 +62,7 @@ #endif -/************************************** +/*-************************************ * Constants **************************************/ #define KB *(1 <<10) @@ -71,7 +71,7 @@ #define PRIME2 2246822519U -/************************************** +/*-************************************ * Local types **************************************/ #define LTLOG 13 @@ -81,7 +81,7 @@ typedef BYTE litDistribTable[LTSIZE]; -/********************************************************* +/*-******************************************************* * Local Functions *********************************************************/ #define RDG_rotl32(x,r) ((x << r) | (x >> (32 - r))) @@ -103,14 +103,12 @@ static void RDG_fillLiteralDistrib(litDistribTable lt, double ld) BYTE firstChar = '('; BYTE lastChar = '}'; - if (ld==0.0) - { + if (ld==0.0) { character = 0; firstChar = 0; lastChar =255; } - while (i LTSIZE) weight = LTSIZE-i; @@ -140,13 +138,11 @@ void RDG_genBlock(void* buffer, size_t buffSize, size_t prefixSize, double match U32 prevOffset = 1; /* special case : sparse content */ - while (matchProba >= 1.0) - { + while (matchProba >= 1.0) { size_t size0 = RDG_rand(seed) & 3; size0 = (size_t)1 << (16 + size0 * 2); size0 += RDG_rand(seed) & (size0-1); /* because size0 is power of 2*/ - if (buffSize < pos + size0) - { + if (buffSize < pos + size0) { memset(buffPtr+pos, 0, buffSize-pos); return; } @@ -160,11 +156,9 @@ void RDG_genBlock(void* buffer, size_t buffSize, size_t prefixSize, double match if (pos==0) buffPtr[0] = RDG_genChar(seed, lt), pos=1; /* Generate compressible data */ - while (pos < buffSize) - { + while (pos < buffSize) { /* Select : Literal (char) or Match (within 32K) */ - if (RDG_RAND15BITS < matchProba32) - { + if (RDG_RAND15BITS < matchProba32) { /* Copy (within 32K) */ size_t match; size_t d; @@ -178,17 +172,14 @@ void RDG_genBlock(void* buffer, size_t buffSize, size_t prefixSize, double match d = pos + length; if (d > buffSize) d = buffSize; while (pos < d) buffPtr[pos++] = buffPtr[match++]; /* correctly manages overlaps */ - } - else - { + } else { /* Literal (noise) */ size_t d; size_t length = RDG_RANDLENGTH; d = pos + length; if (d > buffSize) d = buffSize; while (pos < d) buffPtr[pos++] = RDG_genChar(seed, lt); - } - } + } } } @@ -220,8 +211,7 @@ void RDG_genStdout(unsigned long long size, double matchProba, double litProba, RDG_genBlock(buff, RDG_DICTSIZE, 0, matchProba, lt, &seed); /* Generate compressible data */ - while (total < size) - { + while (total < size) { RDG_genBlock(buff, RDG_DICTSIZE+RDG_BLOCKSIZE, RDG_DICTSIZE, matchProba, lt, &seed); if (size-total < RDG_BLOCKSIZE) genBlockSize = (size_t)(size-total); total += genBlockSize; @@ -230,6 +220,6 @@ void RDG_genStdout(unsigned long long size, double matchProba, double litProba, memcpy(buff, buff + RDG_BLOCKSIZE, RDG_DICTSIZE); } - // cleanup + /* cleanup */ free(buff); } diff --git a/programs/fileio.c b/programs/fileio.c index 9ce8d8cfe..ed2a06181 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -193,42 +193,30 @@ static U64 FIO_getFileSize(const char* infilename) static int FIO_getFiles(FILE** fileOutPtr, FILE** fileInPtr, const char* dstFileName, const char* srcFileName) { - if (!strcmp (srcFileName, stdinmark)) - { + if (!strcmp (srcFileName, stdinmark)) { DISPLAYLEVEL(4,"Using stdin for input\n"); *fileInPtr = stdin; SET_BINARY_MODE(stdin); - } - else - { + } else { *fileInPtr = fopen(srcFileName, "rb"); } - if ( *fileInPtr==0 ) - { + if ( *fileInPtr==0 ) { DISPLAYLEVEL(1, "Unable to access file for processing: %s\n", srcFileName); return 1; } - if (!strcmp (dstFileName, stdoutmark)) - { + if (!strcmp (dstFileName, stdoutmark)) { DISPLAYLEVEL(4,"Using stdout for output\n"); *fileOutPtr = stdout; SET_BINARY_MODE(stdout); - } - else - { - /* Check if destination file already exists */ - if (!g_overwrite) - { + } else { + if (!g_overwrite) { /* Check if destination file already exists */ *fileOutPtr = fopen( dstFileName, "rb" ); - if (*fileOutPtr != 0) - { - /* prompt for overwrite authorization */ + 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)) - { + if ((g_displayLevel <= 1) || (*fileInPtr == stdin)) { /* No interaction possible */ DISPLAY("Operation aborted : %s already exists \n", dstFileName); return 1; @@ -236,15 +224,12 @@ static int FIO_getFiles(FILE** fileOutPtr, FILE** fileInPtr, DISPLAY("Overwrite ? (y/N) : "); { int ch = getchar(); - if ((ch!='Y') && (ch!='y')) - { + 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" ); } @@ -265,15 +250,13 @@ static size_t FIO_loadFile(void** bufferPtr, const char* fileName) U64 fileSize; *bufferPtr = NULL; - if (fileName == NULL) - return 0; + if (fileName == NULL) return 0; DISPLAYLEVEL(4,"Loading %s as dictionary \n", fileName); fileHandle = fopen(fileName, "rb"); if (fileHandle==0) EXM_THROW(31, "Error opening file %s", fileName); fileSize = FIO_getFileSize(fileName); - if (fileSize > MAX_DICT_SIZE) - { + if (fileSize > MAX_DICT_SIZE) { int seekResult; if (fileSize > 1 GB) EXM_THROW(32, "Dictionary file %s is too large", fileName); /* avoid extreme cases */ DISPLAYLEVEL(2,"Dictionary %s is too large : using last %u bytes only \n", fileName, MAX_DICT_SIZE); @@ -455,8 +438,7 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile ress = FIO_createCResources(dictFileName); /* loop on each file */ - for (u=0; u version */ size_t toRead = 4; @@ -573,8 +553,7 @@ static int FIO_decompressFile_extRess(dRess_t ress, if (sizeCheck==0) break; /* no more input */ if (sizeCheck != toRead) EXM_THROW(31, "Read error : cannot read header"); #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1) - if (ZSTD_isLegacy(MEM_readLE32(ress.srcBuffer))) - { + if (ZSTD_isLegacy(MEM_readLE32(ress.srcBuffer))) { filesize += FIO_decompressLegacyFrame(dstFile, srcFile, MEM_readLE32(ress.srcBuffer)); continue; } @@ -624,14 +603,12 @@ int FIO_decompressMultipleFilenames(const char** srcNamesTable, unsigned nbFiles if (dstFileName==NULL) EXM_THROW(70, "not enough memory for dstFileName"); ress = FIO_createDResources(dictFileName); - for (u=0; u Date: Tue, 2 Feb 2016 16:00:50 +0100 Subject: [PATCH 27/34] fixed encoding bugs --- lib/zstd_compress.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 7252d750b..3dd865151 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -251,6 +251,7 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx) dstCCtx->dictBase = srcCCtx->dictBase; dstCCtx->dictLimit = srcCCtx->dictLimit; dstCCtx->lowLimit = srcCCtx->lowLimit; + dstCCtx->loadedDictEnd = srcCCtx->loadedDictEnd; /* copy entropy tables */ dstCCtx->flagStaticTables = srcCCtx->flagStaticTables; @@ -1911,7 +1912,8 @@ static size_t ZSTD_compress_generic (ZSTD_CCtx* zc, if (remaining < blockSize) blockSize = remaining; if ((U32)(ip+blockSize - zc->base) > zc->loadedDictEnd + maxDist) { /* enforce maxDist */ - zc->lowLimit = (U32)(ip+blockSize - zc->base) - maxDist; + U32 newLowLimit = (U32)(ip+blockSize - zc->base) - maxDist; + if (zc->lowLimit < newLowLimit) zc->lowLimit = newLowLimit; if (zc->dictLimit < zc->lowLimit) zc->dictLimit = zc->lowLimit; } From 7d8e6bddb98a085514982b802fb1c8ce980320fb Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 2 Feb 2016 17:30:37 +0100 Subject: [PATCH 28/34] changed long length format --- lib/zstd_compress.c | 18 +++++++++++++++--- lib/zstd_decompress.c | 10 ++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 3dd865151..c89d5ca1b 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -718,7 +718,7 @@ _check_compressibility: */ MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offsetCode, size_t matchCode) { -#if 0 +#if 0 /* for debug */ static const BYTE* g_start = NULL; if (g_start==NULL) g_start = literals; //if (literals - g_start == 8695) @@ -737,7 +737,13 @@ MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const B *(seqStorePtr->dumps++) = (BYTE)(litLength - MaxLL); } else { *(seqStorePtr->dumps++) = 255; - MEM_writeLE32(seqStorePtr->dumps, (U32)litLength); seqStorePtr->dumps += 3; + if (litLength < (1<<15)) { + MEM_writeLE16(seqStorePtr->dumps, (U16)(litLength<<1)); + seqStorePtr->dumps += 2; + } else { + MEM_writeLE32(seqStorePtr->dumps, (U32)((litLength<<1)+1)); + seqStorePtr->dumps += 3; + } } } else *(seqStorePtr->litLength++) = (BYTE)litLength; @@ -751,7 +757,13 @@ MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const B *(seqStorePtr->dumps++) = (BYTE)(matchCode - MaxML); } else { *(seqStorePtr->dumps++) = 255; - MEM_writeLE32(seqStorePtr->dumps, (U32)matchCode); seqStorePtr->dumps += 3; + if (matchCode < (1<<15)) { + MEM_writeLE16(seqStorePtr->dumps, (U16)(matchCode<<1)); + seqStorePtr->dumps += 2; + } else { + MEM_writeLE32(seqStorePtr->dumps, (U32)((matchCode<<1)+1)); + seqStorePtr->dumps += 3; + } } } else *(seqStorePtr->matchLength++) = (BYTE)matchCode; } diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 6061c8741..5d637d2bb 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -626,8 +626,9 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) U32 add = *dumps++; if (add < 255) litLength += add; else { - litLength = MEM_readLE32(dumps) & 0xFFFFFF; /* no pb : dumps is always followed by seq tables > 1 byte */ - dumps += 3; + litLength = MEM_readLE32(dumps) & 0xFFFFFF; /* no risk : dumps is always followed by seq tables > 1 byte */ + if (litLength&1) litLength>>=1, dumps += 3; + else litLength = (U16)(litLength)>>1, dumps += 2; } if (dumps >= de) dumps = de-1; /* late correction, to avoid read overflow (data is now corrupted anyway) */ } @@ -659,7 +660,8 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) if (add < 255) matchLength += add; else { matchLength = MEM_readLE32(dumps) & 0xFFFFFF; /* no pb : dumps is always followed by seq tables > 1 byte */ - dumps += 3; + if (matchLength&1) matchLength>>=1, dumps += 3; + else matchLength = (U16)(matchLength)>>1, dumps += 2; } if (dumps >= de) dumps = de-1; /* late correction, to avoid read overflow (data is now corrupted anyway) */ } @@ -671,7 +673,7 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState) seq->matchLength = matchLength; seqState->dumps = dumps; -#if 0 +#if 0 /* debug */ { static U64 totalDecoded = 0; printf("pos %6u : %3u literals & match %3u bytes at distance %6u \n", From 464fa996e9589cc20d7bb83d0daa4520f8e37991 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 3 Feb 2016 01:09:46 +0100 Subject: [PATCH 29/34] added v0.4 legacy support --- lib/Makefile | 2 +- lib/legacy/zstd_legacy.h | 6 +- lib/legacy/zstd_v04.c | 4431 +++++++++++++++++++++++++++++++ lib/legacy/zstd_v04.h | 148 ++ programs/Makefile | 2 +- programs/fuzzer.c | 2 +- programs/legacy/fileio_legacy.c | 82 + 7 files changed, 4669 insertions(+), 4 deletions(-) create mode 100644 lib/legacy/zstd_v04.c create mode 100644 lib/legacy/zstd_v04.h diff --git a/lib/Makefile b/lib/Makefile index a7172b6f8..e0ca0c626 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -53,7 +53,7 @@ LIBDIR ?= $(PREFIX)/lib INCLUDEDIR=$(PREFIX)/include ZSTD_FILES := zstd_compress.c zstd_decompress.c fse.c huff0.c -ZSTD_LEGACY:= legacy/zstd_v01.c legacy/zstd_v02.c legacy/zstd_v03.c +ZSTD_LEGACY:= legacy/zstd_v01.c legacy/zstd_v02.c legacy/zstd_v03.c legacy/zstd_v04.c ifeq ($(ZSTD_LEGACY_SUPPORT), 0) CPPFLAGS += -DZSTD_LEGACY_SUPPORT=0 diff --git a/lib/legacy/zstd_legacy.h b/lib/legacy/zstd_legacy.h index b3e5eb204..4ae1deb68 100644 --- a/lib/legacy/zstd_legacy.h +++ b/lib/legacy/zstd_legacy.h @@ -45,6 +45,7 @@ extern "C" { #include "zstd_v01.h" #include "zstd_v02.h" #include "zstd_v03.h" +#include "zstd_v04.h" MEM_STATIC unsigned ZSTD_isLegacy (U32 magicNumberLE) { @@ -52,7 +53,8 @@ MEM_STATIC unsigned ZSTD_isLegacy (U32 magicNumberLE) { case ZSTDv01_magicNumberLE : case ZSTDv02_magicNumber : - case ZSTDv03_magicNumber : return 1; + case ZSTDv03_magicNumber : + case ZSTDv04_magicNumber : return 1; default : return 0; } } @@ -71,6 +73,8 @@ MEM_STATIC size_t ZSTD_decompressLegacy( return ZSTDv02_decompress(dst, maxOriginalSize, src, compressedSize); case ZSTDv03_magicNumber : return ZSTDv03_decompress(dst, maxOriginalSize, src, compressedSize); + case ZSTDv04_magicNumber : + return ZSTDv04_decompress(dst, maxOriginalSize, src, compressedSize); default : return ERROR(prefix_unknown); } diff --git a/lib/legacy/zstd_v04.c b/lib/legacy/zstd_v04.c new file mode 100644 index 000000000..45a3f61cc --- /dev/null +++ b/lib/legacy/zstd_v04.c @@ -0,0 +1,4431 @@ +/* ****************************************************************** + zstd_v04.c + Decompression module for ZSTD v0.4 legacy format + Copyright (C) 2016, 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 : + - Homepage : http://www.zstd.net/ +****************************************************************** */ + +/*- Dependencies -*/ +#include "zstd_v04.h" + + +/* ****************************************************************** + mem.h + low-level memory access routines + Copyright (C) 2013-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 : + - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy + - Public forum : https://groups.google.com/forum/#!forum/lz4c +****************************************************************** */ +#ifndef MEM_H_MODULE +#define MEM_H_MODULE + +#if defined (__cplusplus) +extern "C" { +#endif + +/****************************************** +* Includes +******************************************/ +#include /* size_t, ptrdiff_t */ +#include /* memcpy */ + + +/****************************************** +* Compiler-specific +******************************************/ +#if defined(__GNUC__) +# define MEM_STATIC static __attribute__((unused)) +#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define MEM_STATIC static inline +#elif defined(_MSC_VER) +# define MEM_STATIC static __inline +#else +# define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ +#endif + + +/**************************************************************** +* Basic Types +*****************************************************************/ +#if defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# include + typedef uint8_t BYTE; + typedef uint16_t U16; + typedef int16_t S16; + typedef uint32_t U32; + typedef int32_t S32; + typedef uint64_t U64; + typedef int64_t S64; +#else + typedef unsigned char BYTE; + typedef unsigned short U16; + typedef signed short S16; + typedef unsigned int U32; + typedef signed int S32; + typedef unsigned long long U64; + typedef signed long long S64; +#endif + + +/**************************************************************** +* Memory I/O +*****************************************************************/ +/* 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. + * Method 0 (default) : use `memcpy()`. Safe and portable. + * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable). + * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. + * Method 2 : direct access. This method is portable but violate C standard. + * It can generate buggy code on targets generating assembly depending on alignment. + * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6) + * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. + * Prefer these methods in priority order (0 > 1 > 2) + */ +#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ +# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) +# define MEM_FORCE_MEMORY_ACCESS 2 +# elif defined(__INTEL_COMPILER) || \ + (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) +# define MEM_FORCE_MEMORY_ACCESS 1 +# endif +#endif + +MEM_STATIC unsigned MEM_32bits(void) { return sizeof(void*)==4; } +MEM_STATIC unsigned MEM_64bits(void) { return sizeof(void*)==8; } + +MEM_STATIC unsigned MEM_isLittleEndian(void) +{ + const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ + return one.c[0]; +} + +#if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2) + +/* violates C standard 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 void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; } +MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; } +MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; } + +#elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1) + +/* __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; + +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 void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; } +MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; } +MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign*)memPtr)->u64 = value; } + +#else + +/* default method, safe and standard. + can sometimes prove slower */ + +MEM_STATIC U16 MEM_read16(const void* memPtr) +{ + U16 val; memcpy(&val, memPtr, sizeof(val)); return val; +} + +MEM_STATIC U32 MEM_read32(const void* memPtr) +{ + U32 val; memcpy(&val, memPtr, sizeof(val)); return val; +} + +MEM_STATIC U64 MEM_read64(const void* memPtr) +{ + U64 val; memcpy(&val, memPtr, sizeof(val)); return val; +} + +MEM_STATIC void MEM_write16(void* memPtr, U16 value) +{ + memcpy(memPtr, &value, sizeof(value)); +} + +MEM_STATIC void MEM_write32(void* memPtr, U32 value) +{ + memcpy(memPtr, &value, sizeof(value)); +} + +MEM_STATIC void MEM_write64(void* memPtr, U64 value) +{ + memcpy(memPtr, &value, sizeof(value)); +} + +#endif // MEM_FORCE_MEMORY_ACCESS + + +MEM_STATIC U16 MEM_readLE16(const void* memPtr) +{ + if (MEM_isLittleEndian()) + return MEM_read16(memPtr); + else + { + const BYTE* p = (const BYTE*)memPtr; + return (U16)(p[0] + (p[1]<<8)); + } +} + +MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) +{ + if (MEM_isLittleEndian()) + { + MEM_write16(memPtr, val); + } + else + { + BYTE* p = (BYTE*)memPtr; + p[0] = (BYTE)val; + p[1] = (BYTE)(val>>8); + } +} + +MEM_STATIC U32 MEM_readLE32(const void* memPtr) +{ + if (MEM_isLittleEndian()) + return MEM_read32(memPtr); + else + { + const BYTE* p = (const BYTE*)memPtr; + return (U32)((U32)p[0] + ((U32)p[1]<<8) + ((U32)p[2]<<16) + ((U32)p[3]<<24)); + } +} + +MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32) +{ + if (MEM_isLittleEndian()) + { + MEM_write32(memPtr, val32); + } + else + { + BYTE* p = (BYTE*)memPtr; + p[0] = (BYTE)val32; + p[1] = (BYTE)(val32>>8); + p[2] = (BYTE)(val32>>16); + p[3] = (BYTE)(val32>>24); + } +} + +MEM_STATIC U64 MEM_readLE64(const void* memPtr) +{ + if (MEM_isLittleEndian()) + return MEM_read64(memPtr); + else + { + const BYTE* p = (const BYTE*)memPtr; + return (U64)((U64)p[0] + ((U64)p[1]<<8) + ((U64)p[2]<<16) + ((U64)p[3]<<24) + + ((U64)p[4]<<32) + ((U64)p[5]<<40) + ((U64)p[6]<<48) + ((U64)p[7]<<56)); + } +} + +MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64) +{ + if (MEM_isLittleEndian()) + { + MEM_write64(memPtr, val64); + } + else + { + BYTE* p = (BYTE*)memPtr; + p[0] = (BYTE)val64; + p[1] = (BYTE)(val64>>8); + p[2] = (BYTE)(val64>>16); + p[3] = (BYTE)(val64>>24); + p[4] = (BYTE)(val64>>32); + p[5] = (BYTE)(val64>>40); + p[6] = (BYTE)(val64>>48); + p[7] = (BYTE)(val64>>56); + } +} + +MEM_STATIC size_t MEM_readLEST(const void* memPtr) +{ + if (MEM_32bits()) + return (size_t)MEM_readLE32(memPtr); + else + return (size_t)MEM_readLE64(memPtr); +} + +MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val) +{ + if (MEM_32bits()) + MEM_writeLE32(memPtr, (U32)val); + else + MEM_writeLE64(memPtr, (U64)val); +} + +#if defined (__cplusplus) +} +#endif + +#endif /* MEM_H_MODULE */ + +/* ****************************************************************** + Error codes list + Copyright (C) 2016, 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 : + - Source repository : https://github.com/Cyan4973/zstd +****************************************************************** */ +#ifndef ERROR_PUBLIC_H_MODULE +#define ERROR_PUBLIC_H_MODULE + +#if defined (__cplusplus) +extern "C" { +#endif + + +/* **************************************** +* error list +******************************************/ +enum { + ZSTD_error_No_Error, + ZSTD_error_GENERIC, + ZSTD_error_prefix_unknown, + ZSTD_error_frameParameter_unsupported, + ZSTD_error_frameParameter_unsupportedBy32bitsImplementation, + ZSTD_error_init_missing, + ZSTD_error_memory_allocation, + ZSTD_error_stage_wrong, + ZSTD_error_dstSize_tooSmall, + ZSTD_error_srcSize_wrong, + ZSTD_error_corruption_detected, + ZSTD_error_tableLog_tooLarge, + ZSTD_error_maxSymbolValue_tooLarge, + ZSTD_error_maxSymbolValue_tooSmall, + ZSTD_error_maxCode +}; + +/* note : functions provide error codes in reverse negative order, + so compare with (size_t)(0-enum) */ + + +#if defined (__cplusplus) +} +#endif + +#endif /* ERROR_PUBLIC_H_MODULE */ + + + +/* + zstd - standard compression library + Header File for static linking only + Copyright (C) 2014-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://github.com/Cyan4973/zstd + - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c +*/ +#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. + */ + +#if defined (__cplusplus) +extern "C" { +#endif + +/* ************************************* +* Types +***************************************/ +#define ZSTD_WINDOWLOG_MAX 26 +#define ZSTD_WINDOWLOG_MIN 18 +#define ZSTD_WINDOWLOG_ABSOLUTEMIN 11 +#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_SEARCHLOG_MAX (ZSTD_CONTENTLOG_MAX-1) +#define ZSTD_SEARCHLOG_MIN 1 +#define ZSTD_SEARCHLENGTH_MAX 7 +#define ZSTD_SEARCHLENGTH_MIN 4 + +/** from faster to stronger */ +typedef enum { ZSTD_fast, ZSTD_greedy, ZSTD_lazy, ZSTD_lazy2, ZSTD_btlazy2 } ZSTD_strategy; + +typedef struct +{ + U64 srcSize; /* optional : tells how much bytes are present in the frame. Use 0 if not known. */ + 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 searchLog; /* nb of searches : larger == more compression, slower */ + U32 searchLength; /* size of matches : larger == faster decompression, sometimes less compression */ + ZSTD_strategy strategy; +} ZSTD_parameters; + +typedef ZSTDv04_Dctx ZSTD_DCtx; + +/* ************************************* +* Advanced functions +***************************************/ +/** ZSTD_decompress_usingDict +* Same as ZSTD_decompressDCtx, using a Dictionary content as prefix +* Note : dict can be NULL, in which case, it's equivalent to ZSTD_decompressDCtx() */ +static size_t ZSTD_decompress_usingDict(ZSTD_DCtx* ctx, + void* dst, size_t maxDstSize, + const void* src, size_t srcSize, + const void* dict,size_t dictSize); + + +/* ************************************** +* Streaming functions (direct mode) +****************************************/ +static size_t ZSTD_resetDCtx(ZSTD_DCtx* dctx); +static size_t ZSTD_getFrameParams(ZSTD_parameters* params, const void* src, size_t srcSize); +static void ZSTD_decompress_insertDictionary(ZSTD_DCtx* ctx, const void* src, size_t srcSize); + +static size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); +static size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize); + +/** + Streaming decompression, bufferless mode + + A ZSTD_DCtx object is required to track streaming operations. + Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it. + A ZSTD_DCtx object can be re-used multiple times. Use ZSTD_resetDCtx() to return to fresh status. + + First operation is to retrieve frame parameters, using ZSTD_getFrameParams(). + This function doesn't consume its input. It needs enough input data to properly decode the frame header. + Objective is to retrieve *params.windowlog, to know minimum amount of memory required during decoding. + Result : 0 when successful, it means the ZSTD_parameters structure has been filled. + >0 : means there is not enough data into src. Provides the expected size to successfully decode header. + errorCode, which can be tested using ZSTD_isError() (For example, if it's not a ZSTD header) + + Then, you can optionally insert a dictionary. + This operation must mimic the compressor behavior, otherwise decompression will fail or be corrupted. + + Then it's possible to start decompression. + Use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively. + ZSTD_nextSrcSizeToDecompress() tells how much bytes to provide as 'srcSize' to ZSTD_decompressContinue(). + ZSTD_decompressContinue() requires this exact amount of bytes, or it will fail. + ZSTD_decompressContinue() needs previous data blocks during decompression, up to (1 << windowlog). + They should preferably be located contiguously, prior to current block. Alternatively, a round buffer is also possible. + + @result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst'. + It can be zero, which is not an error; it just means ZSTD_decompressContinue() has decoded some header. + + A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero. + Context can then be reset to start a new decompression. +*/ + + +#if defined (__cplusplus) +} +#endif + +/* ****************************************************************** + Error codes and messages + Copyright (C) 2013-2016, 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 : + - Source repository : https://github.com/Cyan4973/zstd +****************************************************************** */ +/* Note : this module is expected to remain private, do not expose it */ + +#ifndef ERROR_H_MODULE +#define ERROR_H_MODULE + +#if defined (__cplusplus) +extern "C" { +#endif + + +/* ***************************************** +* Includes +******************************************/ +#include /* size_t, ptrdiff_t */ + + +/* ***************************************** +* Compiler-specific +******************************************/ +#if defined(__GNUC__) +# define ERR_STATIC static __attribute__((unused)) +#elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# define ERR_STATIC static inline +#elif defined(_MSC_VER) +# define ERR_STATIC static __inline +#else +# define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ +#endif + + +/* ***************************************** +* Error Codes +******************************************/ +#define PREFIX(name) ZSTD_error_##name + +#ifdef ERROR +# undef ERROR /* reported already defined on VS 2015 by Rich Geldreich */ +#endif +#define ERROR(name) (size_t)-PREFIX(name) + +ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } + + +/* ***************************************** +* Error Strings +******************************************/ + +ERR_STATIC const char* ERR_getErrorName(size_t code) +{ + static const char* codeError = "Unspecified error code"; + switch( (size_t)(0-code) ) + { + case ZSTD_error_No_Error: return "No error detected"; + case ZSTD_error_GENERIC: return "Error (generic)"; + case ZSTD_error_prefix_unknown: return "Unknown frame descriptor"; + case ZSTD_error_frameParameter_unsupported: return "Unsupported frame parameter"; + case ZSTD_error_frameParameter_unsupportedBy32bitsImplementation: return "Frame parameter unsupported in 32-bits mode"; + case ZSTD_error_init_missing: return "Context should be init first"; + case ZSTD_error_memory_allocation: return "Allocation error : not enough memory"; + case ZSTD_error_dstSize_tooSmall: return "Destination buffer is too small"; + case ZSTD_error_srcSize_wrong: return "Src size incorrect"; + case ZSTD_error_corruption_detected: return "Corrupted block detected"; + case ZSTD_error_tableLog_tooLarge: return "tableLog requires too much memory"; + case ZSTD_error_maxSymbolValue_tooLarge: return "Unsupported max possible Symbol Value : too large"; + case ZSTD_error_maxSymbolValue_tooSmall: return "Specified maxSymbolValue is too small"; + case ZSTD_error_maxCode: + default: return codeError; + } +} + + +#if defined (__cplusplus) +} +#endif + +#endif /* ERROR_H_MODULE */ + + +#endif /* ZSTD_STATIC_H */ + + +/* + zstd_internal - common functions to include + Header File for include + Copyright (C) 2014-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://github.com/Cyan4973/zstd + - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c +*/ +#ifndef ZSTD_CCOMMON_H_MODULE +#define ZSTD_CCOMMON_H_MODULE + +#if defined (__cplusplus) +extern "C" { +#endif + +/* ************************************* +* Common macros +***************************************/ +#define MIN(a,b) ((a)<(b) ? (a) : (b)) +#define MAX(a,b) ((a)>(b) ? (a) : (b)) + + +/* ************************************* +* Common constants +***************************************/ +#define ZSTD_MAGICNUMBER 0xFD2FB524 /* v0.4 */ + +#define KB *(1 <<10) +#define MB *(1 <<20) +#define GB *(1U<<30) + +#define BLOCKSIZE (128 KB) /* define, for static allocation */ + +static const size_t ZSTD_blockHeaderSize = 3; +static const size_t ZSTD_frameHeaderSize_min = 5; +#define ZSTD_frameHeaderSize_max 5 /* define, for static allocation */ + +#define BIT7 128 +#define BIT6 64 +#define BIT5 32 +#define BIT4 16 +#define BIT1 2 +#define BIT0 1 + +#define IS_RAW BIT0 +#define IS_RLE BIT1 + +#define MINMATCH 4 +#define REPCODE_STARTVALUE 4 + +#define MLbits 7 +#define LLbits 6 +#define Offbits 5 +#define MaxML ((1< /* size_t, ptrdiff_t */ + + +/* ***************************************** +* FSE simple functions +******************************************/ +static size_t FSE_decompress(void* dst, size_t maxDstSize, + const void* cSrc, size_t cSrcSize); +/*! +FSE_decompress(): + Decompress FSE data from buffer 'cSrc', of size 'cSrcSize', + into already allocated destination buffer 'dst', of size 'maxDstSize'. + return : size of regenerated data (<= maxDstSize) + or an error code, which can be tested using FSE_isError() + + ** Important ** : FSE_decompress() doesn't decompress non-compressible nor RLE data !!! + Why ? : making this distinction requires a header. + Header management is intentionally delegated to the user layer, which can better manage special cases. +*/ + + +/* ***************************************** +* Tool functions +******************************************/ +/* Error Management */ +static unsigned FSE_isError(size_t code); /* tells if a return value is an error code */ + + + +/* ***************************************** +* FSE detailed API +******************************************/ +/*! +FSE_compress() does the following: +1. count symbol occurrence from source[] into table count[] +2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog) +3. save normalized counters to memory buffer using writeNCount() +4. build encoding table 'CTable' from normalized counters +5. encode the data stream using encoding table 'CTable' + +FSE_decompress() does the following: +1. read normalized counters with readNCount() +2. build decoding table 'DTable' from normalized counters +3. decode the data stream using decoding table 'DTable' + +The following API allows targeting specific sub-functions for advanced tasks. +For example, it's possible to compress several blocks using the same 'CTable', +or to save and provide normalized distribution using external method. +*/ + + +/* *** DECOMPRESSION *** */ + +/*! +FSE_readNCount(): + Read compactly saved 'normalizedCounter' from 'rBuffer'. + return : size read from 'rBuffer' + or an errorCode, which can be tested using FSE_isError() + maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */ +static size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, const void* rBuffer, size_t rBuffSize); + +/*! +Constructor and Destructor of type FSE_DTable + Note that its size depends on 'tableLog' */ +typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */ + +/*! +FSE_buildDTable(): + Builds 'dt', which must be already allocated, using FSE_createDTable() + return : 0, + or an errorCode, which can be tested using FSE_isError() */ +static size_t FSE_buildDTable ( FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog); + +/*! +FSE_decompress_usingDTable(): + Decompress compressed source 'cSrc' of size 'cSrcSize' using 'dt' + into 'dst' which must be already allocated. + return : size of regenerated data (necessarily <= maxDstSize) + or an errorCode, which can be tested using FSE_isError() */ +static size_t FSE_decompress_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const FSE_DTable* dt); + +/*! +Tutorial : +---------- +(Note : these functions only decompress FSE-compressed blocks. + If block is uncompressed, use memcpy() instead + If block is a single repeated byte, use memset() instead ) + +The first step is to obtain the normalized frequencies of symbols. +This can be performed by FSE_readNCount() if it was saved using FSE_writeNCount(). +'normalizedCounter' must be already allocated, and have at least 'maxSymbolValuePtr[0]+1' cells of signed short. +In practice, that means it's necessary to know 'maxSymbolValue' beforehand, +or size the table to handle worst case situations (typically 256). +FSE_readNCount() will provide 'tableLog' and 'maxSymbolValue'. +The result of FSE_readNCount() is the number of bytes read from 'rBuffer'. +Note that 'rBufferSize' must be at least 4 bytes, even if useful information is less than that. +If there is an error, the function will return an error code, which can be tested using FSE_isError(). + +The next step is to build the decompression tables 'FSE_DTable' from 'normalizedCounter'. +This is performed by the function FSE_buildDTable(). +The space required by 'FSE_DTable' must be already allocated using FSE_createDTable(). +If there is an error, the function will return an error code, which can be tested using FSE_isError(). + +'FSE_DTable' can then be used to decompress 'cSrc', with FSE_decompress_usingDTable(). +'cSrcSize' must be strictly correct, otherwise decompression will fail. +FSE_decompress_usingDTable() result will tell how many bytes were regenerated (<=maxDstSize). +If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small) +*/ + + +#if defined (__cplusplus) +} +#endif + +#endif /* FSE_H */ + + +/* ****************************************************************** + bitstream + Part of NewGen Entropy library + header file (to include) + Copyright (C) 2013-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 : + - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + - Public forum : https://groups.google.com/forum/#!forum/lz4c +****************************************************************** */ +#ifndef BITSTREAM_H_MODULE +#define BITSTREAM_H_MODULE + +#if defined (__cplusplus) +extern "C" { +#endif + + +/* +* This API consists of small unitary functions, which highly benefit from being inlined. +* Since link-time-optimization is not available for all compilers, +* these functions are defined into a .h to be included. +*/ + +/********************************************** +* bitStream decompression API (read backward) +**********************************************/ +typedef struct +{ + size_t bitContainer; + unsigned bitsConsumed; + const char* ptr; + const char* start; +} BIT_DStream_t; + +typedef enum { BIT_DStream_unfinished = 0, + BIT_DStream_endOfBuffer = 1, + BIT_DStream_completed = 2, + BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */ + /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */ + +MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize); +MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits); +MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD); +MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD); + + +/* +* Start by invoking BIT_initDStream(). +* A chunk of the bitStream is then stored into a local register. +* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t). +* You can then retrieve bitFields stored into the local register, **in reverse order**. +* Local register is manually filled from memory by the BIT_reloadDStream() method. +* A reload guarantee a minimum of ((8*sizeof(size_t))-7) bits when its result is BIT_DStream_unfinished. +* Otherwise, it can be less than that, so proceed accordingly. +* Checking if DStream has reached its end can be performed with BIT_endOfDStream() +*/ + + +/****************************************** +* unsafe API +******************************************/ +MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits); +/* faster, but works only if nbBits >= 1 */ + + + +/**************************************************************** +* Helper functions +****************************************************************/ +MEM_STATIC unsigned BIT_highbit32 (register U32 val) +{ +# if defined(_MSC_VER) /* Visual */ + unsigned long r=0; + _BitScanReverse ( &r, val ); + return (unsigned) r; +# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ + return 31 - __builtin_clz (val); +# else /* Software version */ + static const unsigned 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; + unsigned 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 +} + + +/********************************************************** +* bitStream decoding +**********************************************************/ + +/*!BIT_initDStream +* Initialize a BIT_DStream_t. +* @bitD : a pointer to an already allocated BIT_DStream_t structure +* @srcBuffer must point at the beginning of a bitStream +* @srcSize must be the exact size of the bitStream +* @result : size of stream (== srcSize) or an errorCode if a problem is detected +*/ +MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize) +{ + if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); } + + if (srcSize >= sizeof(size_t)) /* normal case */ + { + U32 contain32; + bitD->start = (const char*)srcBuffer; + bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(size_t); + bitD->bitContainer = MEM_readLEST(bitD->ptr); + contain32 = ((const BYTE*)srcBuffer)[srcSize-1]; + if (contain32 == 0) return ERROR(GENERIC); /* endMark not present */ + bitD->bitsConsumed = 8 - BIT_highbit32(contain32); + } + else + { + U32 contain32; + bitD->start = (const char*)srcBuffer; + bitD->ptr = bitD->start; + bitD->bitContainer = *(const BYTE*)(bitD->start); + switch(srcSize) + { + case 7: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[6]) << (sizeof(size_t)*8 - 16); + case 6: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[5]) << (sizeof(size_t)*8 - 24); + case 5: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[4]) << (sizeof(size_t)*8 - 32); + case 4: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[3]) << 24; + case 3: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[2]) << 16; + case 2: bitD->bitContainer += (size_t)(((const BYTE*)(bitD->start))[1]) << 8; + default:; + } + contain32 = ((const BYTE*)srcBuffer)[srcSize-1]; + if (contain32 == 0) return ERROR(GENERIC); /* endMark not present */ + bitD->bitsConsumed = 8 - BIT_highbit32(contain32); + bitD->bitsConsumed += (U32)(sizeof(size_t) - srcSize)*8; + } + + return srcSize; +} + +/*!BIT_lookBits + * Provides next n bits from local register + * local register is not modified (bits are still present for next read/look) + * On 32-bits, maxNbBits==25 + * On 64-bits, maxNbBits==57 + * @return : value extracted + */ +MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits) +{ + const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1; + return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) >> ((bitMask-nbBits) & bitMask); +} + +/*! BIT_lookBitsFast : +* unsafe version; only works only if nbBits >= 1 */ +MEM_STATIC size_t BIT_lookBitsFast(BIT_DStream_t* bitD, U32 nbBits) +{ + const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1; + return (bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> (((bitMask+1)-nbBits) & bitMask); +} + +MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) +{ + bitD->bitsConsumed += nbBits; +} + +/*!BIT_readBits + * Read next n bits from local register. + * pay attention to not read more than nbBits contained into local register. + * @return : extracted value. + */ +MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits) +{ + size_t value = BIT_lookBits(bitD, nbBits); + BIT_skipBits(bitD, nbBits); + return value; +} + +/*!BIT_readBitsFast : +* unsafe version; only works only if nbBits >= 1 */ +MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, U32 nbBits) +{ + size_t value = BIT_lookBitsFast(bitD, nbBits); + BIT_skipBits(bitD, nbBits); + return value; +} + +MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD) +{ + if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* should never happen */ + return BIT_DStream_overflow; + + if (bitD->ptr >= bitD->start + sizeof(bitD->bitContainer)) + { + bitD->ptr -= bitD->bitsConsumed >> 3; + bitD->bitsConsumed &= 7; + bitD->bitContainer = MEM_readLEST(bitD->ptr); + return BIT_DStream_unfinished; + } + if (bitD->ptr == bitD->start) + { + if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer; + return BIT_DStream_completed; + } + { + U32 nbBytes = bitD->bitsConsumed >> 3; + BIT_DStream_status result = BIT_DStream_unfinished; + if (bitD->ptr - nbBytes < bitD->start) + { + nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */ + result = BIT_DStream_endOfBuffer; + } + bitD->ptr -= nbBytes; + bitD->bitsConsumed -= nbBytes*8; + bitD->bitContainer = MEM_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD) */ + return result; + } +} + +/*! BIT_endOfDStream +* @return Tells if DStream has reached its exact end +*/ +MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream) +{ + return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8)); +} + +#if defined (__cplusplus) +} +#endif + +#endif /* BITSTREAM_H_MODULE */ + + + +/* ****************************************************************** + FSE : Finite State Entropy coder + header file for static linking (only) + Copyright (C) 2013-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 : + - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + - Public forum : https://groups.google.com/forum/#!forum/lz4c +****************************************************************** */ +#ifndef FSE_STATIC_H +#define FSE_STATIC_H + +#if defined (__cplusplus) +extern "C" { +#endif + + +/* ***************************************** +* Static allocation +*******************************************/ +/* FSE buffer bounds */ +#define FSE_NCOUNTBOUND 512 +#define FSE_BLOCKBOUND(size) (size + (size>>7)) +#define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */ + +/* It is possible to statically allocate FSE CTable/DTable as a table of unsigned using below macros */ +#define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<(maxTableLog-1)) + ((maxSymbolValue+1)*2)) +#define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1<= BIT_DStream_completed + +When it's done, verify decompression is fully completed, by checking both DStream and the relevant states. +Checking if DStream has reached its end is performed by : + BIT_endOfDStream(&DStream); +Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible. + FSE_endOfDState(&DState); +*/ + + +/* ***************************************** +* FSE unsafe API +*******************************************/ +static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD); +/* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */ + + +/* ***************************************** +* Implementation of inlined functions +*******************************************/ +/* decompression */ + +typedef struct { + U16 tableLog; + U16 fastMode; +} FSE_DTableHeader; /* sizeof U32 */ + +typedef struct +{ + unsigned short newState; + unsigned char symbol; + unsigned char nbBits; +} FSE_decode_t; /* size == U32 */ + +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); + BIT_reloadDStream(bitD); + DStatePtr->table = dt + 1; +} + +MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) +{ + const FSE_decode_t DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + const U32 nbBits = DInfo.nbBits; + BYTE symbol = DInfo.symbol; + size_t lowBits = BIT_readBits(bitD, nbBits); + + DStatePtr->state = DInfo.newState + lowBits; + return symbol; +} + +MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD) +{ + const FSE_decode_t DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state]; + const U32 nbBits = DInfo.nbBits; + BYTE symbol = DInfo.symbol; + size_t lowBits = BIT_readBitsFast(bitD, nbBits); + + DStatePtr->state = DInfo.newState + lowBits; + return symbol; +} + +MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr) +{ + return DStatePtr->state == 0; +} + + +#if defined (__cplusplus) +} +#endif + +#endif /* FSE_STATIC_H */ + +/* ****************************************************************** + FSE : Finite State Entropy coder + Copyright (C) 2013-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 : + - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy + - Public forum : https://groups.google.com/forum/#!forum/lz4c +****************************************************************** */ + +#ifndef FSE_COMMONDEFS_ONLY + +/* ************************************************************** +* Tuning parameters +****************************************************************/ +/*!MEMORY_USAGE : +* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) +* Increasing memory usage improves compression ratio +* Reduced memory usage can improve speed, due to cache effect +* Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */ +#define FSE_MAX_MEMORY_USAGE 14 +#define FSE_DEFAULT_MEMORY_USAGE 13 + +/*!FSE_MAX_SYMBOL_VALUE : +* Maximum symbol value authorized. +* Required for proper stack allocation */ +#define FSE_MAX_SYMBOL_VALUE 255 + + +/* ************************************************************** +* template functions type & suffix +****************************************************************/ +#define FSE_FUNCTION_TYPE BYTE +#define FSE_FUNCTION_EXTENSION +#define FSE_DECODE_TYPE FSE_decode_t + + +#endif /* !FSE_COMMONDEFS_ONLY */ + +/* ************************************************************** +* Compiler specifics +****************************************************************/ +#ifdef _MSC_VER /* Visual Studio */ +# define FORCE_INLINE static __forceinline +# include /* For Visual 2005 */ +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +# pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */ +#else +# ifdef __GNUC__ +# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +# define FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define FORCE_INLINE static inline +# endif +#endif + + +/* ************************************************************** +* Includes +****************************************************************/ +#include /* malloc, free, qsort */ +#include /* memcpy, memset */ +#include /* printf (debug) */ + + +/* *************************************************************** +* Constants +*****************************************************************/ +#define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE-2) +#define FSE_MAX_TABLESIZE (1U< FSE_TABLELOG_ABSOLUTE_MAX +#error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported" +#endif + + +/* ************************************************************** +* Error Management +****************************************************************/ +#define FSE_STATIC_ASSERT(c) { enum { FSE_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */ + + +/* ************************************************************** +* Complex types +****************************************************************/ +typedef U32 DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)]; + + +/* ************************************************************** +* Templates +****************************************************************/ +/* + designed to be included + for type-specific functions (template emulation in C) + Objective is to write these functions only once, for improved maintenance +*/ + +/* safety checks */ +#ifndef FSE_FUNCTION_EXTENSION +# error "FSE_FUNCTION_EXTENSION must be defined" +#endif +#ifndef FSE_FUNCTION_TYPE +# error "FSE_FUNCTION_TYPE must be defined" +#endif + +/* Function names */ +#define FSE_CAT(X,Y) X##Y +#define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y) +#define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y) + +static U32 FSE_tableStep(U32 tableSize) { return (tableSize>>1) + (tableSize>>3) + 3; } + + +static size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog) +{ + FSE_DTableHeader DTableH; + void* const tdPtr = dt+1; /* because dt is unsigned, 32-bits aligned on 32-bits */ + FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr); + const U32 tableSize = 1 << tableLog; + const U32 tableMask = tableSize-1; + const U32 step = FSE_tableStep(tableSize); + U16 symbolNext[FSE_MAX_SYMBOL_VALUE+1]; + U32 position = 0; + U32 highThreshold = tableSize-1; + const S16 largeLimit= (S16)(1 << (tableLog-1)); + U32 noLarge = 1; + U32 s; + + /* Sanity Checks */ + if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge); + if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); + + /* Init, lay down lowprob symbols */ + DTableH.tableLog = (U16)tableLog; + for (s=0; s<=maxSymbolValue; s++) + { + if (normalizedCounter[s]==-1) + { + tableDecode[highThreshold--].symbol = (FSE_FUNCTION_TYPE)s; + symbolNext[s] = 1; + } + else + { + if (normalizedCounter[s] >= largeLimit) noLarge=0; + symbolNext[s] = normalizedCounter[s]; + } + } + + /* Spread symbols */ + for (s=0; s<=maxSymbolValue; s++) + { + int i; + for (i=0; i highThreshold) position = (position + step) & tableMask; /* lowprob area */ + } + } + + if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */ + + /* Build Decoding table */ + { + U32 i; + for (i=0; i FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge); + bitStream >>= 4; + bitCount = 4; + *tableLogPtr = nbBits; + remaining = (1<1) && (charnum<=*maxSVPtr)) + { + if (previous0) + { + unsigned n0 = charnum; + while ((bitStream & 0xFFFF) == 0xFFFF) + { + n0+=24; + if (ip < iend-5) + { + ip+=2; + bitStream = MEM_readLE32(ip) >> bitCount; + } + else + { + bitStream >>= 16; + bitCount+=16; + } + } + while ((bitStream & 3) == 3) + { + n0+=3; + bitStream>>=2; + bitCount+=2; + } + n0 += bitStream & 3; + bitCount += 2; + if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall); + while (charnum < n0) normalizedCounter[charnum++] = 0; + if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) + { + ip += bitCount>>3; + bitCount &= 7; + bitStream = MEM_readLE32(ip) >> bitCount; + } + else + bitStream >>= 2; + } + { + const short max = (short)((2*threshold-1)-remaining); + short count; + + if ((bitStream & (threshold-1)) < (U32)max) + { + count = (short)(bitStream & (threshold-1)); + bitCount += nbBits-1; + } + else + { + count = (short)(bitStream & (2*threshold-1)); + if (count >= threshold) count -= max; + bitCount += nbBits; + } + + count--; /* extra accuracy */ + remaining -= FSE_abs(count); + normalizedCounter[charnum++] = count; + previous0 = !count; + while (remaining < threshold) + { + nbBits--; + threshold >>= 1; + } + + { + if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) + { + ip += bitCount>>3; + bitCount &= 7; + } + else + { + bitCount -= (int)(8 * (iend - 4 - ip)); + ip = iend - 4; + } + bitStream = MEM_readLE32(ip) >> (bitCount & 31); + } + } + } + if (remaining != 1) return ERROR(GENERIC); + *maxSVPtr = charnum-1; + + ip += (bitCount+7)>>3; + if ((size_t)(ip-istart) > hbSize) return ERROR(srcSize_wrong); + return ip-istart; +} + + +/********************************************************* +* Decompression (Byte symbols) +*********************************************************/ +static size_t FSE_buildDTable_rle (FSE_DTable* dt, BYTE symbolValue) +{ + void* ptr = dt; + FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr; + void* dPtr = dt + 1; + FSE_decode_t* const cell = (FSE_decode_t*)dPtr; + + DTableH->tableLog = 0; + DTableH->fastMode = 0; + + cell->newState = 0; + cell->symbol = symbolValue; + cell->nbBits = 0; + + return 0; +} + + +static size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits) +{ + void* ptr = dt; + FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr; + void* dPtr = dt + 1; + FSE_decode_t* const dinfo = (FSE_decode_t*)dPtr; + const unsigned tableSize = 1 << nbBits; + const unsigned tableMask = tableSize - 1; + const unsigned maxSymbolValue = tableMask; + unsigned s; + + /* Sanity checks */ + if (nbBits < 1) return ERROR(GENERIC); /* min size */ + + /* Build Decoding Table */ + DTableH->tableLog = (U16)nbBits; + DTableH->fastMode = 1; + for (s=0; s<=maxSymbolValue; s++) + { + dinfo[s].newState = 0; + dinfo[s].symbol = (BYTE)s; + dinfo[s].nbBits = (BYTE)nbBits; + } + + return 0; +} + +FORCE_INLINE size_t FSE_decompress_usingDTable_generic( + void* dst, size_t maxDstSize, + const void* cSrc, size_t cSrcSize, + const FSE_DTable* dt, const unsigned fast) +{ + BYTE* const ostart = (BYTE*) dst; + BYTE* op = ostart; + BYTE* const omax = op + maxDstSize; + BYTE* const olimit = omax-3; + + BIT_DStream_t bitD; + FSE_DState_t state1; + FSE_DState_t state2; + size_t errorCode; + + /* Init */ + errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize); /* replaced last arg by maxCompressed Size */ + if (FSE_isError(errorCode)) return errorCode; + + FSE_initDState(&state1, &bitD, dt); + FSE_initDState(&state2, &bitD, dt); + +#define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD) + + /* 4 symbols per loop */ + for ( ; (BIT_reloadDStream(&bitD)==BIT_DStream_unfinished) && (op sizeof(bitD.bitContainer)*8) /* This test must be static */ + BIT_reloadDStream(&bitD); + + op[1] = FSE_GETSYMBOL(&state2); + + if (FSE_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ + { if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) { op+=2; break; } } + + op[2] = FSE_GETSYMBOL(&state1); + + if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */ + BIT_reloadDStream(&bitD); + + op[3] = FSE_GETSYMBOL(&state2); + } + + /* tail */ + /* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */ + while (1) + { + if ( (BIT_reloadDStream(&bitD)>BIT_DStream_completed) || (op==omax) || (BIT_endOfDStream(&bitD) && (fast || FSE_endOfDState(&state1))) ) + break; + + *op++ = FSE_GETSYMBOL(&state1); + + if ( (BIT_reloadDStream(&bitD)>BIT_DStream_completed) || (op==omax) || (BIT_endOfDStream(&bitD) && (fast || FSE_endOfDState(&state2))) ) + break; + + *op++ = FSE_GETSYMBOL(&state2); + } + + /* end ? */ + if (BIT_endOfDStream(&bitD) && FSE_endOfDState(&state1) && FSE_endOfDState(&state2)) + return op-ostart; + + if (op==omax) return ERROR(dstSize_tooSmall); /* dst buffer is full, but cSrc unfinished */ + + return ERROR(corruption_detected); +} + + +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; + + /* select fast mode (static) */ + if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1); + return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0); +} + + +static size_t FSE_decompress(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize) +{ + const BYTE* const istart = (const BYTE*)cSrc; + const BYTE* ip = istart; + short counting[FSE_MAX_SYMBOL_VALUE+1]; + DTable_max_t dt; /* Static analyzer seems unable to understand this table will be properly initialized later */ + unsigned tableLog; + unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE; + size_t errorCode; + + if (cSrcSize<2) return ERROR(srcSize_wrong); /* too small input size */ + + /* normal FSE decoding mode */ + errorCode = FSE_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize); + if (FSE_isError(errorCode)) return errorCode; + if (errorCode >= cSrcSize) return ERROR(srcSize_wrong); /* too small input size */ + ip += errorCode; + cSrcSize -= errorCode; + + errorCode = FSE_buildDTable (dt, counting, maxSymbolValue, tableLog); + if (FSE_isError(errorCode)) return errorCode; + + /* always return, even if it is an error code */ + return FSE_decompress_usingDTable (dst, maxDstSize, ip, cSrcSize, dt); +} + + + +#endif /* FSE_COMMONDEFS_ONLY */ + + +/* ****************************************************************** + Huff0 : Huffman coder, part of New Generation Entropy library + header file + Copyright (C) 2013-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 : + - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + - Public forum : https://groups.google.com/forum/#!forum/lz4c +****************************************************************** */ +#ifndef HUFF0_H +#define HUFF0_H + +#if defined (__cplusplus) +extern "C" { +#endif + + +/* **************************************** +* Dependency +******************************************/ +#include /* size_t */ + + +/* **************************************** +* Huff0 simple functions +******************************************/ +static size_t HUF_decompress(void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize); +/*! +HUF_decompress(): + Decompress Huff0 data from buffer 'cSrc', of size 'cSrcSize', + into already allocated destination buffer 'dst', of size 'dstSize'. + 'dstSize' must be the exact size of original (uncompressed) data. + Note : in contrast with FSE, HUF_decompress can regenerate RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data, because it knows size to regenerate. + @return : size of regenerated data (== dstSize) + or an error code, which can be tested using HUF_isError() +*/ + + +/* **************************************** +* Tool functions +******************************************/ +/* Error Management */ +static unsigned HUF_isError(size_t code); /* tells if a return value is an error code */ + + +#if defined (__cplusplus) +} +#endif + +#endif /* HUFF0_H */ + + +/* ****************************************************************** + Huff0 : Huffman coder, part of New Generation Entropy library + header file for static linking (only) + Copyright (C) 2013-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 : + - Source repository : https://github.com/Cyan4973/FiniteStateEntropy + - Public forum : https://groups.google.com/forum/#!forum/lz4c +****************************************************************** */ +#ifndef HUFF0_STATIC_H +#define HUFF0_STATIC_H + +#if defined (__cplusplus) +extern "C" { +#endif + + +/* **************************************** +* Dependency +******************************************/ +#include "huff0.h" + + +/* **************************************** +* Static allocation macros +******************************************/ +/* static allocation of Huff0's DTable */ +#define HUF_DTABLE_SIZE(maxTableLog) (1 + (1<= 199901L) /* C99 */) +/* inline is defined */ +#elif defined(_MSC_VER) +# define inline __inline +#else +# define inline /* disable inline */ +#endif + + +#ifdef _MSC_VER /* Visual Studio */ +# define FORCE_INLINE static __forceinline +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +#else +# ifdef __GNUC__ +# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +# define FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define FORCE_INLINE static inline +# endif +#endif + + +/* ************************************************************** +* Includes +****************************************************************/ +#include /* malloc, free, qsort */ +#include /* memcpy, memset */ +#include /* printf (debug) */ + + +/* ************************************************************** +* Constants +****************************************************************/ +#define HUF_ABSOLUTEMAX_TABLELOG 16 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */ +#define HUF_MAX_TABLELOG 12 /* max configured tableLog (for static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */ +#define HUF_DEFAULT_TABLELOG HUF_MAX_TABLELOG /* tableLog by default, when not specified */ +#define HUF_MAX_SYMBOL_VALUE 255 +#if (HUF_MAX_TABLELOG > HUF_ABSOLUTEMAX_TABLELOG) +# error "HUF_MAX_TABLELOG is too large !" +#endif + + +/* ************************************************************** +* Error Management +****************************************************************/ +static unsigned HUF_isError(size_t code) { return ERR_isError(code); } +#define HUF_STATIC_ASSERT(c) { enum { HUF_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */ + + + +/*-******************************************************* +* Huff0 : Huffman block decompression +*********************************************************/ +typedef struct { BYTE byte; BYTE nbBits; } HUF_DEltX2; /* single-symbol decoding */ + +typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX4; /* double-symbols decoding */ + +typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t; + +/*! HUF_readStats + Read compact Huffman tree, saved by HUF_writeCTable + @huffWeight : destination buffer + @return : size read from `src` +*/ +static size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, + U32* nbSymbolsPtr, U32* tableLogPtr, + const void* src, size_t srcSize) +{ + U32 weightTotal; + U32 tableLog; + const BYTE* ip = (const BYTE*) src; + size_t iSize = ip[0]; + size_t oSize; + U32 n; + + //memset(huffWeight, 0, hwSize); /* is not necessary, even though some analyzer complain ... */ + + if (iSize >= 128) /* special header */ + { + if (iSize >= (242)) /* RLE */ + { + static int l[14] = { 1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 127, 128 }; + oSize = l[iSize-242]; + memset(huffWeight, 1, hwSize); + iSize = 0; + } + else /* Incompressible */ + { + oSize = iSize - 127; + iSize = ((oSize+1)/2); + if (iSize+1 > srcSize) return ERROR(srcSize_wrong); + if (oSize >= hwSize) return ERROR(corruption_detected); + ip += 1; + for (n=0; n> 4; + huffWeight[n+1] = ip[n/2] & 15; + } + } + } + else /* header compressed with FSE (normal case) */ + { + if (iSize+1 > srcSize) return ERROR(srcSize_wrong); + oSize = FSE_decompress(huffWeight, hwSize-1, ip+1, iSize); /* max (hwSize-1) values decoded, as last one is implied */ + if (FSE_isError(oSize)) return oSize; + } + + /* collect weight stats */ + memset(rankStats, 0, (HUF_ABSOLUTEMAX_TABLELOG + 1) * sizeof(U32)); + weightTotal = 0; + for (n=0; n= HUF_ABSOLUTEMAX_TABLELOG) return ERROR(corruption_detected); + rankStats[huffWeight[n]]++; + weightTotal += (1 << huffWeight[n]) >> 1; + } + + /* get last non-null symbol weight (implied, total must be 2^n) */ + tableLog = BIT_highbit32(weightTotal) + 1; + if (tableLog > HUF_ABSOLUTEMAX_TABLELOG) return ERROR(corruption_detected); + { + U32 total = 1 << tableLog; + U32 rest = total - weightTotal; + U32 verif = 1 << BIT_highbit32(rest); + U32 lastWeight = BIT_highbit32(rest) + 1; + if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */ + huffWeight[oSize] = (BYTE)lastWeight; + rankStats[lastWeight]++; + } + + /* check tree construction validity */ + if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */ + + /* results */ + *nbSymbolsPtr = (U32)(oSize+1); + *tableLogPtr = tableLog; + return iSize+1; +} + + +/**************************/ +/* single-symbol decoding */ +/**************************/ + +static size_t HUF_readDTableX2 (U16* DTable, const void* src, size_t srcSize) +{ + BYTE huffWeight[HUF_MAX_SYMBOL_VALUE + 1]; + U32 rankVal[HUF_ABSOLUTEMAX_TABLELOG + 1]; /* large enough for values from 0 to 16 */ + U32 tableLog = 0; + size_t iSize; + U32 nbSymbols = 0; + U32 n; + U32 nextRankStart; + void* const dtPtr = DTable + 1; + HUF_DEltX2* const dt = (HUF_DEltX2*)dtPtr; + + HUF_STATIC_ASSERT(sizeof(HUF_DEltX2) == sizeof(U16)); /* if compilation fails here, assertion is false */ + //memset(huffWeight, 0, sizeof(huffWeight)); /* is not necessary, even though some analyzer complain ... */ + + iSize = HUF_readStats(huffWeight, HUF_MAX_SYMBOL_VALUE + 1, rankVal, &nbSymbols, &tableLog, src, srcSize); + if (HUF_isError(iSize)) return iSize; + + /* check result */ + if (tableLog > DTable[0]) return ERROR(tableLog_tooLarge); /* DTable is too small */ + DTable[0] = (U16)tableLog; /* maybe should separate sizeof DTable, as allocated, from used size of DTable, in case of DTable re-use */ + + /* Prepare ranks */ + nextRankStart = 0; + for (n=1; n<=tableLog; n++) + { + U32 current = nextRankStart; + nextRankStart += (rankVal[n] << (n-1)); + rankVal[n] = current; + } + + /* fill DTable */ + for (n=0; n> 1; + U32 i; + HUF_DEltX2 D; + D.byte = (BYTE)n; D.nbBits = (BYTE)(tableLog + 1 - w); + for (i = rankVal[w]; i < rankVal[w] + length; i++) + dt[i] = D; + rankVal[w] += length; + } + + return iSize; +} + +static BYTE HUF_decodeSymbolX2(BIT_DStream_t* Dstream, const HUF_DEltX2* dt, const U32 dtLog) +{ + const size_t val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */ + const BYTE c = dt[val].byte; + BIT_skipBits(Dstream, dt[val].nbBits); + return c; +} + +#define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \ + *ptr++ = HUF_decodeSymbolX2(DStreamPtr, dt, dtLog) + +#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \ + if (MEM_64bits() || (HUF_MAX_TABLELOG<=12)) \ + HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) + +#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \ + if (MEM_64bits()) \ + HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) + +static inline size_t HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX2* const dt, const U32 dtLog) +{ + BYTE* const pStart = p; + + /* up to 4 symbols at a time */ + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p <= pEnd-4)) + { + HUF_DECODE_SYMBOLX2_2(p, bitDPtr); + HUF_DECODE_SYMBOLX2_1(p, bitDPtr); + HUF_DECODE_SYMBOLX2_2(p, bitDPtr); + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + } + + /* closer to the end */ + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p < pEnd)) + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + + /* no more data to retrieve from bitstream, hence no need to reload */ + while (p < pEnd) + HUF_DECODE_SYMBOLX2_0(p, bitDPtr); + + return pEnd-pStart; +} + + +static size_t HUF_decompress4X2_usingDTable( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const U16* DTable) +{ + if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ + + { + const BYTE* const istart = (const BYTE*) cSrc; + BYTE* const ostart = (BYTE*) dst; + BYTE* const oend = ostart + dstSize; + const void* const dtPtr = DTable; + const HUF_DEltX2* const dt = ((const HUF_DEltX2*)dtPtr) +1; + const U32 dtLog = DTable[0]; + size_t errorCode; + + /* Init */ + BIT_DStream_t bitD1; + BIT_DStream_t bitD2; + BIT_DStream_t bitD3; + BIT_DStream_t bitD4; + const size_t length1 = MEM_readLE16(istart); + const size_t length2 = MEM_readLE16(istart+2); + const size_t length3 = MEM_readLE16(istart+4); + size_t length4; + const BYTE* const istart1 = istart + 6; /* jumpTable */ + const BYTE* const istart2 = istart1 + length1; + const BYTE* const istart3 = istart2 + length2; + const BYTE* const istart4 = istart3 + length3; + const size_t segmentSize = (dstSize+3) / 4; + BYTE* const opStart2 = ostart + segmentSize; + BYTE* const opStart3 = opStart2 + segmentSize; + BYTE* const opStart4 = opStart3 + segmentSize; + BYTE* op1 = ostart; + BYTE* op2 = opStart2; + BYTE* op3 = opStart3; + BYTE* op4 = opStart4; + U32 endSignal; + + length4 = cSrcSize - (length1 + length2 + length3 + 6); + if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ + errorCode = BIT_initDStream(&bitD1, istart1, length1); + if (HUF_isError(errorCode)) return errorCode; + errorCode = BIT_initDStream(&bitD2, istart2, length2); + if (HUF_isError(errorCode)) return errorCode; + errorCode = BIT_initDStream(&bitD3, istart3, length3); + if (HUF_isError(errorCode)) return errorCode; + errorCode = BIT_initDStream(&bitD4, istart4, length4); + if (HUF_isError(errorCode)) return errorCode; + + /* 16-32 symbols per loop (4-8 symbols per stream) */ + endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); + for ( ; (endSignal==BIT_DStream_unfinished) && (op4<(oend-7)) ; ) + { + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_1(op1, &bitD1); + HUF_DECODE_SYMBOLX2_1(op2, &bitD2); + HUF_DECODE_SYMBOLX2_1(op3, &bitD3); + HUF_DECODE_SYMBOLX2_1(op4, &bitD4); + HUF_DECODE_SYMBOLX2_2(op1, &bitD1); + HUF_DECODE_SYMBOLX2_2(op2, &bitD2); + HUF_DECODE_SYMBOLX2_2(op3, &bitD3); + HUF_DECODE_SYMBOLX2_2(op4, &bitD4); + HUF_DECODE_SYMBOLX2_0(op1, &bitD1); + HUF_DECODE_SYMBOLX2_0(op2, &bitD2); + HUF_DECODE_SYMBOLX2_0(op3, &bitD3); + HUF_DECODE_SYMBOLX2_0(op4, &bitD4); + + endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); + } + + /* check corruption */ + if (op1 > opStart2) return ERROR(corruption_detected); + if (op2 > opStart3) return ERROR(corruption_detected); + if (op3 > opStart4) return ERROR(corruption_detected); + /* note : op4 supposed already verified within main loop */ + + /* finish bitStreams one by one */ + HUF_decodeStreamX2(op1, &bitD1, opStart2, dt, dtLog); + HUF_decodeStreamX2(op2, &bitD2, opStart3, dt, dtLog); + HUF_decodeStreamX2(op3, &bitD3, opStart4, dt, dtLog); + HUF_decodeStreamX2(op4, &bitD4, oend, dt, dtLog); + + /* check */ + endSignal = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4); + if (!endSignal) return ERROR(corruption_detected); + + /* decoded size */ + return dstSize; + } +} + + +static size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_MAX_TABLELOG); + const BYTE* ip = (const BYTE*) cSrc; + size_t errorCode; + + errorCode = HUF_readDTableX2 (DTable, cSrc, cSrcSize); + if (HUF_isError(errorCode)) return errorCode; + if (errorCode >= cSrcSize) return ERROR(srcSize_wrong); + ip += errorCode; + cSrcSize -= errorCode; + + return HUF_decompress4X2_usingDTable (dst, dstSize, ip, cSrcSize, DTable); +} + + +/***************************/ +/* double-symbols decoding */ +/***************************/ + +static void HUF_fillDTableX4Level2(HUF_DEltX4* DTable, U32 sizeLog, const U32 consumed, + const U32* rankValOrigin, const int minWeight, + const sortedSymbol_t* sortedSymbols, const U32 sortedListSize, + U32 nbBitsBaseline, U16 baseSeq) +{ + HUF_DEltX4 DElt; + U32 rankVal[HUF_ABSOLUTEMAX_TABLELOG + 1]; + U32 s; + + /* get pre-calculated rankVal */ + memcpy(rankVal, rankValOrigin, sizeof(rankVal)); + + /* fill skipped values */ + if (minWeight>1) + { + U32 i, skipSize = rankVal[minWeight]; + MEM_writeLE16(&(DElt.sequence), baseSeq); + DElt.nbBits = (BYTE)(consumed); + DElt.length = 1; + for (i = 0; i < skipSize; i++) + DTable[i] = DElt; + } + + /* fill DTable */ + for (s=0; s= 1 */ + + rankVal[weight] += length; + } +} + +typedef U32 rankVal_t[HUF_ABSOLUTEMAX_TABLELOG][HUF_ABSOLUTEMAX_TABLELOG + 1]; + +static void HUF_fillDTableX4(HUF_DEltX4* DTable, const U32 targetLog, + const sortedSymbol_t* sortedList, const U32 sortedListSize, + const U32* rankStart, rankVal_t rankValOrigin, const U32 maxWeight, + const U32 nbBitsBaseline) +{ + U32 rankVal[HUF_ABSOLUTEMAX_TABLELOG + 1]; + const int scaleLog = nbBitsBaseline - targetLog; /* note : targetLog >= srcLog, hence scaleLog <= 1 */ + const U32 minBits = nbBitsBaseline - maxWeight; + U32 s; + + memcpy(rankVal, rankValOrigin, sizeof(rankVal)); + + /* fill DTable */ + for (s=0; s= minBits) /* enough room for a second symbol */ + { + U32 sortedRank; + int minWeight = nbBits + scaleLog; + if (minWeight < 1) minWeight = 1; + sortedRank = rankStart[minWeight]; + HUF_fillDTableX4Level2(DTable+start, targetLog-nbBits, nbBits, + rankValOrigin[nbBits], minWeight, + sortedList+sortedRank, sortedListSize-sortedRank, + nbBitsBaseline, symbol); + } + else + { + U32 i; + const U32 end = start + length; + HUF_DEltX4 DElt; + + MEM_writeLE16(&(DElt.sequence), symbol); + DElt.nbBits = (BYTE)(nbBits); + DElt.length = 1; + for (i = start; i < end; i++) + DTable[i] = DElt; + } + rankVal[weight] += length; + } +} + +static size_t HUF_readDTableX4 (U32* DTable, const void* src, size_t srcSize) +{ + BYTE weightList[HUF_MAX_SYMBOL_VALUE + 1]; + sortedSymbol_t sortedSymbol[HUF_MAX_SYMBOL_VALUE + 1]; + U32 rankStats[HUF_ABSOLUTEMAX_TABLELOG + 1] = { 0 }; + U32 rankStart0[HUF_ABSOLUTEMAX_TABLELOG + 2] = { 0 }; + U32* const rankStart = rankStart0+1; + rankVal_t rankVal; + U32 tableLog, maxW, sizeOfSort, nbSymbols; + const U32 memLog = DTable[0]; + size_t iSize; + void* dtPtr = DTable; + HUF_DEltX4* const dt = ((HUF_DEltX4*)dtPtr) + 1; + + HUF_STATIC_ASSERT(sizeof(HUF_DEltX4) == sizeof(U32)); /* if compilation fails here, assertion is false */ + if (memLog > HUF_ABSOLUTEMAX_TABLELOG) return ERROR(tableLog_tooLarge); + //memset(weightList, 0, sizeof(weightList)); /* is not necessary, even though some analyzer complain ... */ + + iSize = HUF_readStats(weightList, HUF_MAX_SYMBOL_VALUE + 1, rankStats, &nbSymbols, &tableLog, src, srcSize); + if (HUF_isError(iSize)) return iSize; + + /* check result */ + 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 */ + + /* Get start index of each weight */ + { + U32 w, nextRankStart = 0; + for (w=1; w<=maxW; w++) + { + U32 current = nextRankStart; + nextRankStart += rankStats[w]; + rankStart[w] = current; + } + rankStart[0] = nextRankStart; /* put all 0w symbols at the end of sorted list*/ + sizeOfSort = nextRankStart; + } + + /* sort symbols by weight */ + { + U32 s; + for (s=0; s> consumed; + } + } + } + + HUF_fillDTableX4(dt, memLog, + sortedSymbol, sizeOfSort, + rankStart0, rankVal, maxW, + tableLog+1); + + return iSize; +} + + +static U32 HUF_decodeSymbolX4(void* op, BIT_DStream_t* DStream, const HUF_DEltX4* dt, const U32 dtLog) +{ + const size_t val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ + memcpy(op, dt+val, 2); + BIT_skipBits(DStream, dt[val].nbBits); + return dt[val].length; +} + +static U32 HUF_decodeLastSymbolX4(void* op, BIT_DStream_t* DStream, const HUF_DEltX4* dt, const U32 dtLog) +{ + const size_t val = BIT_lookBitsFast(DStream, dtLog); /* note : dtLog >= 1 */ + memcpy(op, dt+val, 1); + if (dt[val].length==1) BIT_skipBits(DStream, dt[val].nbBits); + else + { + if (DStream->bitsConsumed < (sizeof(DStream->bitContainer)*8)) + { + BIT_skipBits(DStream, dt[val].nbBits); + if (DStream->bitsConsumed > (sizeof(DStream->bitContainer)*8)) + DStream->bitsConsumed = (sizeof(DStream->bitContainer)*8); /* ugly hack; works only because it's the last symbol. Note : can't easily extract nbBits from just this symbol */ + } + } + return 1; +} + + +#define HUF_DECODE_SYMBOLX4_0(ptr, DStreamPtr) \ + ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog) + +#define HUF_DECODE_SYMBOLX4_1(ptr, DStreamPtr) \ + if (MEM_64bits() || (HUF_MAX_TABLELOG<=12)) \ + ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog) + +#define HUF_DECODE_SYMBOLX4_2(ptr, DStreamPtr) \ + if (MEM_64bits()) \ + ptr += HUF_decodeSymbolX4(ptr, DStreamPtr, dt, dtLog) + +static inline size_t HUF_decodeStreamX4(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd, const HUF_DEltX4* const dt, const U32 dtLog) +{ + BYTE* const pStart = p; + + /* up to 8 symbols at a time */ + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p < pEnd-7)) + { + HUF_DECODE_SYMBOLX4_2(p, bitDPtr); + HUF_DECODE_SYMBOLX4_1(p, bitDPtr); + HUF_DECODE_SYMBOLX4_2(p, bitDPtr); + HUF_DECODE_SYMBOLX4_0(p, bitDPtr); + } + + /* closer to the end */ + while ((BIT_reloadDStream(bitDPtr) == BIT_DStream_unfinished) && (p <= pEnd-2)) + HUF_DECODE_SYMBOLX4_0(p, bitDPtr); + + while (p <= pEnd-2) + HUF_DECODE_SYMBOLX4_0(p, bitDPtr); /* no need to reload : reached the end of DStream */ + + if (p < pEnd) + p += HUF_decodeLastSymbolX4(p, bitDPtr, dt, dtLog); + + return p-pStart; +} + +static size_t HUF_decompress4X4_usingDTable( + void* dst, size_t dstSize, + const void* cSrc, size_t cSrcSize, + const U32* DTable) +{ + if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ + + { + const BYTE* const istart = (const BYTE*) cSrc; + BYTE* const ostart = (BYTE*) dst; + BYTE* const oend = ostart + dstSize; + const void* const dtPtr = DTable; + const HUF_DEltX4* const dt = ((const HUF_DEltX4*)dtPtr) +1; + const U32 dtLog = DTable[0]; + size_t errorCode; + + /* Init */ + BIT_DStream_t bitD1; + BIT_DStream_t bitD2; + BIT_DStream_t bitD3; + BIT_DStream_t bitD4; + const size_t length1 = MEM_readLE16(istart); + const size_t length2 = MEM_readLE16(istart+2); + const size_t length3 = MEM_readLE16(istart+4); + size_t length4; + const BYTE* const istart1 = istart + 6; /* jumpTable */ + const BYTE* const istart2 = istart1 + length1; + const BYTE* const istart3 = istart2 + length2; + const BYTE* const istart4 = istart3 + length3; + const size_t segmentSize = (dstSize+3) / 4; + BYTE* const opStart2 = ostart + segmentSize; + BYTE* const opStart3 = opStart2 + segmentSize; + BYTE* const opStart4 = opStart3 + segmentSize; + BYTE* op1 = ostart; + BYTE* op2 = opStart2; + BYTE* op3 = opStart3; + BYTE* op4 = opStart4; + U32 endSignal; + + length4 = cSrcSize - (length1 + length2 + length3 + 6); + if (length4 > cSrcSize) return ERROR(corruption_detected); /* overflow */ + errorCode = BIT_initDStream(&bitD1, istart1, length1); + if (HUF_isError(errorCode)) return errorCode; + errorCode = BIT_initDStream(&bitD2, istart2, length2); + if (HUF_isError(errorCode)) return errorCode; + errorCode = BIT_initDStream(&bitD3, istart3, length3); + if (HUF_isError(errorCode)) return errorCode; + errorCode = BIT_initDStream(&bitD4, istart4, length4); + if (HUF_isError(errorCode)) return errorCode; + + /* 16-32 symbols per loop (4-8 symbols per stream) */ + endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); + for ( ; (endSignal==BIT_DStream_unfinished) && (op4<(oend-7)) ; ) + { + HUF_DECODE_SYMBOLX4_2(op1, &bitD1); + HUF_DECODE_SYMBOLX4_2(op2, &bitD2); + HUF_DECODE_SYMBOLX4_2(op3, &bitD3); + HUF_DECODE_SYMBOLX4_2(op4, &bitD4); + HUF_DECODE_SYMBOLX4_1(op1, &bitD1); + HUF_DECODE_SYMBOLX4_1(op2, &bitD2); + HUF_DECODE_SYMBOLX4_1(op3, &bitD3); + HUF_DECODE_SYMBOLX4_1(op4, &bitD4); + HUF_DECODE_SYMBOLX4_2(op1, &bitD1); + HUF_DECODE_SYMBOLX4_2(op2, &bitD2); + HUF_DECODE_SYMBOLX4_2(op3, &bitD3); + HUF_DECODE_SYMBOLX4_2(op4, &bitD4); + HUF_DECODE_SYMBOLX4_0(op1, &bitD1); + HUF_DECODE_SYMBOLX4_0(op2, &bitD2); + HUF_DECODE_SYMBOLX4_0(op3, &bitD3); + HUF_DECODE_SYMBOLX4_0(op4, &bitD4); + + endSignal = BIT_reloadDStream(&bitD1) | BIT_reloadDStream(&bitD2) | BIT_reloadDStream(&bitD3) | BIT_reloadDStream(&bitD4); + } + + /* check corruption */ + if (op1 > opStart2) return ERROR(corruption_detected); + if (op2 > opStart3) return ERROR(corruption_detected); + if (op3 > opStart4) return ERROR(corruption_detected); + /* note : op4 supposed already verified within main loop */ + + /* finish bitStreams one by one */ + HUF_decodeStreamX4(op1, &bitD1, opStart2, dt, dtLog); + HUF_decodeStreamX4(op2, &bitD2, opStart3, dt, dtLog); + HUF_decodeStreamX4(op3, &bitD3, opStart4, dt, dtLog); + HUF_decodeStreamX4(op4, &bitD4, oend, dt, dtLog); + + /* check */ + endSignal = BIT_endOfDStream(&bitD1) & BIT_endOfDStream(&bitD2) & BIT_endOfDStream(&bitD3) & BIT_endOfDStream(&bitD4); + if (!endSignal) return ERROR(corruption_detected); + + /* decoded size */ + return dstSize; + } +} + + +static size_t HUF_decompress4X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize) +{ + HUF_CREATE_STATIC_DTABLEX4(DTable, HUF_MAX_TABLELOG); + const BYTE* ip = (const BYTE*) cSrc; + + size_t hSize = HUF_readDTableX4 (DTable, cSrc, cSrcSize); + if (HUF_isError(hSize)) return hSize; + if (hSize >= cSrcSize) return ERROR(srcSize_wrong); + ip += hSize; + cSrcSize -= hSize; + + return HUF_decompress4X4_usingDTable (dst, dstSize, ip, cSrcSize, DTable); +} + + +/**********************************/ +/* quad-symbol decoding */ +/**********************************/ +typedef struct { BYTE nbBits; BYTE nbBytes; } HUF_DDescX6; +typedef union { BYTE byte[4]; U32 sequence; } HUF_DSeqX6; + +/* recursive, up to level 3; may benefit from