Update zstd to 1.4.3
This commit is contained in:
parent
d482a1d8e8
commit
61ad365fc9
|
@ -120,6 +120,8 @@ if env['builtin_zstd']:
|
||||||
"compress/zstd_ldm.c",
|
"compress/zstd_ldm.c",
|
||||||
"compress/zstd_opt.c",
|
"compress/zstd_opt.c",
|
||||||
"compress/zstdmt_compress.c",
|
"compress/zstdmt_compress.c",
|
||||||
|
"compress/zstd_compress_literals.c",
|
||||||
|
"compress/zstd_compress_sequences.c",
|
||||||
"decompress/huf_decompress.c",
|
"decompress/huf_decompress.c",
|
||||||
"decompress/zstd_ddict.c",
|
"decompress/zstd_ddict.c",
|
||||||
"decompress/zstd_decompress_block.c",
|
"decompress/zstd_decompress_block.c",
|
||||||
|
|
|
@ -534,7 +534,7 @@ Files extracted from upstream source:
|
||||||
## zstd
|
## zstd
|
||||||
|
|
||||||
- Upstream: https://github.com/facebook/zstd
|
- Upstream: https://github.com/facebook/zstd
|
||||||
- Version: 1.4.1
|
- Version: 1.4.3
|
||||||
- License: BSD-3-Clause
|
- License: BSD-3-Clause
|
||||||
|
|
||||||
Files extracted from upstream source:
|
Files extracted from upstream source:
|
||||||
|
|
|
@ -57,6 +57,8 @@ extern "C" {
|
||||||
=========================================*/
|
=========================================*/
|
||||||
#if defined(__BMI__) && defined(__GNUC__)
|
#if defined(__BMI__) && defined(__GNUC__)
|
||||||
# include <immintrin.h> /* support for bextr (experimental) */
|
# include <immintrin.h> /* support for bextr (experimental) */
|
||||||
|
#elif defined(__ICCARM__)
|
||||||
|
# include <intrinsics.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define STREAM_ACCUMULATOR_MIN_32 25
|
#define STREAM_ACCUMULATOR_MIN_32 25
|
||||||
|
@ -163,6 +165,8 @@ MEM_STATIC unsigned BIT_highbit32 (U32 val)
|
||||||
return (unsigned) r;
|
return (unsigned) r;
|
||||||
# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */
|
# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */
|
||||||
return 31 - __builtin_clz (val);
|
return 31 - __builtin_clz (val);
|
||||||
|
# elif defined(__ICCARM__) /* IAR Intrinsic */
|
||||||
|
return 31 - __CLZ(val);
|
||||||
# else /* Software version */
|
# else /* Software version */
|
||||||
static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29,
|
static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29,
|
||||||
11, 14, 16, 18, 22, 25, 3, 30,
|
11, 14, 16, 18, 22, 25, 3, 30,
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
# define INLINE_KEYWORD
|
# define INLINE_KEYWORD
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__) || defined(__ICCARM__)
|
||||||
# define FORCE_INLINE_ATTR __attribute__((always_inline))
|
# define FORCE_INLINE_ATTR __attribute__((always_inline))
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
# define FORCE_INLINE_ATTR __forceinline
|
# define FORCE_INLINE_ATTR __forceinline
|
||||||
|
@ -65,7 +65,7 @@
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# define FORCE_NOINLINE static __declspec(noinline)
|
# define FORCE_NOINLINE static __declspec(noinline)
|
||||||
#else
|
#else
|
||||||
# ifdef __GNUC__
|
# if defined(__GNUC__) || defined(__ICCARM__)
|
||||||
# define FORCE_NOINLINE static __attribute__((__noinline__))
|
# define FORCE_NOINLINE static __attribute__((__noinline__))
|
||||||
# else
|
# else
|
||||||
# define FORCE_NOINLINE static
|
# define FORCE_NOINLINE static
|
||||||
|
@ -76,7 +76,7 @@
|
||||||
#ifndef __has_attribute
|
#ifndef __has_attribute
|
||||||
#define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
|
#define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
|
||||||
#endif
|
#endif
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__) || defined(__ICCARM__)
|
||||||
# define TARGET_ATTRIBUTE(target) __attribute__((__target__(target)))
|
# define TARGET_ATTRIBUTE(target) __attribute__((__target__(target)))
|
||||||
#else
|
#else
|
||||||
# define TARGET_ATTRIBUTE(target)
|
# define TARGET_ATTRIBUTE(target)
|
||||||
|
|
|
@ -102,7 +102,7 @@ MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (size
|
||||||
#ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
|
#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__) )
|
# 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
|
# define MEM_FORCE_MEMORY_ACCESS 2
|
||||||
# elif defined(__INTEL_COMPILER) || defined(__GNUC__)
|
# elif defined(__INTEL_COMPILER) || defined(__GNUC__) || defined(__ICCARM__)
|
||||||
# define MEM_FORCE_MEMORY_ACCESS 1
|
# define MEM_FORCE_MEMORY_ACCESS 1
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -53,7 +53,8 @@
|
||||||
# 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__) )
|
# 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 XXH_FORCE_MEMORY_ACCESS 2
|
# define XXH_FORCE_MEMORY_ACCESS 2
|
||||||
# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \
|
# elif (defined(__INTEL_COMPILER) && !defined(WIN32)) || \
|
||||||
(defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) ))
|
(defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) )) || \
|
||||||
|
defined(__ICCARM__)
|
||||||
# define XXH_FORCE_MEMORY_ACCESS 1
|
# define XXH_FORCE_MEMORY_ACCESS 1
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -120,7 +121,7 @@ static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcp
|
||||||
# define INLINE_KEYWORD
|
# define INLINE_KEYWORD
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__) || defined(__ICCARM__)
|
||||||
# define FORCE_INLINE_ATTR __attribute__((always_inline))
|
# define FORCE_INLINE_ATTR __attribute__((always_inline))
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
# define FORCE_INLINE_ATTR __forceinline
|
# define FORCE_INLINE_ATTR __forceinline
|
||||||
|
@ -206,7 +207,12 @@ static U64 XXH_read64(const void* memPtr)
|
||||||
# define XXH_rotl32(x,r) _rotl(x,r)
|
# define XXH_rotl32(x,r) _rotl(x,r)
|
||||||
# define XXH_rotl64(x,r) _rotl64(x,r)
|
# define XXH_rotl64(x,r) _rotl64(x,r)
|
||||||
#else
|
#else
|
||||||
|
#if defined(__ICCARM__)
|
||||||
|
# include <intrinsics.h>
|
||||||
|
# define XXH_rotl32(x,r) __ROR(x,(32 - r))
|
||||||
|
#else
|
||||||
# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
|
# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
|
||||||
|
#endif
|
||||||
# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
|
# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -56,9 +56,9 @@ extern "C" {
|
||||||
/**
|
/**
|
||||||
* Return the specified error if the condition evaluates to true.
|
* Return the specified error if the condition evaluates to true.
|
||||||
*
|
*
|
||||||
* In debug modes, prints additional information. In order to do that
|
* In debug modes, prints additional information.
|
||||||
* (particularly, printing the conditional that failed), this can't just wrap
|
* In order to do that (particularly, printing the conditional that failed),
|
||||||
* RETURN_ERROR().
|
* this can't just wrap RETURN_ERROR().
|
||||||
*/
|
*/
|
||||||
#define RETURN_ERROR_IF(cond, err, ...) \
|
#define RETURN_ERROR_IF(cond, err, ...) \
|
||||||
if (cond) { \
|
if (cond) { \
|
||||||
|
@ -324,6 +324,8 @@ MEM_STATIC U32 ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus
|
||||||
return (unsigned)r;
|
return (unsigned)r;
|
||||||
# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */
|
# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */
|
||||||
return 31 - __builtin_clz(val);
|
return 31 - __builtin_clz(val);
|
||||||
|
# elif defined(__ICCARM__) /* IAR Intrinsic */
|
||||||
|
return 31 - __CLZ(val);
|
||||||
# else /* Software version */
|
# else /* Software version */
|
||||||
static const U32 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 };
|
static const U32 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;
|
U32 v = val;
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#define HUF_STATIC_LINKING_ONLY
|
#define HUF_STATIC_LINKING_ONLY
|
||||||
#include "huf.h"
|
#include "huf.h"
|
||||||
#include "zstd_compress_internal.h"
|
#include "zstd_compress_internal.h"
|
||||||
|
#include "zstd_compress_sequences.h"
|
||||||
|
#include "zstd_compress_literals.h"
|
||||||
#include "zstd_fast.h"
|
#include "zstd_fast.h"
|
||||||
#include "zstd_double_fast.h"
|
#include "zstd_double_fast.h"
|
||||||
#include "zstd_lazy.h"
|
#include "zstd_lazy.h"
|
||||||
|
@ -397,18 +399,6 @@ ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ZSTD_cParam_withinBounds:
|
|
||||||
* @return 1 if value is within cParam bounds,
|
|
||||||
* 0 otherwise */
|
|
||||||
static int ZSTD_cParam_withinBounds(ZSTD_cParameter cParam, int value)
|
|
||||||
{
|
|
||||||
ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam);
|
|
||||||
if (ZSTD_isError(bounds.error)) return 0;
|
|
||||||
if (value < bounds.lowerBound) return 0;
|
|
||||||
if (value > bounds.upperBound) return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ZSTD_cParam_clampBounds:
|
/* ZSTD_cParam_clampBounds:
|
||||||
* Clamps the value into the bounded range.
|
* Clamps the value into the bounded range.
|
||||||
*/
|
*/
|
||||||
|
@ -1903,155 +1893,6 @@ static size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* s
|
||||||
return ZSTD_blockHeaderSize + srcSize;
|
return ZSTD_blockHeaderSize + srcSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
|
|
||||||
{
|
|
||||||
BYTE* const ostart = (BYTE* const)dst;
|
|
||||||
U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
|
|
||||||
|
|
||||||
RETURN_ERROR_IF(srcSize + flSize > dstCapacity, dstSize_tooSmall);
|
|
||||||
|
|
||||||
switch(flSize)
|
|
||||||
{
|
|
||||||
case 1: /* 2 - 1 - 5 */
|
|
||||||
ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
|
|
||||||
break;
|
|
||||||
case 2: /* 2 - 2 - 12 */
|
|
||||||
MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
|
|
||||||
break;
|
|
||||||
case 3: /* 2 - 2 - 20 */
|
|
||||||
MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
|
|
||||||
break;
|
|
||||||
default: /* not necessary : flSize is {1,2,3} */
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(ostart + flSize, src, srcSize);
|
|
||||||
return srcSize + flSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
|
|
||||||
{
|
|
||||||
BYTE* const ostart = (BYTE* const)dst;
|
|
||||||
U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
|
|
||||||
|
|
||||||
(void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
|
|
||||||
|
|
||||||
switch(flSize)
|
|
||||||
{
|
|
||||||
case 1: /* 2 - 1 - 5 */
|
|
||||||
ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
|
|
||||||
break;
|
|
||||||
case 2: /* 2 - 2 - 12 */
|
|
||||||
MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
|
|
||||||
break;
|
|
||||||
case 3: /* 2 - 2 - 20 */
|
|
||||||
MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
|
|
||||||
break;
|
|
||||||
default: /* not necessary : flSize is {1,2,3} */
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
ostart[flSize] = *(const BYTE*)src;
|
|
||||||
return flSize+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ZSTD_minGain() :
|
|
||||||
* minimum compression required
|
|
||||||
* to generate a compress block or a compressed literals section.
|
|
||||||
* note : use same formula for both situations */
|
|
||||||
static size_t ZSTD_minGain(size_t srcSize, ZSTD_strategy strat)
|
|
||||||
{
|
|
||||||
U32 const minlog = (strat>=ZSTD_btultra) ? (U32)(strat) - 1 : 6;
|
|
||||||
ZSTD_STATIC_ASSERT(ZSTD_btultra == 8);
|
|
||||||
assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat));
|
|
||||||
return (srcSize >> minlog) + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
|
|
||||||
ZSTD_hufCTables_t* nextHuf,
|
|
||||||
ZSTD_strategy strategy, int disableLiteralCompression,
|
|
||||||
void* dst, size_t dstCapacity,
|
|
||||||
const void* src, size_t srcSize,
|
|
||||||
void* workspace, size_t wkspSize,
|
|
||||||
const int bmi2)
|
|
||||||
{
|
|
||||||
size_t const minGain = ZSTD_minGain(srcSize, strategy);
|
|
||||||
size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
|
|
||||||
BYTE* const ostart = (BYTE*)dst;
|
|
||||||
U32 singleStream = srcSize < 256;
|
|
||||||
symbolEncodingType_e hType = set_compressed;
|
|
||||||
size_t cLitSize;
|
|
||||||
|
|
||||||
DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i)",
|
|
||||||
disableLiteralCompression);
|
|
||||||
|
|
||||||
/* Prepare nextEntropy assuming reusing the existing table */
|
|
||||||
memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
|
|
||||||
|
|
||||||
if (disableLiteralCompression)
|
|
||||||
return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
|
||||||
|
|
||||||
/* small ? don't even attempt compression (speed opt) */
|
|
||||||
# define COMPRESS_LITERALS_SIZE_MIN 63
|
|
||||||
{ size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN;
|
|
||||||
if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_ERROR_IF(dstCapacity < lhSize+1, dstSize_tooSmall, "not enough space for compression");
|
|
||||||
{ HUF_repeat repeat = prevHuf->repeatMode;
|
|
||||||
int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
|
|
||||||
if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
|
|
||||||
cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
|
|
||||||
workspace, wkspSize, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2)
|
|
||||||
: HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
|
|
||||||
workspace, wkspSize, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2);
|
|
||||||
if (repeat != HUF_repeat_none) {
|
|
||||||
/* reused the existing table */
|
|
||||||
hType = set_repeat;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) {
|
|
||||||
memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
|
|
||||||
return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
|
||||||
}
|
|
||||||
if (cLitSize==1) {
|
|
||||||
memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
|
|
||||||
return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hType == set_compressed) {
|
|
||||||
/* using a newly constructed table */
|
|
||||||
nextHuf->repeatMode = HUF_repeat_check;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Build header */
|
|
||||||
switch(lhSize)
|
|
||||||
{
|
|
||||||
case 3: /* 2 - 2 - 10 - 10 */
|
|
||||||
{ U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
|
|
||||||
MEM_writeLE24(ostart, lhc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 4: /* 2 - 2 - 14 - 14 */
|
|
||||||
{ U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
|
|
||||||
MEM_writeLE32(ostart, lhc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 5: /* 2 - 2 - 18 - 18 */
|
|
||||||
{ U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
|
|
||||||
MEM_writeLE32(ostart, lhc);
|
|
||||||
ostart[4] = (BYTE)(cLitSize >> 10);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: /* not possible : lhSize is {3,4,5} */
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
return lhSize+cLitSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
|
void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
|
||||||
{
|
{
|
||||||
const seqDef* const sequences = seqStorePtr->sequencesStart;
|
const seqDef* const sequences = seqStorePtr->sequencesStart;
|
||||||
|
@ -2074,418 +1915,6 @@ void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
|
||||||
mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
|
mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* -log2(x / 256) lookup table for x in [0, 256).
|
|
||||||
* If x == 0: Return 0
|
|
||||||
* Else: Return floor(-log2(x / 256) * 256)
|
|
||||||
*/
|
|
||||||
static unsigned const kInverseProbabilityLog256[256] = {
|
|
||||||
0, 2048, 1792, 1642, 1536, 1453, 1386, 1329, 1280, 1236, 1197, 1162,
|
|
||||||
1130, 1100, 1073, 1047, 1024, 1001, 980, 960, 941, 923, 906, 889,
|
|
||||||
874, 859, 844, 830, 817, 804, 791, 779, 768, 756, 745, 734,
|
|
||||||
724, 714, 704, 694, 685, 676, 667, 658, 650, 642, 633, 626,
|
|
||||||
618, 610, 603, 595, 588, 581, 574, 567, 561, 554, 548, 542,
|
|
||||||
535, 529, 523, 517, 512, 506, 500, 495, 489, 484, 478, 473,
|
|
||||||
468, 463, 458, 453, 448, 443, 438, 434, 429, 424, 420, 415,
|
|
||||||
411, 407, 402, 398, 394, 390, 386, 382, 377, 373, 370, 366,
|
|
||||||
362, 358, 354, 350, 347, 343, 339, 336, 332, 329, 325, 322,
|
|
||||||
318, 315, 311, 308, 305, 302, 298, 295, 292, 289, 286, 282,
|
|
||||||
279, 276, 273, 270, 267, 264, 261, 258, 256, 253, 250, 247,
|
|
||||||
244, 241, 239, 236, 233, 230, 228, 225, 222, 220, 217, 215,
|
|
||||||
212, 209, 207, 204, 202, 199, 197, 194, 192, 190, 187, 185,
|
|
||||||
182, 180, 178, 175, 173, 171, 168, 166, 164, 162, 159, 157,
|
|
||||||
155, 153, 151, 149, 146, 144, 142, 140, 138, 136, 134, 132,
|
|
||||||
130, 128, 126, 123, 121, 119, 117, 115, 114, 112, 110, 108,
|
|
||||||
106, 104, 102, 100, 98, 96, 94, 93, 91, 89, 87, 85,
|
|
||||||
83, 82, 80, 78, 76, 74, 73, 71, 69, 67, 66, 64,
|
|
||||||
62, 61, 59, 57, 55, 54, 52, 50, 49, 47, 46, 44,
|
|
||||||
42, 41, 39, 37, 36, 34, 33, 31, 30, 28, 26, 25,
|
|
||||||
23, 22, 20, 19, 17, 16, 14, 13, 11, 10, 8, 7,
|
|
||||||
5, 4, 2, 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the cost in bits of encoding the distribution described by count
|
|
||||||
* using the entropy bound.
|
|
||||||
*/
|
|
||||||
static size_t ZSTD_entropyCost(unsigned const* count, unsigned const max, size_t const total)
|
|
||||||
{
|
|
||||||
unsigned cost = 0;
|
|
||||||
unsigned s;
|
|
||||||
for (s = 0; s <= max; ++s) {
|
|
||||||
unsigned norm = (unsigned)((256 * count[s]) / total);
|
|
||||||
if (count[s] != 0 && norm == 0)
|
|
||||||
norm = 1;
|
|
||||||
assert(count[s] < total);
|
|
||||||
cost += count[s] * kInverseProbabilityLog256[norm];
|
|
||||||
}
|
|
||||||
return cost >> 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the cost in bits of encoding the distribution in count using the
|
|
||||||
* table described by norm. The max symbol support by norm is assumed >= max.
|
|
||||||
* norm must be valid for every symbol with non-zero probability in count.
|
|
||||||
*/
|
|
||||||
static size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog,
|
|
||||||
unsigned const* count, unsigned const max)
|
|
||||||
{
|
|
||||||
unsigned const shift = 8 - accuracyLog;
|
|
||||||
size_t cost = 0;
|
|
||||||
unsigned s;
|
|
||||||
assert(accuracyLog <= 8);
|
|
||||||
for (s = 0; s <= max; ++s) {
|
|
||||||
unsigned const normAcc = norm[s] != -1 ? norm[s] : 1;
|
|
||||||
unsigned const norm256 = normAcc << shift;
|
|
||||||
assert(norm256 > 0);
|
|
||||||
assert(norm256 < 256);
|
|
||||||
cost += count[s] * kInverseProbabilityLog256[norm256];
|
|
||||||
}
|
|
||||||
return cost >> 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned ZSTD_getFSEMaxSymbolValue(FSE_CTable const* ctable) {
|
|
||||||
void const* ptr = ctable;
|
|
||||||
U16 const* u16ptr = (U16 const*)ptr;
|
|
||||||
U32 const maxSymbolValue = MEM_read16(u16ptr + 1);
|
|
||||||
return maxSymbolValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the cost in bits of encoding the distribution in count using ctable.
|
|
||||||
* Returns an error if ctable cannot represent all the symbols in count.
|
|
||||||
*/
|
|
||||||
static size_t ZSTD_fseBitCost(
|
|
||||||
FSE_CTable const* ctable,
|
|
||||||
unsigned const* count,
|
|
||||||
unsigned const max)
|
|
||||||
{
|
|
||||||
unsigned const kAccuracyLog = 8;
|
|
||||||
size_t cost = 0;
|
|
||||||
unsigned s;
|
|
||||||
FSE_CState_t cstate;
|
|
||||||
FSE_initCState(&cstate, ctable);
|
|
||||||
RETURN_ERROR_IF(ZSTD_getFSEMaxSymbolValue(ctable) < max, GENERIC,
|
|
||||||
"Repeat FSE_CTable has maxSymbolValue %u < %u",
|
|
||||||
ZSTD_getFSEMaxSymbolValue(ctable), max);
|
|
||||||
for (s = 0; s <= max; ++s) {
|
|
||||||
unsigned const tableLog = cstate.stateLog;
|
|
||||||
unsigned const badCost = (tableLog + 1) << kAccuracyLog;
|
|
||||||
unsigned const bitCost = FSE_bitCost(cstate.symbolTT, tableLog, s, kAccuracyLog);
|
|
||||||
if (count[s] == 0)
|
|
||||||
continue;
|
|
||||||
RETURN_ERROR_IF(bitCost >= badCost, GENERIC,
|
|
||||||
"Repeat FSE_CTable has Prob[%u] == 0", s);
|
|
||||||
cost += count[s] * bitCost;
|
|
||||||
}
|
|
||||||
return cost >> kAccuracyLog;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the cost in bytes of encoding the normalized count header.
|
|
||||||
* Returns an error if any of the helper functions return an error.
|
|
||||||
*/
|
|
||||||
static size_t ZSTD_NCountCost(unsigned const* count, unsigned const max,
|
|
||||||
size_t const nbSeq, unsigned const FSELog)
|
|
||||||
{
|
|
||||||
BYTE wksp[FSE_NCOUNTBOUND];
|
|
||||||
S16 norm[MaxSeq + 1];
|
|
||||||
const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
|
|
||||||
FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq, max));
|
|
||||||
return FSE_writeNCount(wksp, sizeof(wksp), norm, max, tableLog);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
ZSTD_defaultDisallowed = 0,
|
|
||||||
ZSTD_defaultAllowed = 1
|
|
||||||
} ZSTD_defaultPolicy_e;
|
|
||||||
|
|
||||||
MEM_STATIC symbolEncodingType_e
|
|
||||||
ZSTD_selectEncodingType(
|
|
||||||
FSE_repeat* repeatMode, unsigned const* count, unsigned const max,
|
|
||||||
size_t const mostFrequent, size_t nbSeq, unsigned const FSELog,
|
|
||||||
FSE_CTable const* prevCTable,
|
|
||||||
short const* defaultNorm, U32 defaultNormLog,
|
|
||||||
ZSTD_defaultPolicy_e const isDefaultAllowed,
|
|
||||||
ZSTD_strategy const strategy)
|
|
||||||
{
|
|
||||||
ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0);
|
|
||||||
if (mostFrequent == nbSeq) {
|
|
||||||
*repeatMode = FSE_repeat_none;
|
|
||||||
if (isDefaultAllowed && nbSeq <= 2) {
|
|
||||||
/* Prefer set_basic over set_rle when there are 2 or less symbols,
|
|
||||||
* since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol.
|
|
||||||
* If basic encoding isn't possible, always choose RLE.
|
|
||||||
*/
|
|
||||||
DEBUGLOG(5, "Selected set_basic");
|
|
||||||
return set_basic;
|
|
||||||
}
|
|
||||||
DEBUGLOG(5, "Selected set_rle");
|
|
||||||
return set_rle;
|
|
||||||
}
|
|
||||||
if (strategy < ZSTD_lazy) {
|
|
||||||
if (isDefaultAllowed) {
|
|
||||||
size_t const staticFse_nbSeq_max = 1000;
|
|
||||||
size_t const mult = 10 - strategy;
|
|
||||||
size_t const baseLog = 3;
|
|
||||||
size_t const dynamicFse_nbSeq_min = (((size_t)1 << defaultNormLog) * mult) >> baseLog; /* 28-36 for offset, 56-72 for lengths */
|
|
||||||
assert(defaultNormLog >= 5 && defaultNormLog <= 6); /* xx_DEFAULTNORMLOG */
|
|
||||||
assert(mult <= 9 && mult >= 7);
|
|
||||||
if ( (*repeatMode == FSE_repeat_valid)
|
|
||||||
&& (nbSeq < staticFse_nbSeq_max) ) {
|
|
||||||
DEBUGLOG(5, "Selected set_repeat");
|
|
||||||
return set_repeat;
|
|
||||||
}
|
|
||||||
if ( (nbSeq < dynamicFse_nbSeq_min)
|
|
||||||
|| (mostFrequent < (nbSeq >> (defaultNormLog-1))) ) {
|
|
||||||
DEBUGLOG(5, "Selected set_basic");
|
|
||||||
/* The format allows default tables to be repeated, but it isn't useful.
|
|
||||||
* When using simple heuristics to select encoding type, we don't want
|
|
||||||
* to confuse these tables with dictionaries. When running more careful
|
|
||||||
* analysis, we don't need to waste time checking both repeating tables
|
|
||||||
* and default tables.
|
|
||||||
*/
|
|
||||||
*repeatMode = FSE_repeat_none;
|
|
||||||
return set_basic;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
size_t const basicCost = isDefaultAllowed ? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, count, max) : ERROR(GENERIC);
|
|
||||||
size_t const repeatCost = *repeatMode != FSE_repeat_none ? ZSTD_fseBitCost(prevCTable, count, max) : ERROR(GENERIC);
|
|
||||||
size_t const NCountCost = ZSTD_NCountCost(count, max, nbSeq, FSELog);
|
|
||||||
size_t const compressedCost = (NCountCost << 3) + ZSTD_entropyCost(count, max, nbSeq);
|
|
||||||
|
|
||||||
if (isDefaultAllowed) {
|
|
||||||
assert(!ZSTD_isError(basicCost));
|
|
||||||
assert(!(*repeatMode == FSE_repeat_valid && ZSTD_isError(repeatCost)));
|
|
||||||
}
|
|
||||||
assert(!ZSTD_isError(NCountCost));
|
|
||||||
assert(compressedCost < ERROR(maxCode));
|
|
||||||
DEBUGLOG(5, "Estimated bit costs: basic=%u\trepeat=%u\tcompressed=%u",
|
|
||||||
(unsigned)basicCost, (unsigned)repeatCost, (unsigned)compressedCost);
|
|
||||||
if (basicCost <= repeatCost && basicCost <= compressedCost) {
|
|
||||||
DEBUGLOG(5, "Selected set_basic");
|
|
||||||
assert(isDefaultAllowed);
|
|
||||||
*repeatMode = FSE_repeat_none;
|
|
||||||
return set_basic;
|
|
||||||
}
|
|
||||||
if (repeatCost <= compressedCost) {
|
|
||||||
DEBUGLOG(5, "Selected set_repeat");
|
|
||||||
assert(!ZSTD_isError(repeatCost));
|
|
||||||
return set_repeat;
|
|
||||||
}
|
|
||||||
assert(compressedCost < basicCost && compressedCost < repeatCost);
|
|
||||||
}
|
|
||||||
DEBUGLOG(5, "Selected set_compressed");
|
|
||||||
*repeatMode = FSE_repeat_check;
|
|
||||||
return set_compressed;
|
|
||||||
}
|
|
||||||
|
|
||||||
MEM_STATIC size_t
|
|
||||||
ZSTD_buildCTable(void* dst, size_t dstCapacity,
|
|
||||||
FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type,
|
|
||||||
unsigned* count, U32 max,
|
|
||||||
const BYTE* codeTable, size_t nbSeq,
|
|
||||||
const S16* defaultNorm, U32 defaultNormLog, U32 defaultMax,
|
|
||||||
const FSE_CTable* prevCTable, size_t prevCTableSize,
|
|
||||||
void* workspace, size_t workspaceSize)
|
|
||||||
{
|
|
||||||
BYTE* op = (BYTE*)dst;
|
|
||||||
const BYTE* const oend = op + dstCapacity;
|
|
||||||
DEBUGLOG(6, "ZSTD_buildCTable (dstCapacity=%u)", (unsigned)dstCapacity);
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case set_rle:
|
|
||||||
FORWARD_IF_ERROR(FSE_buildCTable_rle(nextCTable, (BYTE)max));
|
|
||||||
RETURN_ERROR_IF(dstCapacity==0, dstSize_tooSmall);
|
|
||||||
*op = codeTable[0];
|
|
||||||
return 1;
|
|
||||||
case set_repeat:
|
|
||||||
memcpy(nextCTable, prevCTable, prevCTableSize);
|
|
||||||
return 0;
|
|
||||||
case set_basic:
|
|
||||||
FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, workspace, workspaceSize)); /* note : could be pre-calculated */
|
|
||||||
return 0;
|
|
||||||
case set_compressed: {
|
|
||||||
S16 norm[MaxSeq + 1];
|
|
||||||
size_t nbSeq_1 = nbSeq;
|
|
||||||
const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
|
|
||||||
if (count[codeTable[nbSeq-1]] > 1) {
|
|
||||||
count[codeTable[nbSeq-1]]--;
|
|
||||||
nbSeq_1--;
|
|
||||||
}
|
|
||||||
assert(nbSeq_1 > 1);
|
|
||||||
FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max));
|
|
||||||
{ size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
|
|
||||||
FORWARD_IF_ERROR(NCountSize);
|
|
||||||
FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, norm, max, tableLog, workspace, workspaceSize));
|
|
||||||
return NCountSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default: assert(0); RETURN_ERROR(GENERIC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FORCE_INLINE_TEMPLATE size_t
|
|
||||||
ZSTD_encodeSequences_body(
|
|
||||||
void* dst, size_t dstCapacity,
|
|
||||||
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
|
||||||
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
|
||||||
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
|
||||||
seqDef const* sequences, size_t nbSeq, int longOffsets)
|
|
||||||
{
|
|
||||||
BIT_CStream_t blockStream;
|
|
||||||
FSE_CState_t stateMatchLength;
|
|
||||||
FSE_CState_t stateOffsetBits;
|
|
||||||
FSE_CState_t stateLitLength;
|
|
||||||
|
|
||||||
RETURN_ERROR_IF(
|
|
||||||
ERR_isError(BIT_initCStream(&blockStream, dst, dstCapacity)),
|
|
||||||
dstSize_tooSmall, "not enough space remaining");
|
|
||||||
DEBUGLOG(6, "available space for bitstream : %i (dstCapacity=%u)",
|
|
||||||
(int)(blockStream.endPtr - blockStream.startPtr),
|
|
||||||
(unsigned)dstCapacity);
|
|
||||||
|
|
||||||
/* first symbols */
|
|
||||||
FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
|
|
||||||
FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
|
|
||||||
FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
|
|
||||||
BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
|
|
||||||
if (MEM_32bits()) BIT_flushBits(&blockStream);
|
|
||||||
BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
|
|
||||||
if (MEM_32bits()) BIT_flushBits(&blockStream);
|
|
||||||
if (longOffsets) {
|
|
||||||
U32 const ofBits = ofCodeTable[nbSeq-1];
|
|
||||||
int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
|
|
||||||
if (extraBits) {
|
|
||||||
BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits);
|
|
||||||
BIT_flushBits(&blockStream);
|
|
||||||
}
|
|
||||||
BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits,
|
|
||||||
ofBits - extraBits);
|
|
||||||
} else {
|
|
||||||
BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
|
|
||||||
}
|
|
||||||
BIT_flushBits(&blockStream);
|
|
||||||
|
|
||||||
{ size_t n;
|
|
||||||
for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
|
|
||||||
BYTE const llCode = llCodeTable[n];
|
|
||||||
BYTE const ofCode = ofCodeTable[n];
|
|
||||||
BYTE const mlCode = mlCodeTable[n];
|
|
||||||
U32 const llBits = LL_bits[llCode];
|
|
||||||
U32 const ofBits = ofCode;
|
|
||||||
U32 const mlBits = ML_bits[mlCode];
|
|
||||||
DEBUGLOG(6, "encoding: litlen:%2u - matchlen:%2u - offCode:%7u",
|
|
||||||
(unsigned)sequences[n].litLength,
|
|
||||||
(unsigned)sequences[n].matchLength + MINMATCH,
|
|
||||||
(unsigned)sequences[n].offset);
|
|
||||||
/* 32b*/ /* 64b*/
|
|
||||||
/* (7)*/ /* (7)*/
|
|
||||||
FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
|
|
||||||
FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
|
|
||||||
if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
|
|
||||||
FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
|
|
||||||
if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
|
|
||||||
BIT_flushBits(&blockStream); /* (7)*/
|
|
||||||
BIT_addBits(&blockStream, sequences[n].litLength, llBits);
|
|
||||||
if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
|
|
||||||
BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
|
|
||||||
if (MEM_32bits() || (ofBits+mlBits+llBits > 56)) BIT_flushBits(&blockStream);
|
|
||||||
if (longOffsets) {
|
|
||||||
int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
|
|
||||||
if (extraBits) {
|
|
||||||
BIT_addBits(&blockStream, sequences[n].offset, extraBits);
|
|
||||||
BIT_flushBits(&blockStream); /* (7)*/
|
|
||||||
}
|
|
||||||
BIT_addBits(&blockStream, sequences[n].offset >> extraBits,
|
|
||||||
ofBits - extraBits); /* 31 */
|
|
||||||
} else {
|
|
||||||
BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
|
|
||||||
}
|
|
||||||
BIT_flushBits(&blockStream); /* (7)*/
|
|
||||||
DEBUGLOG(7, "remaining space : %i", (int)(blockStream.endPtr - blockStream.ptr));
|
|
||||||
} }
|
|
||||||
|
|
||||||
DEBUGLOG(6, "ZSTD_encodeSequences: flushing ML state with %u bits", stateMatchLength.stateLog);
|
|
||||||
FSE_flushCState(&blockStream, &stateMatchLength);
|
|
||||||
DEBUGLOG(6, "ZSTD_encodeSequences: flushing Off state with %u bits", stateOffsetBits.stateLog);
|
|
||||||
FSE_flushCState(&blockStream, &stateOffsetBits);
|
|
||||||
DEBUGLOG(6, "ZSTD_encodeSequences: flushing LL state with %u bits", stateLitLength.stateLog);
|
|
||||||
FSE_flushCState(&blockStream, &stateLitLength);
|
|
||||||
|
|
||||||
{ size_t const streamSize = BIT_closeCStream(&blockStream);
|
|
||||||
RETURN_ERROR_IF(streamSize==0, dstSize_tooSmall, "not enough space");
|
|
||||||
return streamSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t
|
|
||||||
ZSTD_encodeSequences_default(
|
|
||||||
void* dst, size_t dstCapacity,
|
|
||||||
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
|
||||||
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
|
||||||
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
|
||||||
seqDef const* sequences, size_t nbSeq, int longOffsets)
|
|
||||||
{
|
|
||||||
return ZSTD_encodeSequences_body(dst, dstCapacity,
|
|
||||||
CTable_MatchLength, mlCodeTable,
|
|
||||||
CTable_OffsetBits, ofCodeTable,
|
|
||||||
CTable_LitLength, llCodeTable,
|
|
||||||
sequences, nbSeq, longOffsets);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if DYNAMIC_BMI2
|
|
||||||
|
|
||||||
static TARGET_ATTRIBUTE("bmi2") size_t
|
|
||||||
ZSTD_encodeSequences_bmi2(
|
|
||||||
void* dst, size_t dstCapacity,
|
|
||||||
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
|
||||||
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
|
||||||
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
|
||||||
seqDef const* sequences, size_t nbSeq, int longOffsets)
|
|
||||||
{
|
|
||||||
return ZSTD_encodeSequences_body(dst, dstCapacity,
|
|
||||||
CTable_MatchLength, mlCodeTable,
|
|
||||||
CTable_OffsetBits, ofCodeTable,
|
|
||||||
CTable_LitLength, llCodeTable,
|
|
||||||
sequences, nbSeq, longOffsets);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static size_t ZSTD_encodeSequences(
|
|
||||||
void* dst, size_t dstCapacity,
|
|
||||||
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
|
||||||
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
|
||||||
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
|
||||||
seqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2)
|
|
||||||
{
|
|
||||||
DEBUGLOG(5, "ZSTD_encodeSequences: dstCapacity = %u", (unsigned)dstCapacity);
|
|
||||||
#if DYNAMIC_BMI2
|
|
||||||
if (bmi2) {
|
|
||||||
return ZSTD_encodeSequences_bmi2(dst, dstCapacity,
|
|
||||||
CTable_MatchLength, mlCodeTable,
|
|
||||||
CTable_OffsetBits, ofCodeTable,
|
|
||||||
CTable_LitLength, llCodeTable,
|
|
||||||
sequences, nbSeq, longOffsets);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
(void)bmi2;
|
|
||||||
return ZSTD_encodeSequences_default(dst, dstCapacity,
|
|
||||||
CTable_MatchLength, mlCodeTable,
|
|
||||||
CTable_OffsetBits, ofCodeTable,
|
|
||||||
CTable_LitLength, llCodeTable,
|
|
||||||
sequences, nbSeq, longOffsets);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ZSTD_disableLiteralsCompression(const ZSTD_CCtx_params* cctxParams)
|
static int ZSTD_disableLiteralsCompression(const ZSTD_CCtx_params* cctxParams)
|
||||||
{
|
{
|
||||||
switch (cctxParams->literalCompressionMode) {
|
switch (cctxParams->literalCompressionMode) {
|
||||||
|
@ -2526,16 +1955,16 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||||
BYTE* const ostart = (BYTE*)dst;
|
BYTE* const ostart = (BYTE*)dst;
|
||||||
BYTE* const oend = ostart + dstCapacity;
|
BYTE* const oend = ostart + dstCapacity;
|
||||||
BYTE* op = ostart;
|
BYTE* op = ostart;
|
||||||
size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
|
size_t const nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
|
||||||
BYTE* seqHead;
|
BYTE* seqHead;
|
||||||
BYTE* lastNCount = NULL;
|
BYTE* lastNCount = NULL;
|
||||||
|
|
||||||
|
DEBUGLOG(5, "ZSTD_compressSequences_internal (nbSeq=%zu)", nbSeq);
|
||||||
ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
|
ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
|
||||||
DEBUGLOG(5, "ZSTD_compressSequences_internal");
|
|
||||||
|
|
||||||
/* Compress literals */
|
/* Compress literals */
|
||||||
{ const BYTE* const literals = seqStorePtr->litStart;
|
{ const BYTE* const literals = seqStorePtr->litStart;
|
||||||
size_t const litSize = seqStorePtr->lit - literals;
|
size_t const litSize = (size_t)(seqStorePtr->lit - literals);
|
||||||
size_t const cSize = ZSTD_compressLiterals(
|
size_t const cSize = ZSTD_compressLiterals(
|
||||||
&prevEntropy->huf, &nextEntropy->huf,
|
&prevEntropy->huf, &nextEntropy->huf,
|
||||||
cctxParams->cParams.strategy,
|
cctxParams->cParams.strategy,
|
||||||
|
@ -2562,7 +1991,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||||
if (nbSeq==0) {
|
if (nbSeq==0) {
|
||||||
/* Copy the old tables over as if we repeated them */
|
/* Copy the old tables over as if we repeated them */
|
||||||
memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse));
|
memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse));
|
||||||
return op - ostart;
|
return (size_t)(op - ostart);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* seqHead : flags for FSE encoding type */
|
/* seqHead : flags for FSE encoding type */
|
||||||
|
@ -2583,7 +2012,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||||
ZSTD_defaultAllowed, strategy);
|
ZSTD_defaultAllowed, strategy);
|
||||||
assert(set_basic < set_compressed && set_rle < set_compressed);
|
assert(set_basic < set_compressed && set_rle < set_compressed);
|
||||||
assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
|
assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
|
||||||
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
|
{ size_t const countSize = ZSTD_buildCTable(op, (size_t)(oend - op), CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
|
||||||
count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
|
count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
|
||||||
prevEntropy->fse.litlengthCTable, sizeof(prevEntropy->fse.litlengthCTable),
|
prevEntropy->fse.litlengthCTable, sizeof(prevEntropy->fse.litlengthCTable),
|
||||||
workspace, wkspSize);
|
workspace, wkspSize);
|
||||||
|
@ -2606,7 +2035,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||||
OF_defaultNorm, OF_defaultNormLog,
|
OF_defaultNorm, OF_defaultNormLog,
|
||||||
defaultPolicy, strategy);
|
defaultPolicy, strategy);
|
||||||
assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
|
assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
|
||||||
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
|
{ size_t const countSize = ZSTD_buildCTable(op, (size_t)(oend - op), CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
|
||||||
count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
|
count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
|
||||||
prevEntropy->fse.offcodeCTable, sizeof(prevEntropy->fse.offcodeCTable),
|
prevEntropy->fse.offcodeCTable, sizeof(prevEntropy->fse.offcodeCTable),
|
||||||
workspace, wkspSize);
|
workspace, wkspSize);
|
||||||
|
@ -2627,7 +2056,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||||
ML_defaultNorm, ML_defaultNormLog,
|
ML_defaultNorm, ML_defaultNormLog,
|
||||||
ZSTD_defaultAllowed, strategy);
|
ZSTD_defaultAllowed, strategy);
|
||||||
assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
|
assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
|
||||||
{ size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
|
{ size_t const countSize = ZSTD_buildCTable(op, (size_t)(oend - op), CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
|
||||||
count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
|
count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
|
||||||
prevEntropy->fse.matchlengthCTable, sizeof(prevEntropy->fse.matchlengthCTable),
|
prevEntropy->fse.matchlengthCTable, sizeof(prevEntropy->fse.matchlengthCTable),
|
||||||
workspace, wkspSize);
|
workspace, wkspSize);
|
||||||
|
@ -2641,7 +2070,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||||
*seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
|
*seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
|
||||||
|
|
||||||
{ size_t const bitstreamSize = ZSTD_encodeSequences(
|
{ size_t const bitstreamSize = ZSTD_encodeSequences(
|
||||||
op, oend - op,
|
op, (size_t)(oend - op),
|
||||||
CTable_MatchLength, mlCodeTable,
|
CTable_MatchLength, mlCodeTable,
|
||||||
CTable_OffsetBits, ofCodeTable,
|
CTable_OffsetBits, ofCodeTable,
|
||||||
CTable_LitLength, llCodeTable,
|
CTable_LitLength, llCodeTable,
|
||||||
|
@ -2668,7 +2097,7 @@ ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUGLOG(5, "compressed block size : %u", (unsigned)(op - ostart));
|
DEBUGLOG(5, "compressed block size : %u", (unsigned)(op - ostart));
|
||||||
return op - ostart;
|
return (size_t)(op - ostart);
|
||||||
}
|
}
|
||||||
|
|
||||||
MEM_STATIC size_t
|
MEM_STATIC size_t
|
||||||
|
@ -2841,7 +2270,8 @@ static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
|
||||||
{
|
{
|
||||||
size_t cSize;
|
size_t cSize;
|
||||||
DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)",
|
DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)",
|
||||||
(unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, (unsigned)zc->blockState.matchState.nextToUpdate);
|
(unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit,
|
||||||
|
(unsigned)zc->blockState.matchState.nextToUpdate);
|
||||||
|
|
||||||
{ const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize);
|
{ const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize);
|
||||||
FORWARD_IF_ERROR(bss);
|
FORWARD_IF_ERROR(bss);
|
||||||
|
@ -3109,8 +2539,9 @@ size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx)
|
||||||
|
|
||||||
size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
|
size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
size_t const blockSizeMax = ZSTD_getBlockSize(cctx);
|
DEBUGLOG(5, "ZSTD_compressBlock: srcSize = %u", (unsigned)srcSize);
|
||||||
RETURN_ERROR_IF(srcSize > blockSizeMax, srcSize_wrong);
|
{ size_t const blockSizeMax = ZSTD_getBlockSize(cctx);
|
||||||
|
RETURN_ERROR_IF(srcSize > blockSizeMax, srcSize_wrong); }
|
||||||
|
|
||||||
return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */);
|
return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */);
|
||||||
}
|
}
|
||||||
|
@ -3135,7 +2566,7 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms,
|
||||||
if (srcSize <= HASH_READ_SIZE) return 0;
|
if (srcSize <= HASH_READ_SIZE) return 0;
|
||||||
|
|
||||||
while (iend - ip > HASH_READ_SIZE) {
|
while (iend - ip > HASH_READ_SIZE) {
|
||||||
size_t const remaining = iend - ip;
|
size_t const remaining = (size_t)(iend - ip);
|
||||||
size_t const chunk = MIN(remaining, ZSTD_CHUNKSIZE_MAX);
|
size_t const chunk = MIN(remaining, ZSTD_CHUNKSIZE_MAX);
|
||||||
const BYTE* const ichunk = ip + chunk;
|
const BYTE* const ichunk = ip + chunk;
|
||||||
|
|
||||||
|
|
|
@ -134,9 +134,15 @@ typedef struct {
|
||||||
typedef struct ZSTD_matchState_t ZSTD_matchState_t;
|
typedef struct ZSTD_matchState_t ZSTD_matchState_t;
|
||||||
struct ZSTD_matchState_t {
|
struct ZSTD_matchState_t {
|
||||||
ZSTD_window_t window; /* State for window round buffer management */
|
ZSTD_window_t window; /* State for window round buffer management */
|
||||||
U32 loadedDictEnd; /* index of end of dictionary, within context's referential. When dict referential is copied into active context (i.e. not attached), effectively same value as dictSize, since referential starts from zero */
|
U32 loadedDictEnd; /* index of end of dictionary, within context's referential.
|
||||||
|
* When loadedDictEnd != 0, a dictionary is in use, and still valid.
|
||||||
|
* This relies on a mechanism to set loadedDictEnd=0 when dictionary is no longer within distance.
|
||||||
|
* Such mechanism is provided within ZSTD_window_enforceMaxDist() and ZSTD_checkDictValidity().
|
||||||
|
* When dict referential is copied into active context (i.e. not attached),
|
||||||
|
* loadedDictEnd == dictSize, since referential starts from zero.
|
||||||
|
*/
|
||||||
U32 nextToUpdate; /* index from which to continue table update */
|
U32 nextToUpdate; /* index from which to continue table update */
|
||||||
U32 hashLog3; /* dispatch table : larger == faster, more memory */
|
U32 hashLog3; /* dispatch table for matches of len==3 : larger == faster, more memory */
|
||||||
U32* hashTable;
|
U32* hashTable;
|
||||||
U32* hashTable3;
|
U32* hashTable3;
|
||||||
U32* chainTable;
|
U32* chainTable;
|
||||||
|
@ -307,6 +313,30 @@ MEM_STATIC U32 ZSTD_MLcode(U32 mlBase)
|
||||||
return (mlBase > 127) ? ZSTD_highbit32(mlBase) + ML_deltaCode : ML_Code[mlBase];
|
return (mlBase > 127) ? ZSTD_highbit32(mlBase) + ML_deltaCode : ML_Code[mlBase];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ZSTD_cParam_withinBounds:
|
||||||
|
* @return 1 if value is within cParam bounds,
|
||||||
|
* 0 otherwise */
|
||||||
|
MEM_STATIC int ZSTD_cParam_withinBounds(ZSTD_cParameter cParam, int value)
|
||||||
|
{
|
||||||
|
ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam);
|
||||||
|
if (ZSTD_isError(bounds.error)) return 0;
|
||||||
|
if (value < bounds.lowerBound) return 0;
|
||||||
|
if (value > bounds.upperBound) return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ZSTD_minGain() :
|
||||||
|
* minimum compression required
|
||||||
|
* to generate a compress block or a compressed literals section.
|
||||||
|
* note : use same formula for both situations */
|
||||||
|
MEM_STATIC size_t ZSTD_minGain(size_t srcSize, ZSTD_strategy strat)
|
||||||
|
{
|
||||||
|
U32 const minlog = (strat>=ZSTD_btultra) ? (U32)(strat) - 1 : 6;
|
||||||
|
ZSTD_STATIC_ASSERT(ZSTD_btultra == 8);
|
||||||
|
assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat));
|
||||||
|
return (srcSize >> minlog) + 2;
|
||||||
|
}
|
||||||
|
|
||||||
/*! ZSTD_storeSeq() :
|
/*! ZSTD_storeSeq() :
|
||||||
* Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
|
* Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
|
||||||
* `offsetCode` : distance to match + 3 (values 1-3 are repCodes).
|
* `offsetCode` : distance to match + 3 (values 1-3 are repCodes).
|
||||||
|
@ -326,7 +356,7 @@ MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const v
|
||||||
/* copy Literals */
|
/* copy Literals */
|
||||||
assert(seqStorePtr->maxNbLit <= 128 KB);
|
assert(seqStorePtr->maxNbLit <= 128 KB);
|
||||||
assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + seqStorePtr->maxNbLit);
|
assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + seqStorePtr->maxNbLit);
|
||||||
ZSTD_wildcopy(seqStorePtr->lit, literals, litLength, ZSTD_no_overlap);
|
ZSTD_wildcopy(seqStorePtr->lit, literals, (ptrdiff_t)litLength, ZSTD_no_overlap);
|
||||||
seqStorePtr->lit += litLength;
|
seqStorePtr->lit += litLength;
|
||||||
|
|
||||||
/* literal Length */
|
/* literal Length */
|
||||||
|
@ -739,24 +769,37 @@ ZSTD_window_enforceMaxDist(ZSTD_window_t* window,
|
||||||
|
|
||||||
/* Similar to ZSTD_window_enforceMaxDist(),
|
/* Similar to ZSTD_window_enforceMaxDist(),
|
||||||
* but only invalidates dictionary
|
* but only invalidates dictionary
|
||||||
* when input progresses beyond window size. */
|
* when input progresses beyond window size.
|
||||||
|
* assumption : loadedDictEndPtr and dictMatchStatePtr are valid (non NULL)
|
||||||
|
* loadedDictEnd uses same referential as window->base
|
||||||
|
* maxDist is the window size */
|
||||||
MEM_STATIC void
|
MEM_STATIC void
|
||||||
ZSTD_checkDictValidity(ZSTD_window_t* window,
|
ZSTD_checkDictValidity(const ZSTD_window_t* window,
|
||||||
const void* blockEnd,
|
const void* blockEnd,
|
||||||
U32 maxDist,
|
U32 maxDist,
|
||||||
U32* loadedDictEndPtr,
|
U32* loadedDictEndPtr,
|
||||||
const ZSTD_matchState_t** dictMatchStatePtr)
|
const ZSTD_matchState_t** dictMatchStatePtr)
|
||||||
{
|
{
|
||||||
U32 const blockEndIdx = (U32)((BYTE const*)blockEnd - window->base);
|
assert(loadedDictEndPtr != NULL);
|
||||||
U32 const loadedDictEnd = (loadedDictEndPtr != NULL) ? *loadedDictEndPtr : 0;
|
assert(dictMatchStatePtr != NULL);
|
||||||
DEBUGLOG(5, "ZSTD_checkDictValidity: blockEndIdx=%u, maxDist=%u, loadedDictEnd=%u",
|
{ U32 const blockEndIdx = (U32)((BYTE const*)blockEnd - window->base);
|
||||||
(unsigned)blockEndIdx, (unsigned)maxDist, (unsigned)loadedDictEnd);
|
U32 const loadedDictEnd = *loadedDictEndPtr;
|
||||||
|
DEBUGLOG(5, "ZSTD_checkDictValidity: blockEndIdx=%u, maxDist=%u, loadedDictEnd=%u",
|
||||||
|
(unsigned)blockEndIdx, (unsigned)maxDist, (unsigned)loadedDictEnd);
|
||||||
|
assert(blockEndIdx >= loadedDictEnd);
|
||||||
|
|
||||||
if (loadedDictEnd && (blockEndIdx > maxDist + loadedDictEnd)) {
|
if (blockEndIdx > loadedDictEnd + maxDist) {
|
||||||
/* On reaching window size, dictionaries are invalidated */
|
/* On reaching window size, dictionaries are invalidated.
|
||||||
if (loadedDictEndPtr) *loadedDictEndPtr = 0;
|
* For simplification, if window size is reached anywhere within next block,
|
||||||
if (dictMatchStatePtr) *dictMatchStatePtr = NULL;
|
* the dictionary is invalidated for the full block.
|
||||||
}
|
*/
|
||||||
|
DEBUGLOG(6, "invalidating dictionary for current block (distance > windowSize)");
|
||||||
|
*loadedDictEndPtr = 0;
|
||||||
|
*dictMatchStatePtr = NULL;
|
||||||
|
} else {
|
||||||
|
if (*loadedDictEndPtr != 0) {
|
||||||
|
DEBUGLOG(6, "dictionary considered valid for current block");
|
||||||
|
} } }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -798,6 +841,17 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
|
||||||
return contiguous;
|
return contiguous;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MEM_STATIC U32 ZSTD_getLowestMatchIndex(const ZSTD_matchState_t* ms, U32 current, unsigned windowLog)
|
||||||
|
{
|
||||||
|
U32 const maxDistance = 1U << windowLog;
|
||||||
|
U32 const lowestValid = ms->window.lowLimit;
|
||||||
|
U32 const withinWindow = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid;
|
||||||
|
U32 const isDictionary = (ms->loadedDictEnd != 0);
|
||||||
|
U32 const matchLowest = isDictionary ? lowestValid : withinWindow;
|
||||||
|
return matchLowest;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* debug functions */
|
/* debug functions */
|
||||||
#if (DEBUGLEVEL>=2)
|
#if (DEBUGLEVEL>=2)
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||||
|
* in the COPYING file in the root directory of this source tree).
|
||||||
|
* You may select, at your option, one of the above-listed licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*-*************************************
|
||||||
|
* Dependencies
|
||||||
|
***************************************/
|
||||||
|
#include "zstd_compress_literals.h"
|
||||||
|
|
||||||
|
size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
|
||||||
|
{
|
||||||
|
BYTE* const ostart = (BYTE* const)dst;
|
||||||
|
U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
|
||||||
|
|
||||||
|
RETURN_ERROR_IF(srcSize + flSize > dstCapacity, dstSize_tooSmall);
|
||||||
|
|
||||||
|
switch(flSize)
|
||||||
|
{
|
||||||
|
case 1: /* 2 - 1 - 5 */
|
||||||
|
ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
|
||||||
|
break;
|
||||||
|
case 2: /* 2 - 2 - 12 */
|
||||||
|
MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
|
||||||
|
break;
|
||||||
|
case 3: /* 2 - 2 - 20 */
|
||||||
|
MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
|
||||||
|
break;
|
||||||
|
default: /* not necessary : flSize is {1,2,3} */
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(ostart + flSize, src, srcSize);
|
||||||
|
return srcSize + flSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
|
||||||
|
{
|
||||||
|
BYTE* const ostart = (BYTE* const)dst;
|
||||||
|
U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
|
||||||
|
|
||||||
|
(void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
|
||||||
|
|
||||||
|
switch(flSize)
|
||||||
|
{
|
||||||
|
case 1: /* 2 - 1 - 5 */
|
||||||
|
ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
|
||||||
|
break;
|
||||||
|
case 2: /* 2 - 2 - 12 */
|
||||||
|
MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
|
||||||
|
break;
|
||||||
|
case 3: /* 2 - 2 - 20 */
|
||||||
|
MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
|
||||||
|
break;
|
||||||
|
default: /* not necessary : flSize is {1,2,3} */
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ostart[flSize] = *(const BYTE*)src;
|
||||||
|
return flSize+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
|
||||||
|
ZSTD_hufCTables_t* nextHuf,
|
||||||
|
ZSTD_strategy strategy, int disableLiteralCompression,
|
||||||
|
void* dst, size_t dstCapacity,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
void* workspace, size_t wkspSize,
|
||||||
|
const int bmi2)
|
||||||
|
{
|
||||||
|
size_t const minGain = ZSTD_minGain(srcSize, strategy);
|
||||||
|
size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
|
||||||
|
BYTE* const ostart = (BYTE*)dst;
|
||||||
|
U32 singleStream = srcSize < 256;
|
||||||
|
symbolEncodingType_e hType = set_compressed;
|
||||||
|
size_t cLitSize;
|
||||||
|
|
||||||
|
DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i)",
|
||||||
|
disableLiteralCompression);
|
||||||
|
|
||||||
|
/* Prepare nextEntropy assuming reusing the existing table */
|
||||||
|
memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
|
||||||
|
|
||||||
|
if (disableLiteralCompression)
|
||||||
|
return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
||||||
|
|
||||||
|
/* small ? don't even attempt compression (speed opt) */
|
||||||
|
# define COMPRESS_LITERALS_SIZE_MIN 63
|
||||||
|
{ size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN;
|
||||||
|
if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_ERROR_IF(dstCapacity < lhSize+1, dstSize_tooSmall, "not enough space for compression");
|
||||||
|
{ HUF_repeat repeat = prevHuf->repeatMode;
|
||||||
|
int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
|
||||||
|
if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
|
||||||
|
cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
|
||||||
|
workspace, wkspSize, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2)
|
||||||
|
: HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
|
||||||
|
workspace, wkspSize, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2);
|
||||||
|
if (repeat != HUF_repeat_none) {
|
||||||
|
/* reused the existing table */
|
||||||
|
hType = set_repeat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) {
|
||||||
|
memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
|
||||||
|
return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
|
||||||
|
}
|
||||||
|
if (cLitSize==1) {
|
||||||
|
memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
|
||||||
|
return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hType == set_compressed) {
|
||||||
|
/* using a newly constructed table */
|
||||||
|
nextHuf->repeatMode = HUF_repeat_check;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build header */
|
||||||
|
switch(lhSize)
|
||||||
|
{
|
||||||
|
case 3: /* 2 - 2 - 10 - 10 */
|
||||||
|
{ U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
|
||||||
|
MEM_writeLE24(ostart, lhc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4: /* 2 - 2 - 14 - 14 */
|
||||||
|
{ U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
|
||||||
|
MEM_writeLE32(ostart, lhc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 5: /* 2 - 2 - 18 - 18 */
|
||||||
|
{ U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
|
||||||
|
MEM_writeLE32(ostart, lhc);
|
||||||
|
ostart[4] = (BYTE)(cLitSize >> 10);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: /* not possible : lhSize is {3,4,5} */
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
return lhSize+cLitSize;
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||||
|
* in the COPYING file in the root directory of this source tree).
|
||||||
|
* You may select, at your option, one of the above-listed licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZSTD_COMPRESS_LITERALS_H
|
||||||
|
#define ZSTD_COMPRESS_LITERALS_H
|
||||||
|
|
||||||
|
#include "zstd_compress_internal.h" /* ZSTD_hufCTables_t, ZSTD_minGain() */
|
||||||
|
|
||||||
|
|
||||||
|
size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
|
||||||
|
ZSTD_hufCTables_t* nextHuf,
|
||||||
|
ZSTD_strategy strategy, int disableLiteralCompression,
|
||||||
|
void* dst, size_t dstCapacity,
|
||||||
|
const void* src, size_t srcSize,
|
||||||
|
void* workspace, size_t wkspSize,
|
||||||
|
const int bmi2);
|
||||||
|
|
||||||
|
#endif /* ZSTD_COMPRESS_LITERALS_H */
|
|
@ -0,0 +1,415 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||||
|
* in the COPYING file in the root directory of this source tree).
|
||||||
|
* You may select, at your option, one of the above-listed licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*-*************************************
|
||||||
|
* Dependencies
|
||||||
|
***************************************/
|
||||||
|
#include "zstd_compress_sequences.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* -log2(x / 256) lookup table for x in [0, 256).
|
||||||
|
* If x == 0: Return 0
|
||||||
|
* Else: Return floor(-log2(x / 256) * 256)
|
||||||
|
*/
|
||||||
|
static unsigned const kInverseProbabilityLog256[256] = {
|
||||||
|
0, 2048, 1792, 1642, 1536, 1453, 1386, 1329, 1280, 1236, 1197, 1162,
|
||||||
|
1130, 1100, 1073, 1047, 1024, 1001, 980, 960, 941, 923, 906, 889,
|
||||||
|
874, 859, 844, 830, 817, 804, 791, 779, 768, 756, 745, 734,
|
||||||
|
724, 714, 704, 694, 685, 676, 667, 658, 650, 642, 633, 626,
|
||||||
|
618, 610, 603, 595, 588, 581, 574, 567, 561, 554, 548, 542,
|
||||||
|
535, 529, 523, 517, 512, 506, 500, 495, 489, 484, 478, 473,
|
||||||
|
468, 463, 458, 453, 448, 443, 438, 434, 429, 424, 420, 415,
|
||||||
|
411, 407, 402, 398, 394, 390, 386, 382, 377, 373, 370, 366,
|
||||||
|
362, 358, 354, 350, 347, 343, 339, 336, 332, 329, 325, 322,
|
||||||
|
318, 315, 311, 308, 305, 302, 298, 295, 292, 289, 286, 282,
|
||||||
|
279, 276, 273, 270, 267, 264, 261, 258, 256, 253, 250, 247,
|
||||||
|
244, 241, 239, 236, 233, 230, 228, 225, 222, 220, 217, 215,
|
||||||
|
212, 209, 207, 204, 202, 199, 197, 194, 192, 190, 187, 185,
|
||||||
|
182, 180, 178, 175, 173, 171, 168, 166, 164, 162, 159, 157,
|
||||||
|
155, 153, 151, 149, 146, 144, 142, 140, 138, 136, 134, 132,
|
||||||
|
130, 128, 126, 123, 121, 119, 117, 115, 114, 112, 110, 108,
|
||||||
|
106, 104, 102, 100, 98, 96, 94, 93, 91, 89, 87, 85,
|
||||||
|
83, 82, 80, 78, 76, 74, 73, 71, 69, 67, 66, 64,
|
||||||
|
62, 61, 59, 57, 55, 54, 52, 50, 49, 47, 46, 44,
|
||||||
|
42, 41, 39, 37, 36, 34, 33, 31, 30, 28, 26, 25,
|
||||||
|
23, 22, 20, 19, 17, 16, 14, 13, 11, 10, 8, 7,
|
||||||
|
5, 4, 2, 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned ZSTD_getFSEMaxSymbolValue(FSE_CTable const* ctable) {
|
||||||
|
void const* ptr = ctable;
|
||||||
|
U16 const* u16ptr = (U16 const*)ptr;
|
||||||
|
U32 const maxSymbolValue = MEM_read16(u16ptr + 1);
|
||||||
|
return maxSymbolValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the cost in bytes of encoding the normalized count header.
|
||||||
|
* Returns an error if any of the helper functions return an error.
|
||||||
|
*/
|
||||||
|
static size_t ZSTD_NCountCost(unsigned const* count, unsigned const max,
|
||||||
|
size_t const nbSeq, unsigned const FSELog)
|
||||||
|
{
|
||||||
|
BYTE wksp[FSE_NCOUNTBOUND];
|
||||||
|
S16 norm[MaxSeq + 1];
|
||||||
|
const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
|
||||||
|
FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq, max));
|
||||||
|
return FSE_writeNCount(wksp, sizeof(wksp), norm, max, tableLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the cost in bits of encoding the distribution described by count
|
||||||
|
* using the entropy bound.
|
||||||
|
*/
|
||||||
|
static size_t ZSTD_entropyCost(unsigned const* count, unsigned const max, size_t const total)
|
||||||
|
{
|
||||||
|
unsigned cost = 0;
|
||||||
|
unsigned s;
|
||||||
|
for (s = 0; s <= max; ++s) {
|
||||||
|
unsigned norm = (unsigned)((256 * count[s]) / total);
|
||||||
|
if (count[s] != 0 && norm == 0)
|
||||||
|
norm = 1;
|
||||||
|
assert(count[s] < total);
|
||||||
|
cost += count[s] * kInverseProbabilityLog256[norm];
|
||||||
|
}
|
||||||
|
return cost >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the cost in bits of encoding the distribution in count using ctable.
|
||||||
|
* Returns an error if ctable cannot represent all the symbols in count.
|
||||||
|
*/
|
||||||
|
static size_t ZSTD_fseBitCost(
|
||||||
|
FSE_CTable const* ctable,
|
||||||
|
unsigned const* count,
|
||||||
|
unsigned const max)
|
||||||
|
{
|
||||||
|
unsigned const kAccuracyLog = 8;
|
||||||
|
size_t cost = 0;
|
||||||
|
unsigned s;
|
||||||
|
FSE_CState_t cstate;
|
||||||
|
FSE_initCState(&cstate, ctable);
|
||||||
|
RETURN_ERROR_IF(ZSTD_getFSEMaxSymbolValue(ctable) < max, GENERIC,
|
||||||
|
"Repeat FSE_CTable has maxSymbolValue %u < %u",
|
||||||
|
ZSTD_getFSEMaxSymbolValue(ctable), max);
|
||||||
|
for (s = 0; s <= max; ++s) {
|
||||||
|
unsigned const tableLog = cstate.stateLog;
|
||||||
|
unsigned const badCost = (tableLog + 1) << kAccuracyLog;
|
||||||
|
unsigned const bitCost = FSE_bitCost(cstate.symbolTT, tableLog, s, kAccuracyLog);
|
||||||
|
if (count[s] == 0)
|
||||||
|
continue;
|
||||||
|
RETURN_ERROR_IF(bitCost >= badCost, GENERIC,
|
||||||
|
"Repeat FSE_CTable has Prob[%u] == 0", s);
|
||||||
|
cost += count[s] * bitCost;
|
||||||
|
}
|
||||||
|
return cost >> kAccuracyLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the cost in bits of encoding the distribution in count using the
|
||||||
|
* table described by norm. The max symbol support by norm is assumed >= max.
|
||||||
|
* norm must be valid for every symbol with non-zero probability in count.
|
||||||
|
*/
|
||||||
|
static size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog,
|
||||||
|
unsigned const* count, unsigned const max)
|
||||||
|
{
|
||||||
|
unsigned const shift = 8 - accuracyLog;
|
||||||
|
size_t cost = 0;
|
||||||
|
unsigned s;
|
||||||
|
assert(accuracyLog <= 8);
|
||||||
|
for (s = 0; s <= max; ++s) {
|
||||||
|
unsigned const normAcc = norm[s] != -1 ? norm[s] : 1;
|
||||||
|
unsigned const norm256 = normAcc << shift;
|
||||||
|
assert(norm256 > 0);
|
||||||
|
assert(norm256 < 256);
|
||||||
|
cost += count[s] * kInverseProbabilityLog256[norm256];
|
||||||
|
}
|
||||||
|
return cost >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbolEncodingType_e
|
||||||
|
ZSTD_selectEncodingType(
|
||||||
|
FSE_repeat* repeatMode, unsigned const* count, unsigned const max,
|
||||||
|
size_t const mostFrequent, size_t nbSeq, unsigned const FSELog,
|
||||||
|
FSE_CTable const* prevCTable,
|
||||||
|
short const* defaultNorm, U32 defaultNormLog,
|
||||||
|
ZSTD_defaultPolicy_e const isDefaultAllowed,
|
||||||
|
ZSTD_strategy const strategy)
|
||||||
|
{
|
||||||
|
ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0);
|
||||||
|
if (mostFrequent == nbSeq) {
|
||||||
|
*repeatMode = FSE_repeat_none;
|
||||||
|
if (isDefaultAllowed && nbSeq <= 2) {
|
||||||
|
/* Prefer set_basic over set_rle when there are 2 or less symbols,
|
||||||
|
* since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol.
|
||||||
|
* If basic encoding isn't possible, always choose RLE.
|
||||||
|
*/
|
||||||
|
DEBUGLOG(5, "Selected set_basic");
|
||||||
|
return set_basic;
|
||||||
|
}
|
||||||
|
DEBUGLOG(5, "Selected set_rle");
|
||||||
|
return set_rle;
|
||||||
|
}
|
||||||
|
if (strategy < ZSTD_lazy) {
|
||||||
|
if (isDefaultAllowed) {
|
||||||
|
size_t const staticFse_nbSeq_max = 1000;
|
||||||
|
size_t const mult = 10 - strategy;
|
||||||
|
size_t const baseLog = 3;
|
||||||
|
size_t const dynamicFse_nbSeq_min = (((size_t)1 << defaultNormLog) * mult) >> baseLog; /* 28-36 for offset, 56-72 for lengths */
|
||||||
|
assert(defaultNormLog >= 5 && defaultNormLog <= 6); /* xx_DEFAULTNORMLOG */
|
||||||
|
assert(mult <= 9 && mult >= 7);
|
||||||
|
if ( (*repeatMode == FSE_repeat_valid)
|
||||||
|
&& (nbSeq < staticFse_nbSeq_max) ) {
|
||||||
|
DEBUGLOG(5, "Selected set_repeat");
|
||||||
|
return set_repeat;
|
||||||
|
}
|
||||||
|
if ( (nbSeq < dynamicFse_nbSeq_min)
|
||||||
|
|| (mostFrequent < (nbSeq >> (defaultNormLog-1))) ) {
|
||||||
|
DEBUGLOG(5, "Selected set_basic");
|
||||||
|
/* The format allows default tables to be repeated, but it isn't useful.
|
||||||
|
* When using simple heuristics to select encoding type, we don't want
|
||||||
|
* to confuse these tables with dictionaries. When running more careful
|
||||||
|
* analysis, we don't need to waste time checking both repeating tables
|
||||||
|
* and default tables.
|
||||||
|
*/
|
||||||
|
*repeatMode = FSE_repeat_none;
|
||||||
|
return set_basic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
size_t const basicCost = isDefaultAllowed ? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, count, max) : ERROR(GENERIC);
|
||||||
|
size_t const repeatCost = *repeatMode != FSE_repeat_none ? ZSTD_fseBitCost(prevCTable, count, max) : ERROR(GENERIC);
|
||||||
|
size_t const NCountCost = ZSTD_NCountCost(count, max, nbSeq, FSELog);
|
||||||
|
size_t const compressedCost = (NCountCost << 3) + ZSTD_entropyCost(count, max, nbSeq);
|
||||||
|
|
||||||
|
if (isDefaultAllowed) {
|
||||||
|
assert(!ZSTD_isError(basicCost));
|
||||||
|
assert(!(*repeatMode == FSE_repeat_valid && ZSTD_isError(repeatCost)));
|
||||||
|
}
|
||||||
|
assert(!ZSTD_isError(NCountCost));
|
||||||
|
assert(compressedCost < ERROR(maxCode));
|
||||||
|
DEBUGLOG(5, "Estimated bit costs: basic=%u\trepeat=%u\tcompressed=%u",
|
||||||
|
(unsigned)basicCost, (unsigned)repeatCost, (unsigned)compressedCost);
|
||||||
|
if (basicCost <= repeatCost && basicCost <= compressedCost) {
|
||||||
|
DEBUGLOG(5, "Selected set_basic");
|
||||||
|
assert(isDefaultAllowed);
|
||||||
|
*repeatMode = FSE_repeat_none;
|
||||||
|
return set_basic;
|
||||||
|
}
|
||||||
|
if (repeatCost <= compressedCost) {
|
||||||
|
DEBUGLOG(5, "Selected set_repeat");
|
||||||
|
assert(!ZSTD_isError(repeatCost));
|
||||||
|
return set_repeat;
|
||||||
|
}
|
||||||
|
assert(compressedCost < basicCost && compressedCost < repeatCost);
|
||||||
|
}
|
||||||
|
DEBUGLOG(5, "Selected set_compressed");
|
||||||
|
*repeatMode = FSE_repeat_check;
|
||||||
|
return set_compressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
ZSTD_buildCTable(void* dst, size_t dstCapacity,
|
||||||
|
FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type,
|
||||||
|
unsigned* count, U32 max,
|
||||||
|
const BYTE* codeTable, size_t nbSeq,
|
||||||
|
const S16* defaultNorm, U32 defaultNormLog, U32 defaultMax,
|
||||||
|
const FSE_CTable* prevCTable, size_t prevCTableSize,
|
||||||
|
void* workspace, size_t workspaceSize)
|
||||||
|
{
|
||||||
|
BYTE* op = (BYTE*)dst;
|
||||||
|
const BYTE* const oend = op + dstCapacity;
|
||||||
|
DEBUGLOG(6, "ZSTD_buildCTable (dstCapacity=%u)", (unsigned)dstCapacity);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case set_rle:
|
||||||
|
FORWARD_IF_ERROR(FSE_buildCTable_rle(nextCTable, (BYTE)max));
|
||||||
|
RETURN_ERROR_IF(dstCapacity==0, dstSize_tooSmall);
|
||||||
|
*op = codeTable[0];
|
||||||
|
return 1;
|
||||||
|
case set_repeat:
|
||||||
|
memcpy(nextCTable, prevCTable, prevCTableSize);
|
||||||
|
return 0;
|
||||||
|
case set_basic:
|
||||||
|
FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, workspace, workspaceSize)); /* note : could be pre-calculated */
|
||||||
|
return 0;
|
||||||
|
case set_compressed: {
|
||||||
|
S16 norm[MaxSeq + 1];
|
||||||
|
size_t nbSeq_1 = nbSeq;
|
||||||
|
const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
|
||||||
|
if (count[codeTable[nbSeq-1]] > 1) {
|
||||||
|
count[codeTable[nbSeq-1]]--;
|
||||||
|
nbSeq_1--;
|
||||||
|
}
|
||||||
|
assert(nbSeq_1 > 1);
|
||||||
|
FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max));
|
||||||
|
{ size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
|
||||||
|
FORWARD_IF_ERROR(NCountSize);
|
||||||
|
FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, norm, max, tableLog, workspace, workspaceSize));
|
||||||
|
return NCountSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default: assert(0); RETURN_ERROR(GENERIC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE_TEMPLATE size_t
|
||||||
|
ZSTD_encodeSequences_body(
|
||||||
|
void* dst, size_t dstCapacity,
|
||||||
|
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
||||||
|
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
||||||
|
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
||||||
|
seqDef const* sequences, size_t nbSeq, int longOffsets)
|
||||||
|
{
|
||||||
|
BIT_CStream_t blockStream;
|
||||||
|
FSE_CState_t stateMatchLength;
|
||||||
|
FSE_CState_t stateOffsetBits;
|
||||||
|
FSE_CState_t stateLitLength;
|
||||||
|
|
||||||
|
RETURN_ERROR_IF(
|
||||||
|
ERR_isError(BIT_initCStream(&blockStream, dst, dstCapacity)),
|
||||||
|
dstSize_tooSmall, "not enough space remaining");
|
||||||
|
DEBUGLOG(6, "available space for bitstream : %i (dstCapacity=%u)",
|
||||||
|
(int)(blockStream.endPtr - blockStream.startPtr),
|
||||||
|
(unsigned)dstCapacity);
|
||||||
|
|
||||||
|
/* first symbols */
|
||||||
|
FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
|
||||||
|
FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
|
||||||
|
FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
|
||||||
|
BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
|
||||||
|
if (MEM_32bits()) BIT_flushBits(&blockStream);
|
||||||
|
BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
|
||||||
|
if (MEM_32bits()) BIT_flushBits(&blockStream);
|
||||||
|
if (longOffsets) {
|
||||||
|
U32 const ofBits = ofCodeTable[nbSeq-1];
|
||||||
|
int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
|
||||||
|
if (extraBits) {
|
||||||
|
BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits);
|
||||||
|
BIT_flushBits(&blockStream);
|
||||||
|
}
|
||||||
|
BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits,
|
||||||
|
ofBits - extraBits);
|
||||||
|
} else {
|
||||||
|
BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
|
||||||
|
}
|
||||||
|
BIT_flushBits(&blockStream);
|
||||||
|
|
||||||
|
{ size_t n;
|
||||||
|
for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
|
||||||
|
BYTE const llCode = llCodeTable[n];
|
||||||
|
BYTE const ofCode = ofCodeTable[n];
|
||||||
|
BYTE const mlCode = mlCodeTable[n];
|
||||||
|
U32 const llBits = LL_bits[llCode];
|
||||||
|
U32 const ofBits = ofCode;
|
||||||
|
U32 const mlBits = ML_bits[mlCode];
|
||||||
|
DEBUGLOG(6, "encoding: litlen:%2u - matchlen:%2u - offCode:%7u",
|
||||||
|
(unsigned)sequences[n].litLength,
|
||||||
|
(unsigned)sequences[n].matchLength + MINMATCH,
|
||||||
|
(unsigned)sequences[n].offset);
|
||||||
|
/* 32b*/ /* 64b*/
|
||||||
|
/* (7)*/ /* (7)*/
|
||||||
|
FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
|
||||||
|
FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
|
||||||
|
if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
|
||||||
|
FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
|
||||||
|
if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
|
||||||
|
BIT_flushBits(&blockStream); /* (7)*/
|
||||||
|
BIT_addBits(&blockStream, sequences[n].litLength, llBits);
|
||||||
|
if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
|
||||||
|
BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
|
||||||
|
if (MEM_32bits() || (ofBits+mlBits+llBits > 56)) BIT_flushBits(&blockStream);
|
||||||
|
if (longOffsets) {
|
||||||
|
int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
|
||||||
|
if (extraBits) {
|
||||||
|
BIT_addBits(&blockStream, sequences[n].offset, extraBits);
|
||||||
|
BIT_flushBits(&blockStream); /* (7)*/
|
||||||
|
}
|
||||||
|
BIT_addBits(&blockStream, sequences[n].offset >> extraBits,
|
||||||
|
ofBits - extraBits); /* 31 */
|
||||||
|
} else {
|
||||||
|
BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
|
||||||
|
}
|
||||||
|
BIT_flushBits(&blockStream); /* (7)*/
|
||||||
|
DEBUGLOG(7, "remaining space : %i", (int)(blockStream.endPtr - blockStream.ptr));
|
||||||
|
} }
|
||||||
|
|
||||||
|
DEBUGLOG(6, "ZSTD_encodeSequences: flushing ML state with %u bits", stateMatchLength.stateLog);
|
||||||
|
FSE_flushCState(&blockStream, &stateMatchLength);
|
||||||
|
DEBUGLOG(6, "ZSTD_encodeSequences: flushing Off state with %u bits", stateOffsetBits.stateLog);
|
||||||
|
FSE_flushCState(&blockStream, &stateOffsetBits);
|
||||||
|
DEBUGLOG(6, "ZSTD_encodeSequences: flushing LL state with %u bits", stateLitLength.stateLog);
|
||||||
|
FSE_flushCState(&blockStream, &stateLitLength);
|
||||||
|
|
||||||
|
{ size_t const streamSize = BIT_closeCStream(&blockStream);
|
||||||
|
RETURN_ERROR_IF(streamSize==0, dstSize_tooSmall, "not enough space");
|
||||||
|
return streamSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
ZSTD_encodeSequences_default(
|
||||||
|
void* dst, size_t dstCapacity,
|
||||||
|
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
||||||
|
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
||||||
|
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
||||||
|
seqDef const* sequences, size_t nbSeq, int longOffsets)
|
||||||
|
{
|
||||||
|
return ZSTD_encodeSequences_body(dst, dstCapacity,
|
||||||
|
CTable_MatchLength, mlCodeTable,
|
||||||
|
CTable_OffsetBits, ofCodeTable,
|
||||||
|
CTable_LitLength, llCodeTable,
|
||||||
|
sequences, nbSeq, longOffsets);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if DYNAMIC_BMI2
|
||||||
|
|
||||||
|
static TARGET_ATTRIBUTE("bmi2") size_t
|
||||||
|
ZSTD_encodeSequences_bmi2(
|
||||||
|
void* dst, size_t dstCapacity,
|
||||||
|
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
||||||
|
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
||||||
|
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
||||||
|
seqDef const* sequences, size_t nbSeq, int longOffsets)
|
||||||
|
{
|
||||||
|
return ZSTD_encodeSequences_body(dst, dstCapacity,
|
||||||
|
CTable_MatchLength, mlCodeTable,
|
||||||
|
CTable_OffsetBits, ofCodeTable,
|
||||||
|
CTable_LitLength, llCodeTable,
|
||||||
|
sequences, nbSeq, longOffsets);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t ZSTD_encodeSequences(
|
||||||
|
void* dst, size_t dstCapacity,
|
||||||
|
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
||||||
|
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
||||||
|
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
||||||
|
seqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2)
|
||||||
|
{
|
||||||
|
DEBUGLOG(5, "ZSTD_encodeSequences: dstCapacity = %u", (unsigned)dstCapacity);
|
||||||
|
#if DYNAMIC_BMI2
|
||||||
|
if (bmi2) {
|
||||||
|
return ZSTD_encodeSequences_bmi2(dst, dstCapacity,
|
||||||
|
CTable_MatchLength, mlCodeTable,
|
||||||
|
CTable_OffsetBits, ofCodeTable,
|
||||||
|
CTable_LitLength, llCodeTable,
|
||||||
|
sequences, nbSeq, longOffsets);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
(void)bmi2;
|
||||||
|
return ZSTD_encodeSequences_default(dst, dstCapacity,
|
||||||
|
CTable_MatchLength, mlCodeTable,
|
||||||
|
CTable_OffsetBits, ofCodeTable,
|
||||||
|
CTable_LitLength, llCodeTable,
|
||||||
|
sequences, nbSeq, longOffsets);
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under both the BSD-style license (found in the
|
||||||
|
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||||
|
* in the COPYING file in the root directory of this source tree).
|
||||||
|
* You may select, at your option, one of the above-listed licenses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZSTD_COMPRESS_SEQUENCES_H
|
||||||
|
#define ZSTD_COMPRESS_SEQUENCES_H
|
||||||
|
|
||||||
|
#include "fse.h" /* FSE_repeat, FSE_CTable */
|
||||||
|
#include "zstd_internal.h" /* symbolEncodingType_e, ZSTD_strategy */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ZSTD_defaultDisallowed = 0,
|
||||||
|
ZSTD_defaultAllowed = 1
|
||||||
|
} ZSTD_defaultPolicy_e;
|
||||||
|
|
||||||
|
symbolEncodingType_e
|
||||||
|
ZSTD_selectEncodingType(
|
||||||
|
FSE_repeat* repeatMode, unsigned const* count, unsigned const max,
|
||||||
|
size_t const mostFrequent, size_t nbSeq, unsigned const FSELog,
|
||||||
|
FSE_CTable const* prevCTable,
|
||||||
|
short const* defaultNorm, U32 defaultNormLog,
|
||||||
|
ZSTD_defaultPolicy_e const isDefaultAllowed,
|
||||||
|
ZSTD_strategy const strategy);
|
||||||
|
|
||||||
|
size_t
|
||||||
|
ZSTD_buildCTable(void* dst, size_t dstCapacity,
|
||||||
|
FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type,
|
||||||
|
unsigned* count, U32 max,
|
||||||
|
const BYTE* codeTable, size_t nbSeq,
|
||||||
|
const S16* defaultNorm, U32 defaultNormLog, U32 defaultMax,
|
||||||
|
const FSE_CTable* prevCTable, size_t prevCTableSize,
|
||||||
|
void* workspace, size_t workspaceSize);
|
||||||
|
|
||||||
|
size_t ZSTD_encodeSequences(
|
||||||
|
void* dst, size_t dstCapacity,
|
||||||
|
FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
|
||||||
|
FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
|
||||||
|
FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
|
||||||
|
seqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2);
|
||||||
|
|
||||||
|
#endif /* ZSTD_COMPRESS_SEQUENCES_H */
|
|
@ -65,6 +65,7 @@ size_t ZSTD_compressBlock_doubleFast_generic(
|
||||||
const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
|
const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
|
||||||
const U32 lowestValid = ms->window.dictLimit;
|
const U32 lowestValid = ms->window.dictLimit;
|
||||||
const U32 maxDistance = 1U << cParams->windowLog;
|
const U32 maxDistance = 1U << cParams->windowLog;
|
||||||
|
/* presumes that, if there is a dictionary, it must be using Attach mode */
|
||||||
const U32 prefixLowestIndex = (endIndex - lowestValid > maxDistance) ? endIndex - maxDistance : lowestValid;
|
const U32 prefixLowestIndex = (endIndex - lowestValid > maxDistance) ? endIndex - maxDistance : lowestValid;
|
||||||
const BYTE* const prefixLowest = base + prefixLowestIndex;
|
const BYTE* const prefixLowest = base + prefixLowestIndex;
|
||||||
const BYTE* const iend = istart + srcSize;
|
const BYTE* const iend = istart + srcSize;
|
||||||
|
@ -369,9 +370,7 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
|
||||||
const BYTE* const ilimit = iend - 8;
|
const BYTE* const ilimit = iend - 8;
|
||||||
const BYTE* const base = ms->window.base;
|
const BYTE* const base = ms->window.base;
|
||||||
const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
|
const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
|
||||||
const U32 maxDistance = 1U << cParams->windowLog;
|
const U32 lowLimit = ZSTD_getLowestMatchIndex(ms, endIndex, cParams->windowLog);
|
||||||
const U32 lowestValid = ms->window.lowLimit;
|
|
||||||
const U32 lowLimit = (endIndex - lowestValid > maxDistance) ? endIndex - maxDistance : lowestValid;
|
|
||||||
const U32 dictStartIndex = lowLimit;
|
const U32 dictStartIndex = lowLimit;
|
||||||
const U32 dictLimit = ms->window.dictLimit;
|
const U32 dictLimit = ms->window.dictLimit;
|
||||||
const U32 prefixStartIndex = (dictLimit > lowLimit) ? dictLimit : lowLimit;
|
const U32 prefixStartIndex = (dictLimit > lowLimit) ? dictLimit : lowLimit;
|
||||||
|
|
|
@ -71,6 +71,7 @@ size_t ZSTD_compressBlock_fast_generic(
|
||||||
U32 offsetSaved = 0;
|
U32 offsetSaved = 0;
|
||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
|
DEBUGLOG(5, "ZSTD_compressBlock_fast_generic");
|
||||||
ip0 += (ip0 == prefixStart);
|
ip0 += (ip0 == prefixStart);
|
||||||
ip1 = ip0 + 1;
|
ip1 = ip0 + 1;
|
||||||
{
|
{
|
||||||
|
@ -239,6 +240,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic(
|
||||||
assert(prefixStartIndex >= (U32)(dictEnd - dictBase));
|
assert(prefixStartIndex >= (U32)(dictEnd - dictBase));
|
||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
|
DEBUGLOG(5, "ZSTD_compressBlock_fast_dictMatchState_generic");
|
||||||
ip += (dictAndPrefixLength == 0);
|
ip += (dictAndPrefixLength == 0);
|
||||||
/* dictMatchState repCode checks don't currently handle repCode == 0
|
/* dictMatchState repCode checks don't currently handle repCode == 0
|
||||||
* disabling. */
|
* disabling. */
|
||||||
|
@ -379,9 +381,7 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(
|
||||||
const BYTE* ip = istart;
|
const BYTE* ip = istart;
|
||||||
const BYTE* anchor = istart;
|
const BYTE* anchor = istart;
|
||||||
const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
|
const U32 endIndex = (U32)((size_t)(istart - base) + srcSize);
|
||||||
const U32 maxDistance = 1U << cParams->windowLog;
|
const U32 lowLimit = ZSTD_getLowestMatchIndex(ms, endIndex, cParams->windowLog);
|
||||||
const U32 validLow = ms->window.lowLimit;
|
|
||||||
const U32 lowLimit = (endIndex - validLow > maxDistance) ? endIndex - maxDistance : validLow;
|
|
||||||
const U32 dictStartIndex = lowLimit;
|
const U32 dictStartIndex = lowLimit;
|
||||||
const BYTE* const dictStart = dictBase + dictStartIndex;
|
const BYTE* const dictStart = dictBase + dictStartIndex;
|
||||||
const U32 dictLimit = ms->window.dictLimit;
|
const U32 dictLimit = ms->window.dictLimit;
|
||||||
|
@ -392,6 +392,8 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(
|
||||||
const BYTE* const ilimit = iend - 8;
|
const BYTE* const ilimit = iend - 8;
|
||||||
U32 offset_1=rep[0], offset_2=rep[1];
|
U32 offset_1=rep[0], offset_2=rep[1];
|
||||||
|
|
||||||
|
DEBUGLOG(5, "ZSTD_compressBlock_fast_extDict_generic");
|
||||||
|
|
||||||
/* switch to "regular" variant if extDict is invalidated due to maxDistance */
|
/* switch to "regular" variant if extDict is invalidated due to maxDistance */
|
||||||
if (prefixStartIndex == dictStartIndex)
|
if (prefixStartIndex == dictStartIndex)
|
||||||
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, mls);
|
return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, mls);
|
||||||
|
@ -412,8 +414,8 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(
|
||||||
|
|
||||||
if ( (((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > dictStartIndex))
|
if ( (((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > dictStartIndex))
|
||||||
&& (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
|
&& (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
|
||||||
const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
|
const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
|
||||||
mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
|
mLength = ZSTD_count_2segments(ip+1 +4, repMatch +4, iend, repMatchEnd, prefixStart) + 4;
|
||||||
ip++;
|
ip++;
|
||||||
ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, 0, mLength-MINMATCH);
|
ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, 0, mLength-MINMATCH);
|
||||||
} else {
|
} else {
|
||||||
|
@ -423,8 +425,8 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(
|
||||||
ip += ((ip-anchor) >> kSearchStrength) + stepSize;
|
ip += ((ip-anchor) >> kSearchStrength) + stepSize;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
{ const BYTE* matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
|
{ const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
|
||||||
const BYTE* lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
|
const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
|
||||||
U32 offset;
|
U32 offset;
|
||||||
mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
|
mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
|
||||||
while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
|
||||||
|
@ -451,7 +453,7 @@ static size_t ZSTD_compressBlock_fast_extDict_generic(
|
||||||
&& (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
|
&& (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
|
||||||
const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
|
const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
|
||||||
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
|
size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
|
||||||
U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
|
U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
|
||||||
ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
|
ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
|
||||||
hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2;
|
hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2;
|
||||||
ip += repLength2;
|
ip += repLength2;
|
||||||
|
|
|
@ -242,9 +242,7 @@ ZSTD_DUBT_findBestMatch(ZSTD_matchState_t* ms,
|
||||||
|
|
||||||
const BYTE* const base = ms->window.base;
|
const BYTE* const base = ms->window.base;
|
||||||
U32 const current = (U32)(ip-base);
|
U32 const current = (U32)(ip-base);
|
||||||
U32 const maxDistance = 1U << cParams->windowLog;
|
U32 const windowLow = ZSTD_getLowestMatchIndex(ms, current, cParams->windowLog);
|
||||||
U32 const windowValid = ms->window.lowLimit;
|
|
||||||
U32 const windowLow = (current - windowValid > maxDistance) ? current - maxDistance : windowValid;
|
|
||||||
|
|
||||||
U32* const bt = ms->chainTable;
|
U32* const bt = ms->chainTable;
|
||||||
U32 const btLog = cParams->chainLog - 1;
|
U32 const btLog = cParams->chainLog - 1;
|
||||||
|
@ -497,8 +495,10 @@ size_t ZSTD_HcFindBestMatch_generic (
|
||||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||||
const U32 current = (U32)(ip-base);
|
const U32 current = (U32)(ip-base);
|
||||||
const U32 maxDistance = 1U << cParams->windowLog;
|
const U32 maxDistance = 1U << cParams->windowLog;
|
||||||
const U32 lowValid = ms->window.lowLimit;
|
const U32 lowestValid = ms->window.lowLimit;
|
||||||
const U32 lowLimit = (current - lowValid > maxDistance) ? current - maxDistance : lowValid;
|
const U32 withinMaxDistance = (current - lowestValid > maxDistance) ? current - maxDistance : lowestValid;
|
||||||
|
const U32 isDictionary = (ms->loadedDictEnd != 0);
|
||||||
|
const U32 lowLimit = isDictionary ? lowestValid : withinMaxDistance;
|
||||||
const U32 minChain = current > chainSize ? current - chainSize : 0;
|
const U32 minChain = current > chainSize ? current - chainSize : 0;
|
||||||
U32 nbAttempts = 1U << cParams->searchLog;
|
U32 nbAttempts = 1U << cParams->searchLog;
|
||||||
size_t ml=4-1;
|
size_t ml=4-1;
|
||||||
|
@ -619,12 +619,14 @@ FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
|
||||||
/* *******************************
|
/* *******************************
|
||||||
* Common parser - lazy strategy
|
* Common parser - lazy strategy
|
||||||
*********************************/
|
*********************************/
|
||||||
FORCE_INLINE_TEMPLATE
|
typedef enum { search_hashChain, search_binaryTree } searchMethod_e;
|
||||||
size_t ZSTD_compressBlock_lazy_generic(
|
|
||||||
|
FORCE_INLINE_TEMPLATE size_t
|
||||||
|
ZSTD_compressBlock_lazy_generic(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore,
|
ZSTD_matchState_t* ms, seqStore_t* seqStore,
|
||||||
U32 rep[ZSTD_REP_NUM],
|
U32 rep[ZSTD_REP_NUM],
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
const U32 searchMethod, const U32 depth,
|
const searchMethod_e searchMethod, const U32 depth,
|
||||||
ZSTD_dictMode_e const dictMode)
|
ZSTD_dictMode_e const dictMode)
|
||||||
{
|
{
|
||||||
const BYTE* const istart = (const BYTE*)src;
|
const BYTE* const istart = (const BYTE*)src;
|
||||||
|
@ -640,8 +642,10 @@ size_t ZSTD_compressBlock_lazy_generic(
|
||||||
ZSTD_matchState_t* ms,
|
ZSTD_matchState_t* ms,
|
||||||
const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
|
const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
|
||||||
searchMax_f const searchMax = dictMode == ZSTD_dictMatchState ?
|
searchMax_f const searchMax = dictMode == ZSTD_dictMatchState ?
|
||||||
(searchMethod ? ZSTD_BtFindBestMatch_dictMatchState_selectMLS : ZSTD_HcFindBestMatch_dictMatchState_selectMLS) :
|
(searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_dictMatchState_selectMLS
|
||||||
(searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS);
|
: ZSTD_HcFindBestMatch_dictMatchState_selectMLS) :
|
||||||
|
(searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_selectMLS
|
||||||
|
: ZSTD_HcFindBestMatch_selectMLS);
|
||||||
U32 offset_1 = rep[0], offset_2 = rep[1], savedOffset=0;
|
U32 offset_1 = rep[0], offset_2 = rep[1], savedOffset=0;
|
||||||
|
|
||||||
const ZSTD_matchState_t* const dms = ms->dictMatchState;
|
const ZSTD_matchState_t* const dms = ms->dictMatchState;
|
||||||
|
@ -850,7 +854,7 @@ _storeSequence:
|
||||||
rep[1] = offset_2 ? offset_2 : savedOffset;
|
rep[1] = offset_2 ? offset_2 : savedOffset;
|
||||||
|
|
||||||
/* Return the last literals size */
|
/* Return the last literals size */
|
||||||
return iend - anchor;
|
return (size_t)(iend - anchor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -858,56 +862,56 @@ size_t ZSTD_compressBlock_btlazy2(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize)
|
void const* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 1, 2, ZSTD_noDict);
|
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2, ZSTD_noDict);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_lazy2(
|
size_t ZSTD_compressBlock_lazy2(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize)
|
void const* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 2, ZSTD_noDict);
|
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_noDict);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_lazy(
|
size_t ZSTD_compressBlock_lazy(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize)
|
void const* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 1, ZSTD_noDict);
|
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_noDict);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_greedy(
|
size_t ZSTD_compressBlock_greedy(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize)
|
void const* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 0, ZSTD_noDict);
|
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_noDict);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_btlazy2_dictMatchState(
|
size_t ZSTD_compressBlock_btlazy2_dictMatchState(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize)
|
void const* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 1, 2, ZSTD_dictMatchState);
|
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2, ZSTD_dictMatchState);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_lazy2_dictMatchState(
|
size_t ZSTD_compressBlock_lazy2_dictMatchState(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize)
|
void const* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 2, ZSTD_dictMatchState);
|
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2, ZSTD_dictMatchState);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_lazy_dictMatchState(
|
size_t ZSTD_compressBlock_lazy_dictMatchState(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize)
|
void const* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 1, ZSTD_dictMatchState);
|
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1, ZSTD_dictMatchState);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_greedy_dictMatchState(
|
size_t ZSTD_compressBlock_greedy_dictMatchState(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize)
|
void const* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, 0, 0, ZSTD_dictMatchState);
|
return ZSTD_compressBlock_lazy_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0, ZSTD_dictMatchState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -916,7 +920,7 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore,
|
ZSTD_matchState_t* ms, seqStore_t* seqStore,
|
||||||
U32 rep[ZSTD_REP_NUM],
|
U32 rep[ZSTD_REP_NUM],
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
const U32 searchMethod, const U32 depth)
|
const searchMethod_e searchMethod, const U32 depth)
|
||||||
{
|
{
|
||||||
const BYTE* const istart = (const BYTE*)src;
|
const BYTE* const istart = (const BYTE*)src;
|
||||||
const BYTE* ip = istart;
|
const BYTE* ip = istart;
|
||||||
|
@ -934,7 +938,7 @@ size_t ZSTD_compressBlock_lazy_extDict_generic(
|
||||||
typedef size_t (*searchMax_f)(
|
typedef size_t (*searchMax_f)(
|
||||||
ZSTD_matchState_t* ms,
|
ZSTD_matchState_t* ms,
|
||||||
const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
|
const BYTE* ip, const BYTE* iLimit, size_t* offsetPtr);
|
||||||
searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_extDict_selectMLS : ZSTD_HcFindBestMatch_extDict_selectMLS;
|
searchMax_f searchMax = searchMethod==search_binaryTree ? ZSTD_BtFindBestMatch_extDict_selectMLS : ZSTD_HcFindBestMatch_extDict_selectMLS;
|
||||||
|
|
||||||
U32 offset_1 = rep[0], offset_2 = rep[1];
|
U32 offset_1 = rep[0], offset_2 = rep[1];
|
||||||
|
|
||||||
|
@ -1075,7 +1079,7 @@ _storeSequence:
|
||||||
rep[1] = offset_2;
|
rep[1] = offset_2;
|
||||||
|
|
||||||
/* Return the last literals size */
|
/* Return the last literals size */
|
||||||
return iend - anchor;
|
return (size_t)(iend - anchor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1083,7 +1087,7 @@ size_t ZSTD_compressBlock_greedy_extDict(
|
||||||
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
||||||
void const* src, size_t srcSize)
|
void const* src, size_t srcSize)
|
||||||
{
|
{
|
||||||
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, 0, 0);
|
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_lazy_extDict(
|
size_t ZSTD_compressBlock_lazy_extDict(
|
||||||
|
@ -1091,7 +1095,7 @@ size_t ZSTD_compressBlock_lazy_extDict(
|
||||||
void const* src, size_t srcSize)
|
void const* src, size_t srcSize)
|
||||||
|
|
||||||
{
|
{
|
||||||
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, 0, 1);
|
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_lazy2_extDict(
|
size_t ZSTD_compressBlock_lazy2_extDict(
|
||||||
|
@ -1099,7 +1103,7 @@ size_t ZSTD_compressBlock_lazy2_extDict(
|
||||||
void const* src, size_t srcSize)
|
void const* src, size_t srcSize)
|
||||||
|
|
||||||
{
|
{
|
||||||
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, 0, 2);
|
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_hashChain, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_compressBlock_btlazy2_extDict(
|
size_t ZSTD_compressBlock_btlazy2_extDict(
|
||||||
|
@ -1107,5 +1111,5 @@ size_t ZSTD_compressBlock_btlazy2_extDict(
|
||||||
void const* src, size_t srcSize)
|
void const* src, size_t srcSize)
|
||||||
|
|
||||||
{
|
{
|
||||||
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, 1, 2);
|
return ZSTD_compressBlock_lazy_extDict_generic(ms, seqStore, rep, src, srcSize, search_binaryTree, 2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -552,7 +552,6 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
||||||
{
|
{
|
||||||
const ZSTD_compressionParameters* const cParams = &ms->cParams;
|
const ZSTD_compressionParameters* const cParams = &ms->cParams;
|
||||||
U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
|
U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
|
||||||
U32 const maxDistance = 1U << cParams->windowLog;
|
|
||||||
const BYTE* const base = ms->window.base;
|
const BYTE* const base = ms->window.base;
|
||||||
U32 const current = (U32)(ip-base);
|
U32 const current = (U32)(ip-base);
|
||||||
U32 const hashLog = cParams->hashLog;
|
U32 const hashLog = cParams->hashLog;
|
||||||
|
@ -569,8 +568,7 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
||||||
const BYTE* const dictEnd = dictBase + dictLimit;
|
const BYTE* const dictEnd = dictBase + dictLimit;
|
||||||
const BYTE* const prefixStart = base + dictLimit;
|
const BYTE* const prefixStart = base + dictLimit;
|
||||||
U32 const btLow = (btMask >= current) ? 0 : current - btMask;
|
U32 const btLow = (btMask >= current) ? 0 : current - btMask;
|
||||||
U32 const windowValid = ms->window.lowLimit;
|
U32 const windowLow = ZSTD_getLowestMatchIndex(ms, current, cParams->windowLog);
|
||||||
U32 const windowLow = ((current - windowValid) > maxDistance) ? current - maxDistance : windowValid;
|
|
||||||
U32 const matchLow = windowLow ? windowLow : 1;
|
U32 const matchLow = windowLow ? windowLow : 1;
|
||||||
U32* smallerPtr = bt + 2*(current&btMask);
|
U32* smallerPtr = bt + 2*(current&btMask);
|
||||||
U32* largerPtr = bt + 2*(current&btMask) + 1;
|
U32* largerPtr = bt + 2*(current&btMask) + 1;
|
||||||
|
@ -674,19 +672,21 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
||||||
|
|
||||||
while (nbCompares-- && (matchIndex >= matchLow)) {
|
while (nbCompares-- && (matchIndex >= matchLow)) {
|
||||||
U32* const nextPtr = bt + 2*(matchIndex & btMask);
|
U32* const nextPtr = bt + 2*(matchIndex & btMask);
|
||||||
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
|
||||||
const BYTE* match;
|
const BYTE* match;
|
||||||
|
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
||||||
assert(current > matchIndex);
|
assert(current > matchIndex);
|
||||||
|
|
||||||
if ((dictMode == ZSTD_noDict) || (dictMode == ZSTD_dictMatchState) || (matchIndex+matchLength >= dictLimit)) {
|
if ((dictMode == ZSTD_noDict) || (dictMode == ZSTD_dictMatchState) || (matchIndex+matchLength >= dictLimit)) {
|
||||||
assert(matchIndex+matchLength >= dictLimit); /* ensure the condition is correct when !extDict */
|
assert(matchIndex+matchLength >= dictLimit); /* ensure the condition is correct when !extDict */
|
||||||
match = base + matchIndex;
|
match = base + matchIndex;
|
||||||
|
if (matchIndex >= dictLimit) assert(memcmp(match, ip, matchLength) == 0); /* ensure early section of match is equal as expected */
|
||||||
matchLength += ZSTD_count(ip+matchLength, match+matchLength, iLimit);
|
matchLength += ZSTD_count(ip+matchLength, match+matchLength, iLimit);
|
||||||
} else {
|
} else {
|
||||||
match = dictBase + matchIndex;
|
match = dictBase + matchIndex;
|
||||||
|
assert(memcmp(match, ip, matchLength) == 0); /* ensure early section of match is equal as expected */
|
||||||
matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart);
|
matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart);
|
||||||
if (matchIndex+matchLength >= dictLimit)
|
if (matchIndex+matchLength >= dictLimit)
|
||||||
match = base + matchIndex; /* prepare for match[matchLength] */
|
match = base + matchIndex; /* prepare for match[matchLength] read */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchLength > bestLength) {
|
if (matchLength > bestLength) {
|
||||||
|
|
|
@ -574,9 +574,10 @@ void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ZSTD_insertBlock() :
|
/** ZSTD_insertBlock() :
|
||||||
insert `src` block into `dctx` history. Useful to track uncompressed blocks. */
|
* insert `src` block into `dctx` history. Useful to track uncompressed blocks. */
|
||||||
size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize)
|
size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize)
|
||||||
{
|
{
|
||||||
|
DEBUGLOG(5, "ZSTD_insertBlock: %u bytes", (unsigned)blockSize);
|
||||||
ZSTD_checkContinuity(dctx, blockStart);
|
ZSTD_checkContinuity(dctx, blockStart);
|
||||||
dctx->previousDstEnd = (const char*)blockStart + blockSize;
|
dctx->previousDstEnd = (const char*)blockStart + blockSize;
|
||||||
return blockSize;
|
return blockSize;
|
||||||
|
@ -909,6 +910,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
|
||||||
{ blockProperties_t bp;
|
{ blockProperties_t bp;
|
||||||
size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp);
|
size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp);
|
||||||
if (ZSTD_isError(cBlockSize)) return cBlockSize;
|
if (ZSTD_isError(cBlockSize)) return cBlockSize;
|
||||||
|
RETURN_ERROR_IF(cBlockSize > dctx->fParams.blockSizeMax, corruption_detected, "Block Size Exceeds Maximum");
|
||||||
dctx->expected = cBlockSize;
|
dctx->expected = cBlockSize;
|
||||||
dctx->bType = bp.blockType;
|
dctx->bType = bp.blockType;
|
||||||
dctx->rleSize = bp.origSize;
|
dctx->rleSize = bp.origSize;
|
||||||
|
@ -953,6 +955,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
|
||||||
RETURN_ERROR(corruption_detected);
|
RETURN_ERROR(corruption_detected);
|
||||||
}
|
}
|
||||||
if (ZSTD_isError(rSize)) return rSize;
|
if (ZSTD_isError(rSize)) return rSize;
|
||||||
|
RETURN_ERROR_IF(rSize > dctx->fParams.blockSizeMax, corruption_detected, "Decompressed Block Size Exceeds Maximum");
|
||||||
DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize);
|
DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize);
|
||||||
dctx->decodedSize += rSize;
|
dctx->decodedSize += rSize;
|
||||||
if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize);
|
if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize);
|
||||||
|
|
|
@ -79,6 +79,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
|
||||||
size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
|
size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
|
||||||
const void* src, size_t srcSize) /* note : srcSize < BLOCKSIZE */
|
const void* src, size_t srcSize) /* note : srcSize < BLOCKSIZE */
|
||||||
{
|
{
|
||||||
|
DEBUGLOG(5, "ZSTD_decodeLiteralsBlock");
|
||||||
RETURN_ERROR_IF(srcSize < MIN_CBLOCK_SIZE, corruption_detected);
|
RETURN_ERROR_IF(srcSize < MIN_CBLOCK_SIZE, corruption_detected);
|
||||||
|
|
||||||
{ const BYTE* const istart = (const BYTE*) src;
|
{ const BYTE* const istart = (const BYTE*) src;
|
||||||
|
@ -87,6 +88,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
|
||||||
switch(litEncType)
|
switch(litEncType)
|
||||||
{
|
{
|
||||||
case set_repeat:
|
case set_repeat:
|
||||||
|
DEBUGLOG(5, "set_repeat flag : re-using stats from previous compressed literals block");
|
||||||
RETURN_ERROR_IF(dctx->litEntropy==0, dictionary_corrupted);
|
RETURN_ERROR_IF(dctx->litEntropy==0, dictionary_corrupted);
|
||||||
/* fall-through */
|
/* fall-through */
|
||||||
|
|
||||||
|
@ -116,7 +118,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx,
|
||||||
/* 2 - 2 - 18 - 18 */
|
/* 2 - 2 - 18 - 18 */
|
||||||
lhSize = 5;
|
lhSize = 5;
|
||||||
litSize = (lhc >> 4) & 0x3FFFF;
|
litSize = (lhc >> 4) & 0x3FFFF;
|
||||||
litCSize = (lhc >> 22) + (istart[4] << 10);
|
litCSize = (lhc >> 22) + ((size_t)istart[4] << 10);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected);
|
RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected);
|
||||||
|
@ -391,7 +393,8 @@ ZSTD_buildFSETable(ZSTD_seqSymbol* dt,
|
||||||
symbolNext[s] = 1;
|
symbolNext[s] = 1;
|
||||||
} else {
|
} else {
|
||||||
if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
|
if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
|
||||||
symbolNext[s] = normalizedCounter[s];
|
assert(normalizedCounter[s]>=0);
|
||||||
|
symbolNext[s] = (U16)normalizedCounter[s];
|
||||||
} } }
|
} } }
|
||||||
memcpy(dt, &DTableH, sizeof(DTableH));
|
memcpy(dt, &DTableH, sizeof(DTableH));
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ extern "C" {
|
||||||
/*------ Version ------*/
|
/*------ Version ------*/
|
||||||
#define ZSTD_VERSION_MAJOR 1
|
#define ZSTD_VERSION_MAJOR 1
|
||||||
#define ZSTD_VERSION_MINOR 4
|
#define ZSTD_VERSION_MINOR 4
|
||||||
#define ZSTD_VERSION_RELEASE 1
|
#define ZSTD_VERSION_RELEASE 3
|
||||||
|
|
||||||
#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE)
|
#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE)
|
||||||
ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< to check runtime library version */
|
ZSTDLIB_API unsigned ZSTD_versionNumber(void); /**< to check runtime library version */
|
||||||
|
@ -1909,7 +1909,7 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx);
|
||||||
/*!
|
/*!
|
||||||
Block functions produce and decode raw zstd blocks, without frame metadata.
|
Block functions produce and decode raw zstd blocks, without frame metadata.
|
||||||
Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes).
|
Frame metadata cost is typically ~18 bytes, which can be non-negligible for very small blocks (< 100 bytes).
|
||||||
User will have to take in charge required information to regenerate data, such as compressed and content sizes.
|
But users will have to take in charge needed metadata to regenerate data, such as compressed and content sizes.
|
||||||
|
|
||||||
A few rules to respect :
|
A few rules to respect :
|
||||||
- Compressing and decompressing require a context structure
|
- Compressing and decompressing require a context structure
|
||||||
|
@ -1920,12 +1920,14 @@ ZSTDLIB_API ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx);
|
||||||
+ copyCCtx() and copyDCtx() can be used too
|
+ copyCCtx() and copyDCtx() can be used too
|
||||||
- Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB
|
- Block size is limited, it must be <= ZSTD_getBlockSize() <= ZSTD_BLOCKSIZE_MAX == 128 KB
|
||||||
+ If input is larger than a block size, it's necessary to split input data into multiple blocks
|
+ If input is larger than a block size, it's necessary to split input data into multiple blocks
|
||||||
+ For inputs larger than a single block, really consider using regular ZSTD_compress() instead.
|
+ For inputs larger than a single block, consider using regular ZSTD_compress() instead.
|
||||||
Frame metadata is not that costly, and quickly becomes negligible as source size grows larger.
|
Frame metadata is not that costly, and quickly becomes negligible as source size grows larger than a block.
|
||||||
- When a block is considered not compressible enough, ZSTD_compressBlock() result will be zero.
|
- When a block is considered not compressible enough, ZSTD_compressBlock() result will be 0 (zero) !
|
||||||
In which case, nothing is produced into `dst` !
|
===> In which case, nothing is produced into `dst` !
|
||||||
+ User must test for such outcome and deal directly with uncompressed data
|
+ User __must__ test for such outcome and deal directly with uncompressed data
|
||||||
+ ZSTD_decompressBlock() doesn't accept uncompressed data as input !!!
|
+ A block cannot be declared incompressible if ZSTD_compressBlock() return value was != 0.
|
||||||
|
Doing so would mess up with statistics history, leading to potential data corruption.
|
||||||
|
+ ZSTD_decompressBlock() _doesn't accept uncompressed data as input_ !!
|
||||||
+ In case of multiple successive blocks, should some of them be uncompressed,
|
+ In case of multiple successive blocks, should some of them be uncompressed,
|
||||||
decoder must be informed of their existence in order to follow proper history.
|
decoder must be informed of their existence in order to follow proper history.
|
||||||
Use ZSTD_insertBlock() for such a case.
|
Use ZSTD_insertBlock() for such a case.
|
||||||
|
|
Loading…
Reference in New Issue