extzstd 0.2 → 0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/HISTORY.ja.md +13 -0
- data/README.md +17 -14
- data/contrib/zstd/{NEWS → CHANGELOG} +115 -2
- data/contrib/zstd/CODE_OF_CONDUCT.md +5 -0
- data/contrib/zstd/Makefile +99 -53
- data/contrib/zstd/README.md +59 -39
- data/contrib/zstd/TESTING.md +1 -1
- data/contrib/zstd/appveyor.yml +17 -6
- data/contrib/zstd/lib/BUCK +29 -2
- data/contrib/zstd/lib/Makefile +118 -21
- data/contrib/zstd/lib/README.md +84 -44
- data/contrib/zstd/lib/common/bitstream.h +17 -33
- data/contrib/zstd/lib/common/compiler.h +62 -8
- data/contrib/zstd/lib/common/cpu.h +215 -0
- data/contrib/zstd/lib/common/debug.c +44 -0
- data/contrib/zstd/lib/common/debug.h +134 -0
- data/contrib/zstd/lib/common/entropy_common.c +16 -1
- data/contrib/zstd/lib/common/error_private.c +7 -0
- data/contrib/zstd/lib/common/fse.h +48 -44
- data/contrib/zstd/lib/common/fse_decompress.c +3 -3
- data/contrib/zstd/lib/common/huf.h +169 -113
- data/contrib/zstd/lib/common/mem.h +20 -2
- data/contrib/zstd/lib/common/pool.c +135 -49
- data/contrib/zstd/lib/common/pool.h +40 -21
- data/contrib/zstd/lib/common/threading.c +2 -2
- data/contrib/zstd/lib/common/threading.h +12 -12
- data/contrib/zstd/lib/common/xxhash.c +3 -2
- data/contrib/zstd/lib/common/zstd_common.c +3 -6
- data/contrib/zstd/lib/common/zstd_errors.h +17 -7
- data/contrib/zstd/lib/common/zstd_internal.h +76 -48
- data/contrib/zstd/lib/compress/fse_compress.c +89 -209
- data/contrib/zstd/lib/compress/hist.c +203 -0
- data/contrib/zstd/lib/compress/hist.h +95 -0
- data/contrib/zstd/lib/compress/huf_compress.c +188 -80
- data/contrib/zstd/lib/compress/zstd_compress.c +2500 -1203
- data/contrib/zstd/lib/compress/zstd_compress_internal.h +463 -62
- data/contrib/zstd/lib/compress/zstd_double_fast.c +321 -131
- data/contrib/zstd/lib/compress/zstd_double_fast.h +13 -4
- data/contrib/zstd/lib/compress/zstd_fast.c +335 -108
- data/contrib/zstd/lib/compress/zstd_fast.h +12 -6
- data/contrib/zstd/lib/compress/zstd_lazy.c +654 -313
- data/contrib/zstd/lib/compress/zstd_lazy.h +44 -16
- data/contrib/zstd/lib/compress/zstd_ldm.c +310 -420
- data/contrib/zstd/lib/compress/zstd_ldm.h +63 -26
- data/contrib/zstd/lib/compress/zstd_opt.c +773 -325
- data/contrib/zstd/lib/compress/zstd_opt.h +31 -5
- data/contrib/zstd/lib/compress/zstdmt_compress.c +1468 -518
- data/contrib/zstd/lib/compress/zstdmt_compress.h +96 -45
- data/contrib/zstd/lib/decompress/huf_decompress.c +518 -282
- data/contrib/zstd/lib/decompress/zstd_ddict.c +240 -0
- data/contrib/zstd/lib/decompress/zstd_ddict.h +44 -0
- data/contrib/zstd/lib/decompress/zstd_decompress.c +613 -1513
- data/contrib/zstd/lib/decompress/zstd_decompress_block.c +1311 -0
- data/contrib/zstd/lib/decompress/zstd_decompress_block.h +59 -0
- data/contrib/zstd/lib/decompress/zstd_decompress_internal.h +175 -0
- data/contrib/zstd/lib/dictBuilder/cover.c +194 -113
- data/contrib/zstd/lib/dictBuilder/cover.h +112 -0
- data/contrib/zstd/lib/dictBuilder/divsufsort.c +3 -3
- data/contrib/zstd/lib/dictBuilder/fastcover.c +740 -0
- data/contrib/zstd/lib/dictBuilder/zdict.c +142 -106
- data/contrib/zstd/lib/dictBuilder/zdict.h +115 -49
- data/contrib/zstd/lib/legacy/zstd_legacy.h +44 -12
- data/contrib/zstd/lib/legacy/zstd_v01.c +41 -10
- data/contrib/zstd/lib/legacy/zstd_v01.h +12 -7
- data/contrib/zstd/lib/legacy/zstd_v02.c +37 -12
- data/contrib/zstd/lib/legacy/zstd_v02.h +12 -7
- data/contrib/zstd/lib/legacy/zstd_v03.c +38 -12
- data/contrib/zstd/lib/legacy/zstd_v03.h +12 -7
- data/contrib/zstd/lib/legacy/zstd_v04.c +55 -174
- data/contrib/zstd/lib/legacy/zstd_v04.h +12 -7
- data/contrib/zstd/lib/legacy/zstd_v05.c +59 -31
- data/contrib/zstd/lib/legacy/zstd_v05.h +12 -7
- data/contrib/zstd/lib/legacy/zstd_v06.c +48 -20
- data/contrib/zstd/lib/legacy/zstd_v06.h +10 -5
- data/contrib/zstd/lib/legacy/zstd_v07.c +62 -29
- data/contrib/zstd/lib/legacy/zstd_v07.h +10 -5
- data/contrib/zstd/lib/zstd.h +1346 -832
- data/ext/extzstd.c +27 -19
- data/ext/extzstd_stream.c +20 -4
- data/ext/zstd_compress.c +1 -0
- data/ext/zstd_decompress.c +4 -0
- data/ext/zstd_dictbuilder.c +4 -0
- data/ext/zstd_dictbuilder_fastcover.c +5 -0
- data/lib/extzstd.rb +52 -220
- data/lib/extzstd/version.rb +1 -1
- metadata +21 -7
- data/contrib/zstd/circle.yml +0 -63
|
@@ -21,45 +21,82 @@ extern "C" {
|
|
|
21
21
|
* Long distance matching
|
|
22
22
|
***************************************/
|
|
23
23
|
|
|
24
|
-
#define ZSTD_LDM_DEFAULT_WINDOW_LOG
|
|
25
|
-
#define ZSTD_LDM_HASHEVERYLOG_NOTSET 9999
|
|
24
|
+
#define ZSTD_LDM_DEFAULT_WINDOW_LOG ZSTD_WINDOWLOG_LIMIT_DEFAULT
|
|
26
25
|
|
|
27
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* ZSTD_ldm_generateSequences():
|
|
28
28
|
*
|
|
29
|
-
*
|
|
29
|
+
* Generates the sequences using the long distance match finder.
|
|
30
|
+
* Generates long range matching sequences in `sequences`, which parse a prefix
|
|
31
|
+
* of the source. `sequences` must be large enough to store every sequence,
|
|
32
|
+
* which can be checked with `ZSTD_ldm_getMaxNbSeq()`.
|
|
33
|
+
* @returns 0 or an error code.
|
|
30
34
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
35
|
+
* NOTE: The user must have called ZSTD_window_update() for all of the input
|
|
36
|
+
* they have, even if they pass it to ZSTD_ldm_generateSequences() in chunks.
|
|
37
|
+
* NOTE: This function returns an error if it runs out of space to store
|
|
38
|
+
* sequences.
|
|
39
|
+
*/
|
|
40
|
+
size_t ZSTD_ldm_generateSequences(
|
|
41
|
+
ldmState_t* ldms, rawSeqStore_t* sequences,
|
|
42
|
+
ldmParams_t const* params, void const* src, size_t srcSize);
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* ZSTD_ldm_blockCompress():
|
|
46
|
+
*
|
|
47
|
+
* Compresses a block using the predefined sequences, along with a secondary
|
|
48
|
+
* block compressor. The literals section of every sequence is passed to the
|
|
49
|
+
* secondary block compressor, and those sequences are interspersed with the
|
|
50
|
+
* predefined sequences. Returns the length of the last literals.
|
|
51
|
+
* Updates `rawSeqStore.pos` to indicate how many sequences have been consumed.
|
|
52
|
+
* `rawSeqStore.seq` may also be updated to split the last sequence between two
|
|
53
|
+
* blocks.
|
|
54
|
+
* @return The length of the last literals.
|
|
55
|
+
*
|
|
56
|
+
* NOTE: The source must be at most the maximum block size, but the predefined
|
|
57
|
+
* sequences can be any size, and may be longer than the block. In the case that
|
|
58
|
+
* they are longer than the block, the last sequences may need to be split into
|
|
59
|
+
* two. We handle that case correctly, and update `rawSeqStore` appropriately.
|
|
60
|
+
* NOTE: This function does not return any errors.
|
|
61
|
+
*/
|
|
62
|
+
size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
|
|
63
|
+
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
64
|
+
void const* src, size_t srcSize);
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* ZSTD_ldm_skipSequences():
|
|
34
68
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
|
|
39
|
-
*
|
|
40
|
-
|
|
41
|
-
size_t ZSTD_compressBlock_ldm_extDict(ZSTD_CCtx* ctx,
|
|
42
|
-
const void* src, size_t srcSize);
|
|
69
|
+
* Skip past `srcSize` bytes worth of sequences in `rawSeqStore`.
|
|
70
|
+
* Avoids emitting matches less than `minMatch` bytes.
|
|
71
|
+
* Must be called for data with is not passed to ZSTD_ldm_blockCompress().
|
|
72
|
+
*/
|
|
73
|
+
void ZSTD_ldm_skipSequences(rawSeqStore_t* rawSeqStore, size_t srcSize,
|
|
74
|
+
U32 const minMatch);
|
|
43
75
|
|
|
44
|
-
/** ZSTD_ldm_initializeParameters() :
|
|
45
|
-
* Initialize the long distance matching parameters to their default values. */
|
|
46
|
-
size_t ZSTD_ldm_initializeParameters(ldmParams_t* params, U32 enableLdm);
|
|
47
76
|
|
|
48
77
|
/** ZSTD_ldm_getTableSize() :
|
|
49
|
-
* Estimate the space needed for long distance matching tables
|
|
50
|
-
|
|
78
|
+
* Estimate the space needed for long distance matching tables or 0 if LDM is
|
|
79
|
+
* disabled.
|
|
80
|
+
*/
|
|
81
|
+
size_t ZSTD_ldm_getTableSize(ldmParams_t params);
|
|
51
82
|
|
|
52
|
-
/**
|
|
53
|
-
* Return
|
|
54
|
-
|
|
83
|
+
/** ZSTD_ldm_getSeqSpace() :
|
|
84
|
+
* Return an upper bound on the number of sequences that can be produced by
|
|
85
|
+
* the long distance matcher, or 0 if LDM is disabled.
|
|
86
|
+
*/
|
|
87
|
+
size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize);
|
|
55
88
|
|
|
56
89
|
/** ZSTD_ldm_adjustParameters() :
|
|
57
|
-
* If the params->
|
|
90
|
+
* If the params->hashRateLog is not set, set it to its default value based on
|
|
58
91
|
* windowLog and params->hashLog.
|
|
59
92
|
*
|
|
60
93
|
* Ensures that params->bucketSizeLog is <= params->hashLog (setting it to
|
|
61
|
-
* params->hashLog if it is not).
|
|
62
|
-
|
|
94
|
+
* params->hashLog if it is not).
|
|
95
|
+
*
|
|
96
|
+
* Ensures that the minMatchLength >= targetLength during optimal parsing.
|
|
97
|
+
*/
|
|
98
|
+
void ZSTD_ldm_adjustParameters(ldmParams_t* params,
|
|
99
|
+
ZSTD_compressionParameters const* cParams);
|
|
63
100
|
|
|
64
101
|
#if defined (__cplusplus)
|
|
65
102
|
}
|
|
@@ -9,140 +9,259 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
#include "zstd_compress_internal.h"
|
|
12
|
+
#include "hist.h"
|
|
12
13
|
#include "zstd_opt.h"
|
|
13
|
-
#include "zstd_lazy.h" /* ZSTD_updateTree, ZSTD_updateTree_extDict */
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
#define ZSTD_LITFREQ_ADD 2 /* scaling factor for litFreq, so that frequencies adapt faster to new stats
|
|
16
|
+
#define ZSTD_LITFREQ_ADD 2 /* scaling factor for litFreq, so that frequencies adapt faster to new stats */
|
|
17
17
|
#define ZSTD_FREQ_DIV 4 /* log factor when using previous stats to init next stats */
|
|
18
18
|
#define ZSTD_MAX_PRICE (1<<30)
|
|
19
19
|
|
|
20
|
+
#define ZSTD_PREDEF_THRESHOLD 1024 /* if srcSize < ZSTD_PREDEF_THRESHOLD, symbols' cost is assumed static, directly determined by pre-defined distributions */
|
|
21
|
+
|
|
20
22
|
|
|
21
23
|
/*-*************************************
|
|
22
24
|
* Price functions for optimal parser
|
|
23
25
|
***************************************/
|
|
24
|
-
|
|
26
|
+
|
|
27
|
+
#if 0 /* approximation at bit level */
|
|
28
|
+
# define BITCOST_ACCURACY 0
|
|
29
|
+
# define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
|
|
30
|
+
# define WEIGHT(stat) ((void)opt, ZSTD_bitWeight(stat))
|
|
31
|
+
#elif 0 /* fractional bit accuracy */
|
|
32
|
+
# define BITCOST_ACCURACY 8
|
|
33
|
+
# define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
|
|
34
|
+
# define WEIGHT(stat,opt) ((void)opt, ZSTD_fracWeight(stat))
|
|
35
|
+
#else /* opt==approx, ultra==accurate */
|
|
36
|
+
# define BITCOST_ACCURACY 8
|
|
37
|
+
# define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
|
|
38
|
+
# define WEIGHT(stat,opt) (opt ? ZSTD_fracWeight(stat) : ZSTD_bitWeight(stat))
|
|
39
|
+
#endif
|
|
40
|
+
|
|
41
|
+
MEM_STATIC U32 ZSTD_bitWeight(U32 stat)
|
|
25
42
|
{
|
|
26
|
-
|
|
27
|
-
optPtr->log2litLengthSum = ZSTD_highbit32(optPtr->litLengthSum+1);
|
|
28
|
-
optPtr->log2matchLengthSum = ZSTD_highbit32(optPtr->matchLengthSum+1);
|
|
29
|
-
optPtr->log2offCodeSum = ZSTD_highbit32(optPtr->offCodeSum+1);
|
|
43
|
+
return (ZSTD_highbit32(stat+1) * BITCOST_MULTIPLIER);
|
|
30
44
|
}
|
|
31
45
|
|
|
46
|
+
MEM_STATIC U32 ZSTD_fracWeight(U32 rawStat)
|
|
47
|
+
{
|
|
48
|
+
U32 const stat = rawStat + 1;
|
|
49
|
+
U32 const hb = ZSTD_highbit32(stat);
|
|
50
|
+
U32 const BWeight = hb * BITCOST_MULTIPLIER;
|
|
51
|
+
U32 const FWeight = (stat << BITCOST_ACCURACY) >> hb;
|
|
52
|
+
U32 const weight = BWeight + FWeight;
|
|
53
|
+
assert(hb + BITCOST_ACCURACY < 31);
|
|
54
|
+
return weight;
|
|
55
|
+
}
|
|
32
56
|
|
|
33
|
-
|
|
34
|
-
|
|
57
|
+
#if (DEBUGLEVEL>=2)
|
|
58
|
+
/* debugging function,
|
|
59
|
+
* @return price in bytes as fractional value
|
|
60
|
+
* for debug messages only */
|
|
61
|
+
MEM_STATIC double ZSTD_fCost(U32 price)
|
|
35
62
|
{
|
|
36
|
-
|
|
63
|
+
return (double)price / (BITCOST_MULTIPLIER*8);
|
|
64
|
+
}
|
|
65
|
+
#endif
|
|
37
66
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
67
|
+
static int ZSTD_compressedLiterals(optState_t const* const optPtr)
|
|
68
|
+
{
|
|
69
|
+
return optPtr->literalCompressionMode != ZSTD_lcm_uncompressed;
|
|
70
|
+
}
|
|
41
71
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
optPtr->litSum += optPtr->litFreq[u];
|
|
51
|
-
}
|
|
72
|
+
static void ZSTD_setBasePrices(optState_t* optPtr, int optLevel)
|
|
73
|
+
{
|
|
74
|
+
if (ZSTD_compressedLiterals(optPtr))
|
|
75
|
+
optPtr->litSumBasePrice = WEIGHT(optPtr->litSum, optLevel);
|
|
76
|
+
optPtr->litLengthSumBasePrice = WEIGHT(optPtr->litLengthSum, optLevel);
|
|
77
|
+
optPtr->matchLengthSumBasePrice = WEIGHT(optPtr->matchLengthSum, optLevel);
|
|
78
|
+
optPtr->offCodeSumBasePrice = WEIGHT(optPtr->offCodeSum, optLevel);
|
|
79
|
+
}
|
|
52
80
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
|
|
82
|
+
/* ZSTD_downscaleStat() :
|
|
83
|
+
* reduce all elements in table by a factor 2^(ZSTD_FREQ_DIV+malus)
|
|
84
|
+
* return the resulting sum of elements */
|
|
85
|
+
static U32 ZSTD_downscaleStat(unsigned* table, U32 lastEltIndex, int malus)
|
|
86
|
+
{
|
|
87
|
+
U32 s, sum=0;
|
|
88
|
+
DEBUGLOG(5, "ZSTD_downscaleStat (nbElts=%u)", (unsigned)lastEltIndex+1);
|
|
89
|
+
assert(ZSTD_FREQ_DIV+malus > 0 && ZSTD_FREQ_DIV+malus < 31);
|
|
90
|
+
for (s=0; s<lastEltIndex+1; s++) {
|
|
91
|
+
table[s] = 1 + (table[s] >> (ZSTD_FREQ_DIV+malus));
|
|
92
|
+
sum += table[s];
|
|
93
|
+
}
|
|
94
|
+
return sum;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* ZSTD_rescaleFreqs() :
|
|
98
|
+
* if first block (detected by optPtr->litLengthSum == 0) : init statistics
|
|
99
|
+
* take hints from dictionary if there is one
|
|
100
|
+
* or init from zero, using src for literals stats, or flat 1 for match symbols
|
|
101
|
+
* otherwise downscale existing stats, to be used as seed for next block.
|
|
102
|
+
*/
|
|
103
|
+
static void
|
|
104
|
+
ZSTD_rescaleFreqs(optState_t* const optPtr,
|
|
105
|
+
const BYTE* const src, size_t const srcSize,
|
|
106
|
+
int const optLevel)
|
|
107
|
+
{
|
|
108
|
+
int const compressedLiterals = ZSTD_compressedLiterals(optPtr);
|
|
109
|
+
DEBUGLOG(5, "ZSTD_rescaleFreqs (srcSize=%u)", (unsigned)srcSize);
|
|
110
|
+
optPtr->priceType = zop_dynamic;
|
|
111
|
+
|
|
112
|
+
if (optPtr->litLengthSum == 0) { /* first block : init */
|
|
113
|
+
if (srcSize <= ZSTD_PREDEF_THRESHOLD) { /* heuristic */
|
|
114
|
+
DEBUGLOG(5, "(srcSize <= ZSTD_PREDEF_THRESHOLD) => zop_predef");
|
|
115
|
+
optPtr->priceType = zop_predef;
|
|
80
116
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
117
|
+
|
|
118
|
+
assert(optPtr->symbolCosts != NULL);
|
|
119
|
+
if (optPtr->symbolCosts->huf.repeatMode == HUF_repeat_valid) {
|
|
120
|
+
/* huffman table presumed generated by dictionary */
|
|
121
|
+
optPtr->priceType = zop_dynamic;
|
|
122
|
+
|
|
123
|
+
if (compressedLiterals) {
|
|
124
|
+
unsigned lit;
|
|
125
|
+
assert(optPtr->litFreq != NULL);
|
|
126
|
+
optPtr->litSum = 0;
|
|
127
|
+
for (lit=0; lit<=MaxLit; lit++) {
|
|
128
|
+
U32 const scaleLog = 11; /* scale to 2K */
|
|
129
|
+
U32 const bitCost = HUF_getNbBits(optPtr->symbolCosts->huf.CTable, lit);
|
|
130
|
+
assert(bitCost <= scaleLog);
|
|
131
|
+
optPtr->litFreq[lit] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
|
|
132
|
+
optPtr->litSum += optPtr->litFreq[lit];
|
|
133
|
+
} }
|
|
134
|
+
|
|
135
|
+
{ unsigned ll;
|
|
136
|
+
FSE_CState_t llstate;
|
|
137
|
+
FSE_initCState(&llstate, optPtr->symbolCosts->fse.litlengthCTable);
|
|
138
|
+
optPtr->litLengthSum = 0;
|
|
139
|
+
for (ll=0; ll<=MaxLL; ll++) {
|
|
140
|
+
U32 const scaleLog = 10; /* scale to 1K */
|
|
141
|
+
U32 const bitCost = FSE_getMaxNbBits(llstate.symbolTT, ll);
|
|
142
|
+
assert(bitCost < scaleLog);
|
|
143
|
+
optPtr->litLengthFreq[ll] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
|
|
144
|
+
optPtr->litLengthSum += optPtr->litLengthFreq[ll];
|
|
145
|
+
} }
|
|
146
|
+
|
|
147
|
+
{ unsigned ml;
|
|
148
|
+
FSE_CState_t mlstate;
|
|
149
|
+
FSE_initCState(&mlstate, optPtr->symbolCosts->fse.matchlengthCTable);
|
|
150
|
+
optPtr->matchLengthSum = 0;
|
|
151
|
+
for (ml=0; ml<=MaxML; ml++) {
|
|
152
|
+
U32 const scaleLog = 10;
|
|
153
|
+
U32 const bitCost = FSE_getMaxNbBits(mlstate.symbolTT, ml);
|
|
154
|
+
assert(bitCost < scaleLog);
|
|
155
|
+
optPtr->matchLengthFreq[ml] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
|
|
156
|
+
optPtr->matchLengthSum += optPtr->matchLengthFreq[ml];
|
|
157
|
+
} }
|
|
158
|
+
|
|
159
|
+
{ unsigned of;
|
|
160
|
+
FSE_CState_t ofstate;
|
|
161
|
+
FSE_initCState(&ofstate, optPtr->symbolCosts->fse.offcodeCTable);
|
|
162
|
+
optPtr->offCodeSum = 0;
|
|
163
|
+
for (of=0; of<=MaxOff; of++) {
|
|
164
|
+
U32 const scaleLog = 10;
|
|
165
|
+
U32 const bitCost = FSE_getMaxNbBits(ofstate.symbolTT, of);
|
|
166
|
+
assert(bitCost < scaleLog);
|
|
167
|
+
optPtr->offCodeFreq[of] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
|
|
168
|
+
optPtr->offCodeSum += optPtr->offCodeFreq[of];
|
|
169
|
+
} }
|
|
170
|
+
|
|
171
|
+
} else { /* not a dictionary */
|
|
172
|
+
|
|
173
|
+
assert(optPtr->litFreq != NULL);
|
|
174
|
+
if (compressedLiterals) {
|
|
175
|
+
unsigned lit = MaxLit;
|
|
176
|
+
HIST_count_simple(optPtr->litFreq, &lit, src, srcSize); /* use raw first block to init statistics */
|
|
177
|
+
optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
{ unsigned ll;
|
|
181
|
+
for (ll=0; ll<=MaxLL; ll++)
|
|
182
|
+
optPtr->litLengthFreq[ll] = 1;
|
|
183
|
+
}
|
|
184
|
+
optPtr->litLengthSum = MaxLL+1;
|
|
185
|
+
|
|
186
|
+
{ unsigned ml;
|
|
187
|
+
for (ml=0; ml<=MaxML; ml++)
|
|
188
|
+
optPtr->matchLengthFreq[ml] = 1;
|
|
189
|
+
}
|
|
190
|
+
optPtr->matchLengthSum = MaxML+1;
|
|
191
|
+
|
|
192
|
+
{ unsigned of;
|
|
193
|
+
for (of=0; of<=MaxOff; of++)
|
|
194
|
+
optPtr->offCodeFreq[of] = 1;
|
|
195
|
+
}
|
|
196
|
+
optPtr->offCodeSum = MaxOff+1;
|
|
197
|
+
|
|
85
198
|
}
|
|
199
|
+
|
|
200
|
+
} else { /* new block : re-use previous statistics, scaled down */
|
|
201
|
+
|
|
202
|
+
if (compressedLiterals)
|
|
203
|
+
optPtr->litSum = ZSTD_downscaleStat(optPtr->litFreq, MaxLit, 1);
|
|
204
|
+
optPtr->litLengthSum = ZSTD_downscaleStat(optPtr->litLengthFreq, MaxLL, 0);
|
|
205
|
+
optPtr->matchLengthSum = ZSTD_downscaleStat(optPtr->matchLengthFreq, MaxML, 0);
|
|
206
|
+
optPtr->offCodeSum = ZSTD_downscaleStat(optPtr->offCodeFreq, MaxOff, 0);
|
|
86
207
|
}
|
|
87
208
|
|
|
88
|
-
|
|
209
|
+
ZSTD_setBasePrices(optPtr, optLevel);
|
|
89
210
|
}
|
|
90
211
|
|
|
91
|
-
|
|
92
212
|
/* ZSTD_rawLiteralsCost() :
|
|
93
|
-
*
|
|
94
|
-
* does not include
|
|
213
|
+
* price of literals (only) in specified segment (which length can be 0).
|
|
214
|
+
* does not include price of literalLength symbol */
|
|
95
215
|
static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength,
|
|
96
|
-
const optState_t* const optPtr
|
|
216
|
+
const optState_t* const optPtr,
|
|
217
|
+
int optLevel)
|
|
97
218
|
{
|
|
98
|
-
if (optPtr->staticPrices) return (litLength*6); /* 6 bit per literal - no statistic used */
|
|
99
219
|
if (litLength == 0) return 0;
|
|
100
220
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
221
|
+
if (!ZSTD_compressedLiterals(optPtr))
|
|
222
|
+
return (litLength << 3) * BITCOST_MULTIPLIER; /* Uncompressed - 8 bytes per literal. */
|
|
223
|
+
|
|
224
|
+
if (optPtr->priceType == zop_predef)
|
|
225
|
+
return (litLength*6) * BITCOST_MULTIPLIER; /* 6 bit per literal - no statistic used */
|
|
226
|
+
|
|
227
|
+
/* dynamic statistics */
|
|
228
|
+
{ U32 price = litLength * optPtr->litSumBasePrice;
|
|
229
|
+
U32 u;
|
|
230
|
+
for (u=0; u < litLength; u++) {
|
|
231
|
+
assert(WEIGHT(optPtr->litFreq[literals[u]], optLevel) <= optPtr->litSumBasePrice); /* literal cost should never be negative */
|
|
232
|
+
price -= WEIGHT(optPtr->litFreq[literals[u]], optLevel);
|
|
233
|
+
}
|
|
234
|
+
return price;
|
|
107
235
|
}
|
|
108
236
|
}
|
|
109
237
|
|
|
110
238
|
/* ZSTD_litLengthPrice() :
|
|
111
239
|
* cost of literalLength symbol */
|
|
112
|
-
static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optPtr)
|
|
240
|
+
static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optPtr, int optLevel)
|
|
113
241
|
{
|
|
114
|
-
if (optPtr->
|
|
242
|
+
if (optPtr->priceType == zop_predef) return WEIGHT(litLength, optLevel);
|
|
115
243
|
|
|
116
|
-
/*
|
|
244
|
+
/* dynamic statistics */
|
|
117
245
|
{ U32 const llCode = ZSTD_LLcode(litLength);
|
|
118
|
-
|
|
119
|
-
|
|
246
|
+
return (LL_bits[llCode] * BITCOST_MULTIPLIER)
|
|
247
|
+
+ optPtr->litLengthSumBasePrice
|
|
248
|
+
- WEIGHT(optPtr->litLengthFreq[llCode], optLevel);
|
|
120
249
|
}
|
|
121
250
|
}
|
|
122
251
|
|
|
123
|
-
/* ZSTD_litLengthPrice() :
|
|
124
|
-
* cost of the literal part of a sequence,
|
|
125
|
-
* including literals themselves, and literalLength symbol */
|
|
126
|
-
static U32 ZSTD_fullLiteralsCost(const BYTE* const literals, U32 const litLength,
|
|
127
|
-
const optState_t* const optPtr)
|
|
128
|
-
{
|
|
129
|
-
return ZSTD_rawLiteralsCost(literals, litLength, optPtr)
|
|
130
|
-
+ ZSTD_litLengthPrice(litLength, optPtr);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
252
|
/* ZSTD_litLengthContribution() :
|
|
134
253
|
* @return ( cost(litlength) - cost(0) )
|
|
135
254
|
* this value can then be added to rawLiteralsCost()
|
|
136
255
|
* to provide a cost which is directly comparable to a match ending at same position */
|
|
137
|
-
static int ZSTD_litLengthContribution(U32 const litLength, const optState_t* const optPtr)
|
|
256
|
+
static int ZSTD_litLengthContribution(U32 const litLength, const optState_t* const optPtr, int optLevel)
|
|
138
257
|
{
|
|
139
|
-
if (optPtr->
|
|
258
|
+
if (optPtr->priceType >= zop_predef) return WEIGHT(litLength, optLevel);
|
|
140
259
|
|
|
141
|
-
/*
|
|
260
|
+
/* dynamic statistics */
|
|
142
261
|
{ U32 const llCode = ZSTD_LLcode(litLength);
|
|
143
|
-
int const contribution = LL_bits[llCode]
|
|
144
|
-
|
|
145
|
-
|
|
262
|
+
int const contribution = (LL_bits[llCode] * BITCOST_MULTIPLIER)
|
|
263
|
+
+ WEIGHT(optPtr->litLengthFreq[0], optLevel) /* note: log2litLengthSum cancel out */
|
|
264
|
+
- WEIGHT(optPtr->litLengthFreq[llCode], optLevel);
|
|
146
265
|
#if 1
|
|
147
266
|
return contribution;
|
|
148
267
|
#else
|
|
@@ -156,10 +275,11 @@ static int ZSTD_litLengthContribution(U32 const litLength, const optState_t* con
|
|
|
156
275
|
* which can be compared to the ending cost of a match
|
|
157
276
|
* should a new match start at this position */
|
|
158
277
|
static int ZSTD_literalsContribution(const BYTE* const literals, U32 const litLength,
|
|
159
|
-
const optState_t* const optPtr
|
|
278
|
+
const optState_t* const optPtr,
|
|
279
|
+
int optLevel)
|
|
160
280
|
{
|
|
161
|
-
int const contribution = ZSTD_rawLiteralsCost(literals, litLength, optPtr)
|
|
162
|
-
+ ZSTD_litLengthContribution(litLength, optPtr);
|
|
281
|
+
int const contribution = ZSTD_rawLiteralsCost(literals, litLength, optPtr, optLevel)
|
|
282
|
+
+ ZSTD_litLengthContribution(litLength, optPtr, optLevel);
|
|
163
283
|
return contribution;
|
|
164
284
|
}
|
|
165
285
|
|
|
@@ -167,37 +287,45 @@ static int ZSTD_literalsContribution(const BYTE* const literals, U32 const litLe
|
|
|
167
287
|
* Provides the cost of the match part (offset + matchLength) of a sequence
|
|
168
288
|
* Must be combined with ZSTD_fullLiteralsCost() to get the full cost of a sequence.
|
|
169
289
|
* optLevel: when <2, favors small offset for decompression speed (improved cache efficiency) */
|
|
170
|
-
FORCE_INLINE_TEMPLATE U32
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
290
|
+
FORCE_INLINE_TEMPLATE U32
|
|
291
|
+
ZSTD_getMatchPrice(U32 const offset,
|
|
292
|
+
U32 const matchLength,
|
|
293
|
+
const optState_t* const optPtr,
|
|
294
|
+
int const optLevel)
|
|
174
295
|
{
|
|
175
296
|
U32 price;
|
|
176
297
|
U32 const offCode = ZSTD_highbit32(offset+1);
|
|
177
298
|
U32 const mlBase = matchLength - MINMATCH;
|
|
178
299
|
assert(matchLength >= MINMATCH);
|
|
179
300
|
|
|
180
|
-
if (optPtr->
|
|
181
|
-
return
|
|
301
|
+
if (optPtr->priceType == zop_predef) /* fixed scheme, do not use statistics */
|
|
302
|
+
return WEIGHT(mlBase, optLevel) + ((16 + offCode) * BITCOST_MULTIPLIER);
|
|
182
303
|
|
|
183
|
-
|
|
184
|
-
|
|
304
|
+
/* dynamic statistics */
|
|
305
|
+
price = (offCode * BITCOST_MULTIPLIER) + (optPtr->offCodeSumBasePrice - WEIGHT(optPtr->offCodeFreq[offCode], optLevel));
|
|
306
|
+
if ((optLevel<2) /*static*/ && offCode >= 20)
|
|
307
|
+
price += (offCode-19)*2 * BITCOST_MULTIPLIER; /* handicap for long distance offsets, favor decompression speed */
|
|
185
308
|
|
|
186
309
|
/* match Length */
|
|
187
310
|
{ U32 const mlCode = ZSTD_MLcode(mlBase);
|
|
188
|
-
price += ML_bits[mlCode] + optPtr->
|
|
311
|
+
price += (ML_bits[mlCode] * BITCOST_MULTIPLIER) + (optPtr->matchLengthSumBasePrice - WEIGHT(optPtr->matchLengthFreq[mlCode], optLevel));
|
|
189
312
|
}
|
|
190
313
|
|
|
314
|
+
price += BITCOST_MULTIPLIER / 5; /* heuristic : make matches a bit more costly to favor less sequences -> faster decompression speed */
|
|
315
|
+
|
|
191
316
|
DEBUGLOG(8, "ZSTD_getMatchPrice(ml:%u) = %u", matchLength, price);
|
|
192
317
|
return price;
|
|
193
318
|
}
|
|
194
319
|
|
|
320
|
+
/* ZSTD_updateStats() :
|
|
321
|
+
* assumption : literals + litLengtn <= iend */
|
|
195
322
|
static void ZSTD_updateStats(optState_t* const optPtr,
|
|
196
323
|
U32 litLength, const BYTE* literals,
|
|
197
324
|
U32 offsetCode, U32 matchLength)
|
|
198
325
|
{
|
|
199
326
|
/* literals */
|
|
200
|
-
{
|
|
327
|
+
if (ZSTD_compressedLiterals(optPtr)) {
|
|
328
|
+
U32 u;
|
|
201
329
|
for (u=0; u < litLength; u++)
|
|
202
330
|
optPtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD;
|
|
203
331
|
optPtr->litSum += litLength*ZSTD_LITFREQ_ADD;
|
|
@@ -244,14 +372,15 @@ MEM_STATIC U32 ZSTD_readMINMATCH(const void* memPtr, U32 length)
|
|
|
244
372
|
|
|
245
373
|
/* Update hashTable3 up to ip (excluded)
|
|
246
374
|
Assumption : always within prefix (i.e. not within extDict) */
|
|
247
|
-
static U32 ZSTD_insertAndFindFirstIndexHash3 (
|
|
375
|
+
static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_matchState_t* ms, const BYTE* const ip)
|
|
248
376
|
{
|
|
249
|
-
U32* const hashTable3
|
|
250
|
-
U32 const hashLog3
|
|
251
|
-
const BYTE* const base =
|
|
252
|
-
U32 idx =
|
|
253
|
-
U32 const target =
|
|
377
|
+
U32* const hashTable3 = ms->hashTable3;
|
|
378
|
+
U32 const hashLog3 = ms->hashLog3;
|
|
379
|
+
const BYTE* const base = ms->window.base;
|
|
380
|
+
U32 idx = ms->nextToUpdate3;
|
|
381
|
+
U32 const target = ms->nextToUpdate3 = (U32)(ip - base);
|
|
254
382
|
size_t const hash3 = ZSTD_hash3Ptr(ip, hashLog3);
|
|
383
|
+
assert(hashLog3 > 0);
|
|
255
384
|
|
|
256
385
|
while(idx < target) {
|
|
257
386
|
hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx;
|
|
@@ -265,41 +394,196 @@ static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_CCtx* const cctx, const BYTE*
|
|
|
265
394
|
/*-*************************************
|
|
266
395
|
* Binary Tree search
|
|
267
396
|
***************************************/
|
|
397
|
+
/** ZSTD_insertBt1() : add one or multiple positions to tree.
|
|
398
|
+
* ip : assumed <= iend-8 .
|
|
399
|
+
* @return : nb of positions added */
|
|
400
|
+
static U32 ZSTD_insertBt1(
|
|
401
|
+
ZSTD_matchState_t* ms,
|
|
402
|
+
const BYTE* const ip, const BYTE* const iend,
|
|
403
|
+
U32 const mls, const int extDict)
|
|
404
|
+
{
|
|
405
|
+
const ZSTD_compressionParameters* const cParams = &ms->cParams;
|
|
406
|
+
U32* const hashTable = ms->hashTable;
|
|
407
|
+
U32 const hashLog = cParams->hashLog;
|
|
408
|
+
size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
|
|
409
|
+
U32* const bt = ms->chainTable;
|
|
410
|
+
U32 const btLog = cParams->chainLog - 1;
|
|
411
|
+
U32 const btMask = (1 << btLog) - 1;
|
|
412
|
+
U32 matchIndex = hashTable[h];
|
|
413
|
+
size_t commonLengthSmaller=0, commonLengthLarger=0;
|
|
414
|
+
const BYTE* const base = ms->window.base;
|
|
415
|
+
const BYTE* const dictBase = ms->window.dictBase;
|
|
416
|
+
const U32 dictLimit = ms->window.dictLimit;
|
|
417
|
+
const BYTE* const dictEnd = dictBase + dictLimit;
|
|
418
|
+
const BYTE* const prefixStart = base + dictLimit;
|
|
419
|
+
const BYTE* match;
|
|
420
|
+
const U32 current = (U32)(ip-base);
|
|
421
|
+
const U32 btLow = btMask >= current ? 0 : current - btMask;
|
|
422
|
+
U32* smallerPtr = bt + 2*(current&btMask);
|
|
423
|
+
U32* largerPtr = smallerPtr + 1;
|
|
424
|
+
U32 dummy32; /* to be nullified at the end */
|
|
425
|
+
U32 const windowLow = ms->window.lowLimit;
|
|
426
|
+
U32 matchEndIdx = current+8+1;
|
|
427
|
+
size_t bestLength = 8;
|
|
428
|
+
U32 nbCompares = 1U << cParams->searchLog;
|
|
429
|
+
#ifdef ZSTD_C_PREDICT
|
|
430
|
+
U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
|
|
431
|
+
U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
|
|
432
|
+
predictedSmall += (predictedSmall>0);
|
|
433
|
+
predictedLarge += (predictedLarge>0);
|
|
434
|
+
#endif /* ZSTD_C_PREDICT */
|
|
435
|
+
|
|
436
|
+
DEBUGLOG(8, "ZSTD_insertBt1 (%u)", current);
|
|
437
|
+
|
|
438
|
+
assert(ip <= iend-8); /* required for h calculation */
|
|
439
|
+
hashTable[h] = current; /* Update Hash Table */
|
|
440
|
+
|
|
441
|
+
assert(windowLow > 0);
|
|
442
|
+
while (nbCompares-- && (matchIndex >= windowLow)) {
|
|
443
|
+
U32* const nextPtr = bt + 2*(matchIndex & btMask);
|
|
444
|
+
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
|
445
|
+
assert(matchIndex < current);
|
|
446
|
+
|
|
447
|
+
#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
|
|
448
|
+
const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
|
|
449
|
+
if (matchIndex == predictedSmall) {
|
|
450
|
+
/* no need to check length, result known */
|
|
451
|
+
*smallerPtr = matchIndex;
|
|
452
|
+
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
|
453
|
+
smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
|
|
454
|
+
matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
|
|
455
|
+
predictedSmall = predictPtr[1] + (predictPtr[1]>0);
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
if (matchIndex == predictedLarge) {
|
|
459
|
+
*largerPtr = matchIndex;
|
|
460
|
+
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
|
|
461
|
+
largerPtr = nextPtr;
|
|
462
|
+
matchIndex = nextPtr[0];
|
|
463
|
+
predictedLarge = predictPtr[0] + (predictPtr[0]>0);
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
#endif
|
|
467
|
+
|
|
468
|
+
if (!extDict || (matchIndex+matchLength >= dictLimit)) {
|
|
469
|
+
assert(matchIndex+matchLength >= dictLimit); /* might be wrong if actually extDict */
|
|
470
|
+
match = base + matchIndex;
|
|
471
|
+
matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
|
|
472
|
+
} else {
|
|
473
|
+
match = dictBase + matchIndex;
|
|
474
|
+
matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
|
|
475
|
+
if (matchIndex+matchLength >= dictLimit)
|
|
476
|
+
match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
if (matchLength > bestLength) {
|
|
480
|
+
bestLength = matchLength;
|
|
481
|
+
if (matchLength > matchEndIdx - matchIndex)
|
|
482
|
+
matchEndIdx = matchIndex + (U32)matchLength;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (ip+matchLength == iend) { /* equal : no way to know if inf or sup */
|
|
486
|
+
break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
if (match[matchLength] < ip[matchLength]) { /* necessarily within buffer */
|
|
490
|
+
/* match is smaller than current */
|
|
491
|
+
*smallerPtr = matchIndex; /* update smaller idx */
|
|
492
|
+
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
|
|
493
|
+
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop searching */
|
|
494
|
+
smallerPtr = nextPtr+1; /* new "candidate" => larger than match, which was smaller than target */
|
|
495
|
+
matchIndex = nextPtr[1]; /* new matchIndex, larger than previous and closer to current */
|
|
496
|
+
} else {
|
|
497
|
+
/* match is larger than current */
|
|
498
|
+
*largerPtr = matchIndex;
|
|
499
|
+
commonLengthLarger = matchLength;
|
|
500
|
+
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop searching */
|
|
501
|
+
largerPtr = nextPtr;
|
|
502
|
+
matchIndex = nextPtr[0];
|
|
503
|
+
} }
|
|
504
|
+
|
|
505
|
+
*smallerPtr = *largerPtr = 0;
|
|
506
|
+
if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
|
|
507
|
+
assert(matchEndIdx > current + 8);
|
|
508
|
+
return matchEndIdx - (current + 8);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
FORCE_INLINE_TEMPLATE
|
|
512
|
+
void ZSTD_updateTree_internal(
|
|
513
|
+
ZSTD_matchState_t* ms,
|
|
514
|
+
const BYTE* const ip, const BYTE* const iend,
|
|
515
|
+
const U32 mls, const ZSTD_dictMode_e dictMode)
|
|
516
|
+
{
|
|
517
|
+
const BYTE* const base = ms->window.base;
|
|
518
|
+
U32 const target = (U32)(ip - base);
|
|
519
|
+
U32 idx = ms->nextToUpdate;
|
|
520
|
+
DEBUGLOG(6, "ZSTD_updateTree_internal, from %u to %u (dictMode:%u)",
|
|
521
|
+
idx, target, dictMode);
|
|
522
|
+
|
|
523
|
+
while(idx < target)
|
|
524
|
+
idx += ZSTD_insertBt1(ms, base+idx, iend, mls, dictMode == ZSTD_extDict);
|
|
525
|
+
ms->nextToUpdate = target;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
void ZSTD_updateTree(ZSTD_matchState_t* ms, const BYTE* ip, const BYTE* iend) {
|
|
529
|
+
ZSTD_updateTree_internal(ms, ip, iend, ms->cParams.minMatch, ZSTD_noDict);
|
|
530
|
+
}
|
|
531
|
+
|
|
268
532
|
FORCE_INLINE_TEMPLATE
|
|
269
533
|
U32 ZSTD_insertBtAndGetAllMatches (
|
|
270
|
-
|
|
271
|
-
const BYTE* const ip, const BYTE* const iLimit,
|
|
272
|
-
U32
|
|
273
|
-
U32
|
|
274
|
-
ZSTD_match_t* matches,
|
|
534
|
+
ZSTD_matchState_t* ms,
|
|
535
|
+
const BYTE* const ip, const BYTE* const iLimit, const ZSTD_dictMode_e dictMode,
|
|
536
|
+
U32 rep[ZSTD_REP_NUM],
|
|
537
|
+
U32 const ll0, /* tells if associated literal length is 0 or not. This value must be 0 or 1 */
|
|
538
|
+
ZSTD_match_t* matches,
|
|
539
|
+
const U32 lengthToBeat,
|
|
540
|
+
U32 const mls /* template */)
|
|
275
541
|
{
|
|
276
|
-
const
|
|
542
|
+
const ZSTD_compressionParameters* const cParams = &ms->cParams;
|
|
543
|
+
U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
|
|
544
|
+
const BYTE* const base = ms->window.base;
|
|
277
545
|
U32 const current = (U32)(ip-base);
|
|
278
|
-
U32 const hashLog =
|
|
546
|
+
U32 const hashLog = cParams->hashLog;
|
|
279
547
|
U32 const minMatch = (mls==3) ? 3 : 4;
|
|
280
|
-
U32* const hashTable =
|
|
548
|
+
U32* const hashTable = ms->hashTable;
|
|
281
549
|
size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
|
|
282
550
|
U32 matchIndex = hashTable[h];
|
|
283
|
-
U32* const bt =
|
|
284
|
-
U32 const btLog =
|
|
551
|
+
U32* const bt = ms->chainTable;
|
|
552
|
+
U32 const btLog = cParams->chainLog - 1;
|
|
285
553
|
U32 const btMask= (1U << btLog) - 1;
|
|
286
554
|
size_t commonLengthSmaller=0, commonLengthLarger=0;
|
|
287
|
-
const BYTE* const dictBase =
|
|
288
|
-
U32 const dictLimit =
|
|
555
|
+
const BYTE* const dictBase = ms->window.dictBase;
|
|
556
|
+
U32 const dictLimit = ms->window.dictLimit;
|
|
289
557
|
const BYTE* const dictEnd = dictBase + dictLimit;
|
|
290
558
|
const BYTE* const prefixStart = base + dictLimit;
|
|
291
559
|
U32 const btLow = btMask >= current ? 0 : current - btMask;
|
|
292
|
-
U32 const windowLow =
|
|
560
|
+
U32 const windowLow = ms->window.lowLimit;
|
|
561
|
+
U32 const matchLow = windowLow ? windowLow : 1;
|
|
293
562
|
U32* smallerPtr = bt + 2*(current&btMask);
|
|
294
563
|
U32* largerPtr = bt + 2*(current&btMask) + 1;
|
|
295
564
|
U32 matchEndIdx = current+8+1; /* farthest referenced position of any match => detects repetitive patterns */
|
|
296
565
|
U32 dummy32; /* to be nullified at the end */
|
|
297
566
|
U32 mnum = 0;
|
|
567
|
+
U32 nbCompares = 1U << cParams->searchLog;
|
|
568
|
+
|
|
569
|
+
const ZSTD_matchState_t* dms = dictMode == ZSTD_dictMatchState ? ms->dictMatchState : NULL;
|
|
570
|
+
const ZSTD_compressionParameters* const dmsCParams =
|
|
571
|
+
dictMode == ZSTD_dictMatchState ? &dms->cParams : NULL;
|
|
572
|
+
const BYTE* const dmsBase = dictMode == ZSTD_dictMatchState ? dms->window.base : NULL;
|
|
573
|
+
const BYTE* const dmsEnd = dictMode == ZSTD_dictMatchState ? dms->window.nextSrc : NULL;
|
|
574
|
+
U32 const dmsHighLimit = dictMode == ZSTD_dictMatchState ? (U32)(dmsEnd - dmsBase) : 0;
|
|
575
|
+
U32 const dmsLowLimit = dictMode == ZSTD_dictMatchState ? dms->window.lowLimit : 0;
|
|
576
|
+
U32 const dmsIndexDelta = dictMode == ZSTD_dictMatchState ? windowLow - dmsHighLimit : 0;
|
|
577
|
+
U32 const dmsHashLog = dictMode == ZSTD_dictMatchState ? dmsCParams->hashLog : hashLog;
|
|
578
|
+
U32 const dmsBtLog = dictMode == ZSTD_dictMatchState ? dmsCParams->chainLog - 1 : btLog;
|
|
579
|
+
U32 const dmsBtMask = dictMode == ZSTD_dictMatchState ? (1U << dmsBtLog) - 1 : 0;
|
|
580
|
+
U32 const dmsBtLow = dictMode == ZSTD_dictMatchState && dmsBtMask < dmsHighLimit - dmsLowLimit ? dmsHighLimit - dmsBtMask : dmsLowLimit;
|
|
298
581
|
|
|
299
582
|
size_t bestLength = lengthToBeat-1;
|
|
300
|
-
DEBUGLOG(
|
|
583
|
+
DEBUGLOG(8, "ZSTD_insertBtAndGetAllMatches: current=%u", current);
|
|
301
584
|
|
|
302
585
|
/* check repCode */
|
|
586
|
+
assert(ll0 <= 1); /* necessarily 1 or 0 */
|
|
303
587
|
{ U32 const lastR = ZSTD_REP_NUM + ll0;
|
|
304
588
|
U32 repCode;
|
|
305
589
|
for (repCode = ll0; repCode < lastR; repCode++) {
|
|
@@ -312,18 +596,26 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
|
|
312
596
|
repLen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repOffset, iLimit) + minMatch;
|
|
313
597
|
}
|
|
314
598
|
} else { /* repIndex < dictLimit || repIndex >= current */
|
|
315
|
-
const BYTE* const repMatch =
|
|
599
|
+
const BYTE* const repMatch = dictMode == ZSTD_dictMatchState ?
|
|
600
|
+
dmsBase + repIndex - dmsIndexDelta :
|
|
601
|
+
dictBase + repIndex;
|
|
316
602
|
assert(current >= windowLow);
|
|
317
|
-
if (
|
|
603
|
+
if ( dictMode == ZSTD_extDict
|
|
318
604
|
&& ( ((repOffset-1) /*intentional overflow*/ < current - windowLow) /* equivalent to `current > repIndex >= windowLow` */
|
|
319
605
|
& (((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */)
|
|
320
606
|
&& (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
|
|
321
607
|
repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dictEnd, prefixStart) + minMatch;
|
|
608
|
+
}
|
|
609
|
+
if (dictMode == ZSTD_dictMatchState
|
|
610
|
+
&& ( ((repOffset-1) /*intentional overflow*/ < current - (dmsLowLimit + dmsIndexDelta)) /* equivalent to `current > repIndex >= dmsLowLimit` */
|
|
611
|
+
& ((U32)((dictLimit-1) - repIndex) >= 3) ) /* intentional overflow : do not test positions overlapping 2 memory segments */
|
|
612
|
+
&& (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
|
|
613
|
+
repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dmsEnd, prefixStart) + minMatch;
|
|
322
614
|
} }
|
|
323
615
|
/* save longer solution */
|
|
324
616
|
if (repLen > bestLength) {
|
|
325
|
-
DEBUGLOG(8, "found
|
|
326
|
-
repCode
|
|
617
|
+
DEBUGLOG(8, "found repCode %u (ll0:%u, offset:%u) of length %u",
|
|
618
|
+
repCode, ll0, repOffset, repLen);
|
|
327
619
|
bestLength = repLen;
|
|
328
620
|
matches[mnum].off = repCode - ll0;
|
|
329
621
|
matches[mnum].len = (U32)repLen;
|
|
@@ -335,11 +627,11 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
|
|
335
627
|
|
|
336
628
|
/* HC3 match finder */
|
|
337
629
|
if ((mls == 3) /*static*/ && (bestLength < mls)) {
|
|
338
|
-
U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3
|
|
339
|
-
if ((matchIndex3
|
|
630
|
+
U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(ms, ip);
|
|
631
|
+
if ((matchIndex3 >= matchLow)
|
|
340
632
|
& (current - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) {
|
|
341
633
|
size_t mlen;
|
|
342
|
-
if ((
|
|
634
|
+
if ((dictMode == ZSTD_noDict) /*static*/ || (dictMode == ZSTD_dictMatchState) /*static*/ || (matchIndex3 >= dictLimit)) {
|
|
343
635
|
const BYTE* const match = base + matchIndex3;
|
|
344
636
|
mlen = ZSTD_count(ip, match, iLimit);
|
|
345
637
|
} else {
|
|
@@ -359,19 +651,23 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
|
|
359
651
|
mnum = 1;
|
|
360
652
|
if ( (mlen > sufficient_len) |
|
|
361
653
|
(ip+mlen == iLimit) ) { /* best possible length */
|
|
362
|
-
|
|
654
|
+
ms->nextToUpdate = current+1; /* skip insertion */
|
|
363
655
|
return 1;
|
|
364
|
-
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
/* no dictMatchState lookup: dicts don't have a populated HC3 table */
|
|
660
|
+
}
|
|
365
661
|
|
|
366
662
|
hashTable[h] = current; /* Update Hash Table */
|
|
367
663
|
|
|
368
|
-
while (nbCompares-- && (matchIndex
|
|
664
|
+
while (nbCompares-- && (matchIndex >= matchLow)) {
|
|
369
665
|
U32* const nextPtr = bt + 2*(matchIndex & btMask);
|
|
370
666
|
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
|
371
667
|
const BYTE* match;
|
|
372
668
|
assert(current > matchIndex);
|
|
373
669
|
|
|
374
|
-
if ((
|
|
670
|
+
if ((dictMode == ZSTD_noDict) || (dictMode == ZSTD_dictMatchState) || (matchIndex+matchLength >= dictLimit)) {
|
|
375
671
|
assert(matchIndex+matchLength >= dictLimit); /* ensure the condition is correct when !extDict */
|
|
376
672
|
match = base + matchIndex;
|
|
377
673
|
matchLength += ZSTD_count(ip+matchLength, match+matchLength, iLimit);
|
|
@@ -383,8 +679,8 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
|
|
383
679
|
}
|
|
384
680
|
|
|
385
681
|
if (matchLength > bestLength) {
|
|
386
|
-
DEBUGLOG(8, "found match of length %u at distance %u",
|
|
387
|
-
(U32)matchLength, current - matchIndex);
|
|
682
|
+
DEBUGLOG(8, "found match of length %u at distance %u (offCode=%u)",
|
|
683
|
+
(U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE);
|
|
388
684
|
assert(matchEndIdx > matchIndex);
|
|
389
685
|
if (matchLength > matchEndIdx - matchIndex)
|
|
390
686
|
matchEndIdx = matchIndex + (U32)matchLength;
|
|
@@ -392,9 +688,10 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
|
|
392
688
|
matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE;
|
|
393
689
|
matches[mnum].len = (U32)matchLength;
|
|
394
690
|
mnum++;
|
|
395
|
-
if (matchLength > ZSTD_OPT_NUM)
|
|
396
|
-
|
|
397
|
-
|
|
691
|
+
if ( (matchLength > ZSTD_OPT_NUM)
|
|
692
|
+
| (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) {
|
|
693
|
+
if (dictMode == ZSTD_dictMatchState) nbCompares = 0; /* break should also skip searching dms */
|
|
694
|
+
break; /* drop, to preserve bt consistency (miss a little bit of compression) */
|
|
398
695
|
}
|
|
399
696
|
}
|
|
400
697
|
|
|
@@ -415,31 +712,72 @@ U32 ZSTD_insertBtAndGetAllMatches (
|
|
|
415
712
|
|
|
416
713
|
*smallerPtr = *largerPtr = 0;
|
|
417
714
|
|
|
715
|
+
if (dictMode == ZSTD_dictMatchState && nbCompares) {
|
|
716
|
+
size_t const dmsH = ZSTD_hashPtr(ip, dmsHashLog, mls);
|
|
717
|
+
U32 dictMatchIndex = dms->hashTable[dmsH];
|
|
718
|
+
const U32* const dmsBt = dms->chainTable;
|
|
719
|
+
commonLengthSmaller = commonLengthLarger = 0;
|
|
720
|
+
while (nbCompares-- && (dictMatchIndex > dmsLowLimit)) {
|
|
721
|
+
const U32* const nextPtr = dmsBt + 2*(dictMatchIndex & dmsBtMask);
|
|
722
|
+
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
|
|
723
|
+
const BYTE* match = dmsBase + dictMatchIndex;
|
|
724
|
+
matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dmsEnd, prefixStart);
|
|
725
|
+
if (dictMatchIndex+matchLength >= dmsHighLimit)
|
|
726
|
+
match = base + dictMatchIndex + dmsIndexDelta; /* to prepare for next usage of match[matchLength] */
|
|
727
|
+
|
|
728
|
+
if (matchLength > bestLength) {
|
|
729
|
+
matchIndex = dictMatchIndex + dmsIndexDelta;
|
|
730
|
+
DEBUGLOG(8, "found dms match of length %u at distance %u (offCode=%u)",
|
|
731
|
+
(U32)matchLength, current - matchIndex, current - matchIndex + ZSTD_REP_MOVE);
|
|
732
|
+
if (matchLength > matchEndIdx - matchIndex)
|
|
733
|
+
matchEndIdx = matchIndex + (U32)matchLength;
|
|
734
|
+
bestLength = matchLength;
|
|
735
|
+
matches[mnum].off = (current - matchIndex) + ZSTD_REP_MOVE;
|
|
736
|
+
matches[mnum].len = (U32)matchLength;
|
|
737
|
+
mnum++;
|
|
738
|
+
if ( (matchLength > ZSTD_OPT_NUM)
|
|
739
|
+
| (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) {
|
|
740
|
+
break; /* drop, to guarantee consistency (miss a little bit of compression) */
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
if (dictMatchIndex <= dmsBtLow) { break; } /* beyond tree size, stop the search */
|
|
745
|
+
if (match[matchLength] < ip[matchLength]) {
|
|
746
|
+
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
|
|
747
|
+
dictMatchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
|
|
748
|
+
} else {
|
|
749
|
+
/* match is larger than current */
|
|
750
|
+
commonLengthLarger = matchLength;
|
|
751
|
+
dictMatchIndex = nextPtr[0];
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
|
|
418
756
|
assert(matchEndIdx > current+8);
|
|
419
|
-
|
|
757
|
+
ms->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
|
|
420
758
|
return mnum;
|
|
421
759
|
}
|
|
422
760
|
|
|
423
761
|
|
|
424
762
|
FORCE_INLINE_TEMPLATE U32 ZSTD_BtGetAllMatches (
|
|
425
|
-
|
|
426
|
-
const BYTE* ip, const BYTE* const iHighLimit,
|
|
427
|
-
U32 const maxNbAttempts, U32 const matchLengthSearch, U32 const sufficient_len,
|
|
763
|
+
ZSTD_matchState_t* ms,
|
|
764
|
+
const BYTE* ip, const BYTE* const iHighLimit, const ZSTD_dictMode_e dictMode,
|
|
428
765
|
U32 rep[ZSTD_REP_NUM], U32 const ll0,
|
|
429
766
|
ZSTD_match_t* matches, U32 const lengthToBeat)
|
|
430
767
|
{
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
768
|
+
const ZSTD_compressionParameters* const cParams = &ms->cParams;
|
|
769
|
+
U32 const matchLengthSearch = cParams->minMatch;
|
|
770
|
+
DEBUGLOG(8, "ZSTD_BtGetAllMatches");
|
|
771
|
+
if (ip < ms->window.base + ms->nextToUpdate) return 0; /* skipped area */
|
|
772
|
+
ZSTD_updateTree_internal(ms, ip, iHighLimit, matchLengthSearch, dictMode);
|
|
435
773
|
switch(matchLengthSearch)
|
|
436
774
|
{
|
|
437
|
-
case 3 : return ZSTD_insertBtAndGetAllMatches(
|
|
775
|
+
case 3 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 3);
|
|
438
776
|
default :
|
|
439
|
-
case 4 : return ZSTD_insertBtAndGetAllMatches(
|
|
440
|
-
case 5 : return ZSTD_insertBtAndGetAllMatches(
|
|
777
|
+
case 4 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 4);
|
|
778
|
+
case 5 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 5);
|
|
441
779
|
case 7 :
|
|
442
|
-
case 6 : return ZSTD_insertBtAndGetAllMatches(
|
|
780
|
+
case 6 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 6);
|
|
443
781
|
}
|
|
444
782
|
}
|
|
445
783
|
|
|
@@ -451,7 +789,7 @@ typedef struct repcodes_s {
|
|
|
451
789
|
U32 rep[3];
|
|
452
790
|
} repcodes_t;
|
|
453
791
|
|
|
454
|
-
repcodes_t ZSTD_updateRep(U32 const rep[3], U32 const offset, U32 const ll0)
|
|
792
|
+
static repcodes_t ZSTD_updateRep(U32 const rep[3], U32 const offset, U32 const ll0)
|
|
455
793
|
{
|
|
456
794
|
repcodes_t newReps;
|
|
457
795
|
if (offset >= ZSTD_REP_NUM) { /* full offset */
|
|
@@ -473,143 +811,115 @@ repcodes_t ZSTD_updateRep(U32 const rep[3], U32 const offset, U32 const ll0)
|
|
|
473
811
|
}
|
|
474
812
|
|
|
475
813
|
|
|
476
|
-
|
|
477
|
-
const BYTE* anchor;
|
|
478
|
-
U32 litlen;
|
|
479
|
-
U32 rawLitCost;
|
|
480
|
-
} cachedLiteralPrice_t;
|
|
481
|
-
|
|
482
|
-
static U32 ZSTD_rawLiteralsCost_cached(
|
|
483
|
-
cachedLiteralPrice_t* const cachedLitPrice,
|
|
484
|
-
const BYTE* const anchor, U32 const litlen,
|
|
485
|
-
const optState_t* const optStatePtr)
|
|
814
|
+
static U32 ZSTD_totalLen(ZSTD_optimal_t sol)
|
|
486
815
|
{
|
|
487
|
-
|
|
488
|
-
U32 remainingLength;
|
|
489
|
-
const BYTE* startPosition;
|
|
490
|
-
|
|
491
|
-
if (anchor == cachedLitPrice->anchor) {
|
|
492
|
-
startCost = cachedLitPrice->rawLitCost;
|
|
493
|
-
startPosition = anchor + cachedLitPrice->litlen;
|
|
494
|
-
assert(litlen >= cachedLitPrice->litlen);
|
|
495
|
-
remainingLength = litlen - cachedLitPrice->litlen;
|
|
496
|
-
} else {
|
|
497
|
-
startCost = 0;
|
|
498
|
-
startPosition = anchor;
|
|
499
|
-
remainingLength = litlen;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
{ U32 const rawLitCost = startCost + ZSTD_rawLiteralsCost(startPosition, remainingLength, optStatePtr);
|
|
503
|
-
cachedLitPrice->anchor = anchor;
|
|
504
|
-
cachedLitPrice->litlen = litlen;
|
|
505
|
-
cachedLitPrice->rawLitCost = rawLitCost;
|
|
506
|
-
return rawLitCost;
|
|
507
|
-
}
|
|
816
|
+
return sol.litlen + sol.mlen;
|
|
508
817
|
}
|
|
509
818
|
|
|
510
|
-
|
|
511
|
-
cachedLiteralPrice_t* const cachedLitPrice,
|
|
512
|
-
const BYTE* const anchor, U32 const litlen,
|
|
513
|
-
const optState_t* const optStatePtr)
|
|
514
|
-
{
|
|
515
|
-
return ZSTD_rawLiteralsCost_cached(cachedLitPrice, anchor, litlen, optStatePtr)
|
|
516
|
-
+ ZSTD_litLengthPrice(litlen, optStatePtr);
|
|
517
|
-
}
|
|
819
|
+
#if 0 /* debug */
|
|
518
820
|
|
|
519
|
-
static
|
|
520
|
-
|
|
521
|
-
const BYTE* const anchor, U32 const litlen,
|
|
522
|
-
const optState_t* const optStatePtr)
|
|
821
|
+
static void
|
|
822
|
+
listStats(const U32* table, int lastEltID)
|
|
523
823
|
{
|
|
524
|
-
int const
|
|
525
|
-
|
|
526
|
-
|
|
824
|
+
int const nbElts = lastEltID + 1;
|
|
825
|
+
int enb;
|
|
826
|
+
for (enb=0; enb < nbElts; enb++) {
|
|
827
|
+
(void)table;
|
|
828
|
+
//RAWLOG(2, "%3i:%3i, ", enb, table[enb]);
|
|
829
|
+
RAWLOG(2, "%4i,", table[enb]);
|
|
830
|
+
}
|
|
831
|
+
RAWLOG(2, " \n");
|
|
527
832
|
}
|
|
528
833
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
834
|
+
#endif
|
|
835
|
+
|
|
836
|
+
FORCE_INLINE_TEMPLATE size_t
|
|
837
|
+
ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
|
|
838
|
+
seqStore_t* seqStore,
|
|
839
|
+
U32 rep[ZSTD_REP_NUM],
|
|
840
|
+
const void* src, size_t srcSize,
|
|
841
|
+
const int optLevel,
|
|
842
|
+
const ZSTD_dictMode_e dictMode)
|
|
533
843
|
{
|
|
534
|
-
|
|
535
|
-
optState_t* const optStatePtr = &(ctx->optState);
|
|
844
|
+
optState_t* const optStatePtr = &ms->opt;
|
|
536
845
|
const BYTE* const istart = (const BYTE*)src;
|
|
537
846
|
const BYTE* ip = istart;
|
|
538
847
|
const BYTE* anchor = istart;
|
|
539
848
|
const BYTE* const iend = istart + srcSize;
|
|
540
849
|
const BYTE* const ilimit = iend - 8;
|
|
541
|
-
const BYTE* const base =
|
|
542
|
-
const BYTE* const prefixStart = base +
|
|
850
|
+
const BYTE* const base = ms->window.base;
|
|
851
|
+
const BYTE* const prefixStart = base + ms->window.dictLimit;
|
|
852
|
+
const ZSTD_compressionParameters* const cParams = &ms->cParams;
|
|
543
853
|
|
|
544
|
-
U32 const
|
|
545
|
-
U32 const
|
|
546
|
-
U32 const mls = ctx->appliedParams.cParams.searchLength;
|
|
547
|
-
U32 const minMatch = (ctx->appliedParams.cParams.searchLength == 3) ? 3 : 4;
|
|
854
|
+
U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
|
|
855
|
+
U32 const minMatch = (cParams->minMatch == 3) ? 3 : 4;
|
|
548
856
|
|
|
549
857
|
ZSTD_optimal_t* const opt = optStatePtr->priceTable;
|
|
550
858
|
ZSTD_match_t* const matches = optStatePtr->matchTable;
|
|
551
|
-
|
|
552
|
-
U32 rep[ZSTD_REP_NUM];
|
|
859
|
+
ZSTD_optimal_t lastSequence;
|
|
553
860
|
|
|
554
861
|
/* init */
|
|
555
|
-
DEBUGLOG(5, "ZSTD_compressBlock_opt_generic"
|
|
556
|
-
|
|
557
|
-
|
|
862
|
+
DEBUGLOG(5, "ZSTD_compressBlock_opt_generic: current=%u, prefix=%u, nextToUpdate=%u",
|
|
863
|
+
(U32)(ip - base), ms->window.dictLimit, ms->nextToUpdate);
|
|
864
|
+
assert(optLevel <= 2);
|
|
865
|
+
ms->nextToUpdate3 = ms->nextToUpdate;
|
|
866
|
+
ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize, optLevel);
|
|
558
867
|
ip += (ip==prefixStart);
|
|
559
|
-
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) rep[i]=seqStorePtr->rep[i]; }
|
|
560
|
-
memset(&cachedLitPrice, 0, sizeof(cachedLitPrice));
|
|
561
868
|
|
|
562
869
|
/* Match Loop */
|
|
563
870
|
while (ip < ilimit) {
|
|
564
871
|
U32 cur, last_pos = 0;
|
|
565
|
-
U32 best_mlen, best_off;
|
|
566
872
|
|
|
567
873
|
/* find first match */
|
|
568
874
|
{ U32 const litlen = (U32)(ip - anchor);
|
|
569
875
|
U32 const ll0 = !litlen;
|
|
570
|
-
U32 const nbMatches = ZSTD_BtGetAllMatches(
|
|
876
|
+
U32 const nbMatches = ZSTD_BtGetAllMatches(ms, ip, iend, dictMode, rep, ll0, matches, minMatch);
|
|
571
877
|
if (!nbMatches) { ip++; continue; }
|
|
572
878
|
|
|
573
879
|
/* initialize opt[0] */
|
|
574
880
|
{ U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
|
|
575
|
-
opt[0].mlen =
|
|
881
|
+
opt[0].mlen = 0; /* means is_a_literal */
|
|
576
882
|
opt[0].litlen = litlen;
|
|
883
|
+
opt[0].price = ZSTD_literalsContribution(anchor, litlen, optStatePtr, optLevel);
|
|
577
884
|
|
|
578
885
|
/* large match -> immediate encoding */
|
|
579
886
|
{ U32 const maxML = matches[nbMatches-1].len;
|
|
580
|
-
|
|
581
|
-
|
|
887
|
+
U32 const maxOffset = matches[nbMatches-1].off;
|
|
888
|
+
DEBUGLOG(6, "found %u matches of maxLength=%u and maxOffCode=%u at cPos=%u => start new series",
|
|
889
|
+
nbMatches, maxML, maxOffset, (U32)(ip-prefixStart));
|
|
582
890
|
|
|
583
891
|
if (maxML > sufficient_len) {
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
892
|
+
lastSequence.litlen = litlen;
|
|
893
|
+
lastSequence.mlen = maxML;
|
|
894
|
+
lastSequence.off = maxOffset;
|
|
895
|
+
DEBUGLOG(6, "large match (%u>%u), immediate encoding",
|
|
896
|
+
maxML, sufficient_len);
|
|
588
897
|
cur = 0;
|
|
589
|
-
last_pos =
|
|
898
|
+
last_pos = ZSTD_totalLen(lastSequence);
|
|
590
899
|
goto _shortestPath;
|
|
591
900
|
} }
|
|
592
901
|
|
|
593
902
|
/* set prices for first matches starting position == 0 */
|
|
594
|
-
{ U32 const literalsPrice =
|
|
903
|
+
{ U32 const literalsPrice = opt[0].price + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
|
|
595
904
|
U32 pos;
|
|
596
905
|
U32 matchNb;
|
|
597
|
-
for (pos =
|
|
598
|
-
opt[pos].
|
|
599
|
-
opt[pos].price = ZSTD_MAX_PRICE;
|
|
906
|
+
for (pos = 1; pos < minMatch; pos++) {
|
|
907
|
+
opt[pos].price = ZSTD_MAX_PRICE; /* mlen, litlen and price will be fixed during forward scanning */
|
|
600
908
|
}
|
|
601
909
|
for (matchNb = 0; matchNb < nbMatches; matchNb++) {
|
|
602
910
|
U32 const offset = matches[matchNb].off;
|
|
603
911
|
U32 const end = matches[matchNb].len;
|
|
604
912
|
repcodes_t const repHistory = ZSTD_updateRep(rep, offset, ll0);
|
|
605
913
|
for ( ; pos <= end ; pos++ ) {
|
|
606
|
-
U32 const matchPrice =
|
|
607
|
-
|
|
608
|
-
|
|
914
|
+
U32 const matchPrice = ZSTD_getMatchPrice(offset, pos, optStatePtr, optLevel);
|
|
915
|
+
U32 const sequencePrice = literalsPrice + matchPrice;
|
|
916
|
+
DEBUGLOG(7, "rPos:%u => set initial price : %.2f",
|
|
917
|
+
pos, ZSTD_fCost(sequencePrice));
|
|
609
918
|
opt[pos].mlen = pos;
|
|
610
919
|
opt[pos].off = offset;
|
|
611
920
|
opt[pos].litlen = litlen;
|
|
612
|
-
opt[pos].price =
|
|
921
|
+
opt[pos].price = sequencePrice;
|
|
922
|
+
ZSTD_STATIC_ASSERT(sizeof(opt[pos].rep) == sizeof(repHistory));
|
|
613
923
|
memcpy(opt[pos].rep, &repHistory, sizeof(repHistory));
|
|
614
924
|
} }
|
|
615
925
|
last_pos = pos-1;
|
|
@@ -620,55 +930,67 @@ size_t ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
|
|
|
620
930
|
for (cur = 1; cur <= last_pos; cur++) {
|
|
621
931
|
const BYTE* const inr = ip + cur;
|
|
622
932
|
assert(cur < ZSTD_OPT_NUM);
|
|
933
|
+
DEBUGLOG(7, "cPos:%zi==rPos:%u", inr-istart, cur)
|
|
623
934
|
|
|
624
935
|
/* Fix current position with one literal if cheaper */
|
|
625
|
-
{ U32 const litlen = (opt[cur-1].mlen ==
|
|
626
|
-
int price
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
price = ZSTD_literalsContribution_cached(&cachedLitPrice, anchor, litlen, optStatePtr);
|
|
631
|
-
}
|
|
936
|
+
{ U32 const litlen = (opt[cur-1].mlen == 0) ? opt[cur-1].litlen + 1 : 1;
|
|
937
|
+
int const price = opt[cur-1].price
|
|
938
|
+
+ ZSTD_rawLiteralsCost(ip+cur-1, 1, optStatePtr, optLevel)
|
|
939
|
+
+ ZSTD_litLengthPrice(litlen, optStatePtr, optLevel)
|
|
940
|
+
- ZSTD_litLengthPrice(litlen-1, optStatePtr, optLevel);
|
|
632
941
|
assert(price < 1000000000); /* overflow check */
|
|
633
942
|
if (price <= opt[cur].price) {
|
|
634
|
-
DEBUGLOG(7, "rPos:%u : better price (
|
|
635
|
-
cur, price, opt[cur].price)
|
|
636
|
-
|
|
943
|
+
DEBUGLOG(7, "cPos:%zi==rPos:%u : better price (%.2f<=%.2f) using literal (ll==%u) (hist:%u,%u,%u)",
|
|
944
|
+
inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price), litlen,
|
|
945
|
+
opt[cur-1].rep[0], opt[cur-1].rep[1], opt[cur-1].rep[2]);
|
|
946
|
+
opt[cur].mlen = 0;
|
|
637
947
|
opt[cur].off = 0;
|
|
638
948
|
opt[cur].litlen = litlen;
|
|
639
949
|
opt[cur].price = price;
|
|
640
950
|
memcpy(opt[cur].rep, opt[cur-1].rep, sizeof(opt[cur].rep));
|
|
641
|
-
|
|
951
|
+
} else {
|
|
952
|
+
DEBUGLOG(7, "cPos:%zi==rPos:%u : literal would cost more (%.2f>%.2f) (hist:%u,%u,%u)",
|
|
953
|
+
inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price),
|
|
954
|
+
opt[cur].rep[0], opt[cur].rep[1], opt[cur].rep[2]);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
642
957
|
|
|
643
958
|
/* last match must start at a minimum distance of 8 from oend */
|
|
644
959
|
if (inr > ilimit) continue;
|
|
645
960
|
|
|
646
961
|
if (cur == last_pos) break;
|
|
647
962
|
|
|
648
|
-
|
|
649
|
-
|
|
963
|
+
if ( (optLevel==0) /*static_test*/
|
|
964
|
+
&& (opt[cur+1].price <= opt[cur].price + (BITCOST_MULTIPLIER/2)) ) {
|
|
965
|
+
DEBUGLOG(7, "move to next rPos:%u : price is <=", cur+1);
|
|
650
966
|
continue; /* skip unpromising positions; about ~+6% speed, -0.01 ratio */
|
|
967
|
+
}
|
|
651
968
|
|
|
652
|
-
{ U32 const ll0 = (opt[cur].mlen !=
|
|
653
|
-
U32 const litlen = (opt[cur].mlen ==
|
|
654
|
-
U32 const previousPrice =
|
|
655
|
-
U32 const basePrice = previousPrice +
|
|
656
|
-
U32 const nbMatches = ZSTD_BtGetAllMatches(
|
|
969
|
+
{ U32 const ll0 = (opt[cur].mlen != 0);
|
|
970
|
+
U32 const litlen = (opt[cur].mlen == 0) ? opt[cur].litlen : 0;
|
|
971
|
+
U32 const previousPrice = opt[cur].price;
|
|
972
|
+
U32 const basePrice = previousPrice + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
|
|
973
|
+
U32 const nbMatches = ZSTD_BtGetAllMatches(ms, inr, iend, dictMode, opt[cur].rep, ll0, matches, minMatch);
|
|
657
974
|
U32 matchNb;
|
|
658
|
-
if (!nbMatches)
|
|
975
|
+
if (!nbMatches) {
|
|
976
|
+
DEBUGLOG(7, "rPos:%u : no match found", cur);
|
|
977
|
+
continue;
|
|
978
|
+
}
|
|
659
979
|
|
|
660
980
|
{ U32 const maxML = matches[nbMatches-1].len;
|
|
661
|
-
DEBUGLOG(7, "rPos:%u, found %u matches, of maxLength=%u",
|
|
662
|
-
cur, nbMatches, maxML);
|
|
981
|
+
DEBUGLOG(7, "cPos:%zi==rPos:%u, found %u matches, of maxLength=%u",
|
|
982
|
+
inr-istart, cur, nbMatches, maxML);
|
|
663
983
|
|
|
664
984
|
if ( (maxML > sufficient_len)
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
985
|
+
|| (cur + maxML >= ZSTD_OPT_NUM) ) {
|
|
986
|
+
lastSequence.mlen = maxML;
|
|
987
|
+
lastSequence.off = matches[nbMatches-1].off;
|
|
988
|
+
lastSequence.litlen = litlen;
|
|
989
|
+
cur -= (opt[cur].mlen==0) ? opt[cur].litlen : 0; /* last sequence is actually only literals, fix cur to last match - note : may underflow, in which case, it's first sequence, and it's okay */
|
|
990
|
+
last_pos = cur + ZSTD_totalLen(lastSequence);
|
|
991
|
+
if (cur > ZSTD_OPT_NUM) cur = 0; /* underflow => first match */
|
|
669
992
|
goto _shortestPath;
|
|
670
|
-
|
|
671
|
-
}
|
|
993
|
+
} }
|
|
672
994
|
|
|
673
995
|
/* set prices using matches found at position == cur */
|
|
674
996
|
for (matchNb = 0; matchNb < nbMatches; matchNb++) {
|
|
@@ -678,108 +1000,234 @@ size_t ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
|
|
|
678
1000
|
U32 const startML = (matchNb>0) ? matches[matchNb-1].len+1 : minMatch;
|
|
679
1001
|
U32 mlen;
|
|
680
1002
|
|
|
681
|
-
DEBUGLOG(7, "testing match %u => offCode=%
|
|
1003
|
+
DEBUGLOG(7, "testing match %u => offCode=%4u, mlen=%2u, llen=%2u",
|
|
682
1004
|
matchNb, matches[matchNb].off, lastML, litlen);
|
|
683
1005
|
|
|
684
|
-
for (mlen = lastML; mlen >= startML; mlen--) {
|
|
1006
|
+
for (mlen = lastML; mlen >= startML; mlen--) { /* scan downward */
|
|
685
1007
|
U32 const pos = cur + mlen;
|
|
686
1008
|
int const price = basePrice + ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel);
|
|
687
1009
|
|
|
688
1010
|
if ((pos > last_pos) || (price < opt[pos].price)) {
|
|
689
|
-
DEBUGLOG(7, "rPos:%u => new better price (
|
|
690
|
-
pos, price, opt[pos].price);
|
|
691
|
-
while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; }
|
|
1011
|
+
DEBUGLOG(7, "rPos:%u (ml=%2u) => new better price (%.2f<%.2f)",
|
|
1012
|
+
pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price));
|
|
1013
|
+
while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } /* fill empty positions */
|
|
692
1014
|
opt[pos].mlen = mlen;
|
|
693
1015
|
opt[pos].off = offset;
|
|
694
1016
|
opt[pos].litlen = litlen;
|
|
695
1017
|
opt[pos].price = price;
|
|
1018
|
+
ZSTD_STATIC_ASSERT(sizeof(opt[pos].rep) == sizeof(repHistory));
|
|
696
1019
|
memcpy(opt[pos].rep, &repHistory, sizeof(repHistory));
|
|
697
1020
|
} else {
|
|
698
|
-
|
|
1021
|
+
DEBUGLOG(7, "rPos:%u (ml=%2u) => new price is worse (%.2f>=%.2f)",
|
|
1022
|
+
pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price));
|
|
1023
|
+
if (optLevel==0) break; /* early update abort; gets ~+10% speed for about -0.01 ratio loss */
|
|
699
1024
|
}
|
|
700
1025
|
} } }
|
|
701
1026
|
} /* for (cur = 1; cur <= last_pos; cur++) */
|
|
702
1027
|
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
cur
|
|
1028
|
+
lastSequence = opt[last_pos];
|
|
1029
|
+
cur = last_pos > ZSTD_totalLen(lastSequence) ? last_pos - ZSTD_totalLen(lastSequence) : 0; /* single sequence, and it starts before `ip` */
|
|
1030
|
+
assert(cur < ZSTD_OPT_NUM); /* control overflow*/
|
|
706
1031
|
|
|
707
1032
|
_shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */
|
|
708
|
-
assert(opt[0].mlen ==
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
|
|
745
|
-
if (repCode >= 2) rep[2] = rep[1];
|
|
746
|
-
rep[1] = rep[0];
|
|
747
|
-
rep[0] = currentOffset;
|
|
1033
|
+
assert(opt[0].mlen == 0);
|
|
1034
|
+
|
|
1035
|
+
{ U32 const storeEnd = cur + 1;
|
|
1036
|
+
U32 storeStart = storeEnd;
|
|
1037
|
+
U32 seqPos = cur;
|
|
1038
|
+
|
|
1039
|
+
DEBUGLOG(6, "start reverse traversal (last_pos:%u, cur:%u)",
|
|
1040
|
+
last_pos, cur); (void)last_pos;
|
|
1041
|
+
assert(storeEnd < ZSTD_OPT_NUM);
|
|
1042
|
+
DEBUGLOG(6, "last sequence copied into pos=%u (llen=%u,mlen=%u,ofc=%u)",
|
|
1043
|
+
storeEnd, lastSequence.litlen, lastSequence.mlen, lastSequence.off);
|
|
1044
|
+
opt[storeEnd] = lastSequence;
|
|
1045
|
+
while (seqPos > 0) {
|
|
1046
|
+
U32 const backDist = ZSTD_totalLen(opt[seqPos]);
|
|
1047
|
+
storeStart--;
|
|
1048
|
+
DEBUGLOG(6, "sequence from rPos=%u copied into pos=%u (llen=%u,mlen=%u,ofc=%u)",
|
|
1049
|
+
seqPos, storeStart, opt[seqPos].litlen, opt[seqPos].mlen, opt[seqPos].off);
|
|
1050
|
+
opt[storeStart] = opt[seqPos];
|
|
1051
|
+
seqPos = (seqPos > backDist) ? seqPos - backDist : 0;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
/* save sequences */
|
|
1055
|
+
DEBUGLOG(6, "sending selected sequences into seqStore")
|
|
1056
|
+
{ U32 storePos;
|
|
1057
|
+
for (storePos=storeStart; storePos <= storeEnd; storePos++) {
|
|
1058
|
+
U32 const llen = opt[storePos].litlen;
|
|
1059
|
+
U32 const mlen = opt[storePos].mlen;
|
|
1060
|
+
U32 const offCode = opt[storePos].off;
|
|
1061
|
+
U32 const advance = llen + mlen;
|
|
1062
|
+
DEBUGLOG(6, "considering seq starting at %zi, llen=%u, mlen=%u",
|
|
1063
|
+
anchor - istart, (unsigned)llen, (unsigned)mlen);
|
|
1064
|
+
|
|
1065
|
+
if (mlen==0) { /* only literals => must be last "sequence", actually starting a new stream of sequences */
|
|
1066
|
+
assert(storePos == storeEnd); /* must be last sequence */
|
|
1067
|
+
ip = anchor + llen; /* last "sequence" is a bunch of literals => don't progress anchor */
|
|
1068
|
+
continue; /* will finish */
|
|
748
1069
|
}
|
|
749
|
-
}
|
|
750
1070
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
1071
|
+
/* repcodes update : like ZSTD_updateRep(), but update in place */
|
|
1072
|
+
if (offCode >= ZSTD_REP_NUM) { /* full offset */
|
|
1073
|
+
rep[2] = rep[1];
|
|
1074
|
+
rep[1] = rep[0];
|
|
1075
|
+
rep[0] = offCode - ZSTD_REP_MOVE;
|
|
1076
|
+
} else { /* repcode */
|
|
1077
|
+
U32 const repCode = offCode + (llen==0);
|
|
1078
|
+
if (repCode) { /* note : if repCode==0, no change */
|
|
1079
|
+
U32 const currentOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
|
|
1080
|
+
if (repCode >= 2) rep[2] = rep[1];
|
|
1081
|
+
rep[1] = rep[0];
|
|
1082
|
+
rep[0] = currentOffset;
|
|
1083
|
+
} }
|
|
1084
|
+
|
|
1085
|
+
assert(anchor + llen <= iend);
|
|
1086
|
+
ZSTD_updateStats(optStatePtr, llen, anchor, offCode, mlen);
|
|
1087
|
+
ZSTD_storeSeq(seqStore, llen, anchor, offCode, mlen-MINMATCH);
|
|
1088
|
+
anchor += advance;
|
|
1089
|
+
ip = anchor;
|
|
1090
|
+
} }
|
|
1091
|
+
ZSTD_setBasePrices(optStatePtr, optLevel);
|
|
1092
|
+
}
|
|
757
1093
|
|
|
758
|
-
/*
|
|
759
|
-
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->repToConfirm[i] = rep[i]; }
|
|
1094
|
+
} /* while (ip < ilimit) */
|
|
760
1095
|
|
|
761
1096
|
/* Return the last literals size */
|
|
762
1097
|
return iend - anchor;
|
|
763
1098
|
}
|
|
764
1099
|
|
|
765
1100
|
|
|
766
|
-
size_t ZSTD_compressBlock_btopt(
|
|
1101
|
+
size_t ZSTD_compressBlock_btopt(
|
|
1102
|
+
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
1103
|
+
const void* src, size_t srcSize)
|
|
767
1104
|
{
|
|
768
1105
|
DEBUGLOG(5, "ZSTD_compressBlock_btopt");
|
|
769
|
-
return ZSTD_compressBlock_opt_generic(
|
|
1106
|
+
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_noDict);
|
|
770
1107
|
}
|
|
771
1108
|
|
|
772
|
-
|
|
1109
|
+
|
|
1110
|
+
/* used in 2-pass strategy */
|
|
1111
|
+
static U32 ZSTD_upscaleStat(unsigned* table, U32 lastEltIndex, int bonus)
|
|
773
1112
|
{
|
|
774
|
-
|
|
1113
|
+
U32 s, sum=0;
|
|
1114
|
+
assert(ZSTD_FREQ_DIV+bonus >= 0);
|
|
1115
|
+
for (s=0; s<lastEltIndex+1; s++) {
|
|
1116
|
+
table[s] <<= ZSTD_FREQ_DIV+bonus;
|
|
1117
|
+
table[s]--;
|
|
1118
|
+
sum += table[s];
|
|
1119
|
+
}
|
|
1120
|
+
return sum;
|
|
775
1121
|
}
|
|
776
1122
|
|
|
777
|
-
|
|
1123
|
+
/* used in 2-pass strategy */
|
|
1124
|
+
MEM_STATIC void ZSTD_upscaleStats(optState_t* optPtr)
|
|
778
1125
|
{
|
|
779
|
-
|
|
1126
|
+
if (ZSTD_compressedLiterals(optPtr))
|
|
1127
|
+
optPtr->litSum = ZSTD_upscaleStat(optPtr->litFreq, MaxLit, 0);
|
|
1128
|
+
optPtr->litLengthSum = ZSTD_upscaleStat(optPtr->litLengthFreq, MaxLL, 0);
|
|
1129
|
+
optPtr->matchLengthSum = ZSTD_upscaleStat(optPtr->matchLengthFreq, MaxML, 0);
|
|
1130
|
+
optPtr->offCodeSum = ZSTD_upscaleStat(optPtr->offCodeFreq, MaxOff, 0);
|
|
780
1131
|
}
|
|
781
1132
|
|
|
782
|
-
|
|
1133
|
+
/* ZSTD_initStats_ultra():
|
|
1134
|
+
* make a first compression pass, just to seed stats with more accurate starting values.
|
|
1135
|
+
* only works on first block, with no dictionary and no ldm.
|
|
1136
|
+
* this function cannot error, hence its contract must be respected.
|
|
1137
|
+
*/
|
|
1138
|
+
static void
|
|
1139
|
+
ZSTD_initStats_ultra(ZSTD_matchState_t* ms,
|
|
1140
|
+
seqStore_t* seqStore,
|
|
1141
|
+
U32 rep[ZSTD_REP_NUM],
|
|
1142
|
+
const void* src, size_t srcSize)
|
|
1143
|
+
{
|
|
1144
|
+
U32 tmpRep[ZSTD_REP_NUM]; /* updated rep codes will sink here */
|
|
1145
|
+
memcpy(tmpRep, rep, sizeof(tmpRep));
|
|
1146
|
+
|
|
1147
|
+
DEBUGLOG(4, "ZSTD_initStats_ultra (srcSize=%zu)", srcSize);
|
|
1148
|
+
assert(ms->opt.litLengthSum == 0); /* first block */
|
|
1149
|
+
assert(seqStore->sequences == seqStore->sequencesStart); /* no ldm */
|
|
1150
|
+
assert(ms->window.dictLimit == ms->window.lowLimit); /* no dictionary */
|
|
1151
|
+
assert(ms->window.dictLimit - ms->nextToUpdate <= 1); /* no prefix (note: intentional overflow, defined as 2-complement) */
|
|
1152
|
+
|
|
1153
|
+
ZSTD_compressBlock_opt_generic(ms, seqStore, tmpRep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict); /* generate stats into ms->opt*/
|
|
1154
|
+
|
|
1155
|
+
/* invalidate first scan from history */
|
|
1156
|
+
ZSTD_resetSeqStore(seqStore);
|
|
1157
|
+
ms->window.base -= srcSize;
|
|
1158
|
+
ms->window.dictLimit += (U32)srcSize;
|
|
1159
|
+
ms->window.lowLimit = ms->window.dictLimit;
|
|
1160
|
+
ms->nextToUpdate = ms->window.dictLimit;
|
|
1161
|
+
ms->nextToUpdate3 = ms->window.dictLimit;
|
|
1162
|
+
|
|
1163
|
+
/* re-inforce weight of collected statistics */
|
|
1164
|
+
ZSTD_upscaleStats(&ms->opt);
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
size_t ZSTD_compressBlock_btultra(
|
|
1168
|
+
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
1169
|
+
const void* src, size_t srcSize)
|
|
1170
|
+
{
|
|
1171
|
+
DEBUGLOG(5, "ZSTD_compressBlock_btultra (srcSize=%zu)", srcSize);
|
|
1172
|
+
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict);
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
size_t ZSTD_compressBlock_btultra2(
|
|
1176
|
+
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
1177
|
+
const void* src, size_t srcSize)
|
|
1178
|
+
{
|
|
1179
|
+
U32 const current = (U32)((const BYTE*)src - ms->window.base);
|
|
1180
|
+
DEBUGLOG(5, "ZSTD_compressBlock_btultra2 (srcSize=%zu)", srcSize);
|
|
1181
|
+
|
|
1182
|
+
/* 2-pass strategy:
|
|
1183
|
+
* this strategy makes a first pass over first block to collect statistics
|
|
1184
|
+
* and seed next round's statistics with it.
|
|
1185
|
+
* After 1st pass, function forgets everything, and starts a new block.
|
|
1186
|
+
* Consequently, this can only work if no data has been previously loaded in tables,
|
|
1187
|
+
* aka, no dictionary, no prefix, no ldm preprocessing.
|
|
1188
|
+
* The compression ratio gain is generally small (~0.5% on first block),
|
|
1189
|
+
* the cost is 2x cpu time on first block. */
|
|
1190
|
+
assert(srcSize <= ZSTD_BLOCKSIZE_MAX);
|
|
1191
|
+
if ( (ms->opt.litLengthSum==0) /* first block */
|
|
1192
|
+
&& (seqStore->sequences == seqStore->sequencesStart) /* no ldm */
|
|
1193
|
+
&& (ms->window.dictLimit == ms->window.lowLimit) /* no dictionary */
|
|
1194
|
+
&& (current == ms->window.dictLimit) /* start of frame, nothing already loaded nor skipped */
|
|
1195
|
+
&& (srcSize > ZSTD_PREDEF_THRESHOLD)
|
|
1196
|
+
) {
|
|
1197
|
+
ZSTD_initStats_ultra(ms, seqStore, rep, src, srcSize);
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_noDict);
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
size_t ZSTD_compressBlock_btopt_dictMatchState(
|
|
1204
|
+
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
1205
|
+
const void* src, size_t srcSize)
|
|
1206
|
+
{
|
|
1207
|
+
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_dictMatchState);
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
size_t ZSTD_compressBlock_btultra_dictMatchState(
|
|
1211
|
+
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
1212
|
+
const void* src, size_t srcSize)
|
|
783
1213
|
{
|
|
784
|
-
return ZSTD_compressBlock_opt_generic(
|
|
1214
|
+
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_dictMatchState);
|
|
785
1215
|
}
|
|
1216
|
+
|
|
1217
|
+
size_t ZSTD_compressBlock_btopt_extDict(
|
|
1218
|
+
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
1219
|
+
const void* src, size_t srcSize)
|
|
1220
|
+
{
|
|
1221
|
+
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_extDict);
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
size_t ZSTD_compressBlock_btultra_extDict(
|
|
1225
|
+
ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
|
|
1226
|
+
const void* src, size_t srcSize)
|
|
1227
|
+
{
|
|
1228
|
+
return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /*optLevel*/, ZSTD_extDict);
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
/* note : no btultra2 variant for extDict nor dictMatchState,
|
|
1232
|
+
* because btultra2 is not meant to work with dictionaries
|
|
1233
|
+
* and is only specific for the first block (no prefix) */
|