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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/HISTORY.ja.md +13 -0
  3. data/README.md +17 -14
  4. data/contrib/zstd/{NEWS → CHANGELOG} +115 -2
  5. data/contrib/zstd/CODE_OF_CONDUCT.md +5 -0
  6. data/contrib/zstd/Makefile +99 -53
  7. data/contrib/zstd/README.md +59 -39
  8. data/contrib/zstd/TESTING.md +1 -1
  9. data/contrib/zstd/appveyor.yml +17 -6
  10. data/contrib/zstd/lib/BUCK +29 -2
  11. data/contrib/zstd/lib/Makefile +118 -21
  12. data/contrib/zstd/lib/README.md +84 -44
  13. data/contrib/zstd/lib/common/bitstream.h +17 -33
  14. data/contrib/zstd/lib/common/compiler.h +62 -8
  15. data/contrib/zstd/lib/common/cpu.h +215 -0
  16. data/contrib/zstd/lib/common/debug.c +44 -0
  17. data/contrib/zstd/lib/common/debug.h +134 -0
  18. data/contrib/zstd/lib/common/entropy_common.c +16 -1
  19. data/contrib/zstd/lib/common/error_private.c +7 -0
  20. data/contrib/zstd/lib/common/fse.h +48 -44
  21. data/contrib/zstd/lib/common/fse_decompress.c +3 -3
  22. data/contrib/zstd/lib/common/huf.h +169 -113
  23. data/contrib/zstd/lib/common/mem.h +20 -2
  24. data/contrib/zstd/lib/common/pool.c +135 -49
  25. data/contrib/zstd/lib/common/pool.h +40 -21
  26. data/contrib/zstd/lib/common/threading.c +2 -2
  27. data/contrib/zstd/lib/common/threading.h +12 -12
  28. data/contrib/zstd/lib/common/xxhash.c +3 -2
  29. data/contrib/zstd/lib/common/zstd_common.c +3 -6
  30. data/contrib/zstd/lib/common/zstd_errors.h +17 -7
  31. data/contrib/zstd/lib/common/zstd_internal.h +76 -48
  32. data/contrib/zstd/lib/compress/fse_compress.c +89 -209
  33. data/contrib/zstd/lib/compress/hist.c +203 -0
  34. data/contrib/zstd/lib/compress/hist.h +95 -0
  35. data/contrib/zstd/lib/compress/huf_compress.c +188 -80
  36. data/contrib/zstd/lib/compress/zstd_compress.c +2500 -1203
  37. data/contrib/zstd/lib/compress/zstd_compress_internal.h +463 -62
  38. data/contrib/zstd/lib/compress/zstd_double_fast.c +321 -131
  39. data/contrib/zstd/lib/compress/zstd_double_fast.h +13 -4
  40. data/contrib/zstd/lib/compress/zstd_fast.c +335 -108
  41. data/contrib/zstd/lib/compress/zstd_fast.h +12 -6
  42. data/contrib/zstd/lib/compress/zstd_lazy.c +654 -313
  43. data/contrib/zstd/lib/compress/zstd_lazy.h +44 -16
  44. data/contrib/zstd/lib/compress/zstd_ldm.c +310 -420
  45. data/contrib/zstd/lib/compress/zstd_ldm.h +63 -26
  46. data/contrib/zstd/lib/compress/zstd_opt.c +773 -325
  47. data/contrib/zstd/lib/compress/zstd_opt.h +31 -5
  48. data/contrib/zstd/lib/compress/zstdmt_compress.c +1468 -518
  49. data/contrib/zstd/lib/compress/zstdmt_compress.h +96 -45
  50. data/contrib/zstd/lib/decompress/huf_decompress.c +518 -282
  51. data/contrib/zstd/lib/decompress/zstd_ddict.c +240 -0
  52. data/contrib/zstd/lib/decompress/zstd_ddict.h +44 -0
  53. data/contrib/zstd/lib/decompress/zstd_decompress.c +613 -1513
  54. data/contrib/zstd/lib/decompress/zstd_decompress_block.c +1311 -0
  55. data/contrib/zstd/lib/decompress/zstd_decompress_block.h +59 -0
  56. data/contrib/zstd/lib/decompress/zstd_decompress_internal.h +175 -0
  57. data/contrib/zstd/lib/dictBuilder/cover.c +194 -113
  58. data/contrib/zstd/lib/dictBuilder/cover.h +112 -0
  59. data/contrib/zstd/lib/dictBuilder/divsufsort.c +3 -3
  60. data/contrib/zstd/lib/dictBuilder/fastcover.c +740 -0
  61. data/contrib/zstd/lib/dictBuilder/zdict.c +142 -106
  62. data/contrib/zstd/lib/dictBuilder/zdict.h +115 -49
  63. data/contrib/zstd/lib/legacy/zstd_legacy.h +44 -12
  64. data/contrib/zstd/lib/legacy/zstd_v01.c +41 -10
  65. data/contrib/zstd/lib/legacy/zstd_v01.h +12 -7
  66. data/contrib/zstd/lib/legacy/zstd_v02.c +37 -12
  67. data/contrib/zstd/lib/legacy/zstd_v02.h +12 -7
  68. data/contrib/zstd/lib/legacy/zstd_v03.c +38 -12
  69. data/contrib/zstd/lib/legacy/zstd_v03.h +12 -7
  70. data/contrib/zstd/lib/legacy/zstd_v04.c +55 -174
  71. data/contrib/zstd/lib/legacy/zstd_v04.h +12 -7
  72. data/contrib/zstd/lib/legacy/zstd_v05.c +59 -31
  73. data/contrib/zstd/lib/legacy/zstd_v05.h +12 -7
  74. data/contrib/zstd/lib/legacy/zstd_v06.c +48 -20
  75. data/contrib/zstd/lib/legacy/zstd_v06.h +10 -5
  76. data/contrib/zstd/lib/legacy/zstd_v07.c +62 -29
  77. data/contrib/zstd/lib/legacy/zstd_v07.h +10 -5
  78. data/contrib/zstd/lib/zstd.h +1346 -832
  79. data/ext/extzstd.c +27 -19
  80. data/ext/extzstd_stream.c +20 -4
  81. data/ext/zstd_compress.c +1 -0
  82. data/ext/zstd_decompress.c +4 -0
  83. data/ext/zstd_dictbuilder.c +4 -0
  84. data/ext/zstd_dictbuilder_fastcover.c +5 -0
  85. data/lib/extzstd.rb +52 -220
  86. data/lib/extzstd/version.rb +1 -1
  87. metadata +21 -7
  88. 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 ZSTD_WINDOWLOG_DEFAULTMAX
25
- #define ZSTD_LDM_HASHEVERYLOG_NOTSET 9999
24
+ #define ZSTD_LDM_DEFAULT_WINDOW_LOG ZSTD_WINDOWLOG_LIMIT_DEFAULT
26
25
 
27
- /** ZSTD_compressBlock_ldm_generic() :
26
+ /**
27
+ * ZSTD_ldm_generateSequences():
28
28
  *
29
- * This is a block compressor intended for long distance matching.
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
- * The function searches for matches of length at least
32
- * ldmParams.minMatchLength using a hash table in cctx->ldmState.
33
- * Matches can be at a distance of up to cParams.windowLog.
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
- * Upon finding a match, the unmatched literals are compressed using a
36
- * ZSTD_blockCompressor (depending on the strategy in the compression
37
- * parameters), which stores the matched sequences. The "long distance"
38
- * match is then stored with the remaining literals from the
39
- * ZSTD_blockCompressor. */
40
- size_t ZSTD_compressBlock_ldm(ZSTD_CCtx* cctx, const void* src, size_t srcSize);
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
- size_t ZSTD_ldm_getTableSize(U32 hashLog, U32 bucketSizeLog);
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
- /** ZSTD_ldm_getTableSize() :
53
- * Return prime8bytes^(minMatchLength-1) */
54
- U64 ZSTD_ldm_getHashPower(U32 minMatchLength);
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->hashEveryLog is not set, set it to its default value based on
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
- void ZSTD_ldm_adjustParameters(ldmParams_t* params, U32 windowLog);
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. Also used for matchSum (?) */
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
- static void ZSTD_setLog2Prices(optState_t* optPtr)
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
- optPtr->log2litSum = ZSTD_highbit32(optPtr->litSum+1);
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
- static void ZSTD_rescaleFreqs(optState_t* const optPtr,
34
- const BYTE* const src, size_t const srcSize)
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
- optPtr->staticPrices = 0;
63
+ return (double)price / (BITCOST_MULTIPLIER*8);
64
+ }
65
+ #endif
37
66
 
38
- if (optPtr->litLengthSum == 0) { /* first init */
39
- unsigned u;
40
- if (srcSize <= 1024) optPtr->staticPrices = 1;
67
+ static int ZSTD_compressedLiterals(optState_t const* const optPtr)
68
+ {
69
+ return optPtr->literalCompressionMode != ZSTD_lcm_uncompressed;
70
+ }
41
71
 
42
- assert(optPtr->litFreq!=NULL);
43
- for (u=0; u<=MaxLit; u++)
44
- optPtr->litFreq[u] = 0;
45
- for (u=0; u<srcSize; u++)
46
- optPtr->litFreq[src[u]]++;
47
- optPtr->litSum = 0;
48
- for (u=0; u<=MaxLit; u++) {
49
- optPtr->litFreq[u] = 1 + (optPtr->litFreq[u] >> ZSTD_FREQ_DIV);
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
- for (u=0; u<=MaxLL; u++)
54
- optPtr->litLengthFreq[u] = 1;
55
- optPtr->litLengthSum = MaxLL+1;
56
- for (u=0; u<=MaxML; u++)
57
- optPtr->matchLengthFreq[u] = 1;
58
- optPtr->matchLengthSum = MaxML+1;
59
- for (u=0; u<=MaxOff; u++)
60
- optPtr->offCodeFreq[u] = 1;
61
- optPtr->offCodeSum = (MaxOff+1);
62
-
63
- } else {
64
- unsigned u;
65
-
66
- optPtr->litSum = 0;
67
- for (u=0; u<=MaxLit; u++) {
68
- optPtr->litFreq[u] = 1 + (optPtr->litFreq[u] >> (ZSTD_FREQ_DIV+1));
69
- optPtr->litSum += optPtr->litFreq[u];
70
- }
71
- optPtr->litLengthSum = 0;
72
- for (u=0; u<=MaxLL; u++) {
73
- optPtr->litLengthFreq[u] = 1 + (optPtr->litLengthFreq[u]>>(ZSTD_FREQ_DIV+1));
74
- optPtr->litLengthSum += optPtr->litLengthFreq[u];
75
- }
76
- optPtr->matchLengthSum = 0;
77
- for (u=0; u<=MaxML; u++) {
78
- optPtr->matchLengthFreq[u] = 1 + (optPtr->matchLengthFreq[u]>>ZSTD_FREQ_DIV);
79
- optPtr->matchLengthSum += optPtr->matchLengthFreq[u];
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
- optPtr->offCodeSum = 0;
82
- for (u=0; u<=MaxOff; u++) {
83
- optPtr->offCodeFreq[u] = 1 + (optPtr->offCodeFreq[u]>>ZSTD_FREQ_DIV);
84
- optPtr->offCodeSum += optPtr->offCodeFreq[u];
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
- ZSTD_setLog2Prices(optPtr);
209
+ ZSTD_setBasePrices(optPtr, optLevel);
89
210
  }
90
211
 
91
-
92
212
  /* ZSTD_rawLiteralsCost() :
93
- * cost of literals (only) in given segment (which length can be null)
94
- * does not include cost of literalLength symbol */
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
- /* literals */
102
- { U32 u;
103
- U32 cost = litLength * optPtr->log2litSum;
104
- for (u=0; u < litLength; u++)
105
- cost -= ZSTD_highbit32(optPtr->litFreq[literals[u]]+1);
106
- return cost;
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->staticPrices) return ZSTD_highbit32((U32)litLength+1);
242
+ if (optPtr->priceType == zop_predef) return WEIGHT(litLength, optLevel);
115
243
 
116
- /* literal Length */
244
+ /* dynamic statistics */
117
245
  { U32 const llCode = ZSTD_LLcode(litLength);
118
- U32 const price = LL_bits[llCode] + optPtr->log2litLengthSum - ZSTD_highbit32(optPtr->litLengthFreq[llCode]+1);
119
- return price;
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->staticPrices) return ZSTD_highbit32(litLength+1);
258
+ if (optPtr->priceType >= zop_predef) return WEIGHT(litLength, optLevel);
140
259
 
141
- /* literal Length */
260
+ /* dynamic statistics */
142
261
  { U32 const llCode = ZSTD_LLcode(litLength);
143
- int const contribution = LL_bits[llCode]
144
- + ZSTD_highbit32(optPtr->litLengthFreq[0]+1)
145
- - ZSTD_highbit32(optPtr->litLengthFreq[llCode]+1);
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 ZSTD_getMatchPrice(
171
- U32 const offset, U32 const matchLength,
172
- const optState_t* const optPtr,
173
- int const optLevel)
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->staticPrices) /* fixed scheme, do not use statistics */
181
- return ZSTD_highbit32((U32)mlBase+1) + 16 + offCode;
301
+ if (optPtr->priceType == zop_predef) /* fixed scheme, do not use statistics */
302
+ return WEIGHT(mlBase, optLevel) + ((16 + offCode) * BITCOST_MULTIPLIER);
182
303
 
183
- price = offCode + optPtr->log2offCodeSum - ZSTD_highbit32(optPtr->offCodeFreq[offCode]+1);
184
- if ((optLevel<2) /*static*/ && offCode >= 20) price += (offCode-19)*2; /* handicap for long distance offsets, favor decompression speed */
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->log2matchLengthSum - ZSTD_highbit32(optPtr->matchLengthFreq[mlCode]+1);
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
- { U32 u;
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 (ZSTD_CCtx* const cctx, const BYTE* const ip)
375
+ static U32 ZSTD_insertAndFindFirstIndexHash3 (ZSTD_matchState_t* ms, const BYTE* const ip)
248
376
  {
249
- U32* const hashTable3 = cctx->hashTable3;
250
- U32 const hashLog3 = cctx->hashLog3;
251
- const BYTE* const base = cctx->base;
252
- U32 idx = cctx->nextToUpdate3;
253
- U32 const target = cctx->nextToUpdate3 = (U32)(ip - base);
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
- ZSTD_CCtx* zc,
271
- const BYTE* const ip, const BYTE* const iLimit, int const extDict,
272
- U32 nbCompares, U32 const mls, U32 const sufficient_len,
273
- U32 rep[ZSTD_REP_NUM], U32 const ll0,
274
- ZSTD_match_t* matches, const U32 lengthToBeat)
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 BYTE* const base = zc->base;
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 = zc->appliedParams.cParams.hashLog;
546
+ U32 const hashLog = cParams->hashLog;
279
547
  U32 const minMatch = (mls==3) ? 3 : 4;
280
- U32* const hashTable = zc->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 = zc->chainTable;
284
- U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
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 = zc->dictBase;
288
- U32 const dictLimit = zc->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 = zc->lowLimit;
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(7, "ZSTD_insertBtAndGetAllMatches");
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 = dictBase + repIndex;
599
+ const BYTE* const repMatch = dictMode == ZSTD_dictMatchState ?
600
+ dmsBase + repIndex - dmsIndexDelta :
601
+ dictBase + repIndex;
316
602
  assert(current >= windowLow);
317
- if ( extDict /* this case only valid in extDict mode */
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 rep-match %u of length %u",
326
- repCode - ll0, (U32)repLen);
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 (zc, ip);
339
- if ((matchIndex3 > windowLow)
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 ((!extDict) /*static*/ || (matchIndex3 >= dictLimit)) {
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
- zc->nextToUpdate = current+1; /* skip insertion */
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 > windowLow)) {
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 ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
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) break;
396
- if (ip+matchLength == iLimit) { /* equal : no way to know if inf or sup */
397
- break; /* drop, to preserve bt consistency (miss a little bit of compression) */
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
- zc->nextToUpdate = matchEndIdx - 8; /* skip repetitive patterns */
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
- ZSTD_CCtx* zc, /* Index table will be updated */
426
- const BYTE* ip, const BYTE* const iHighLimit, int const extDict,
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
- DEBUGLOG(7, "ZSTD_BtGetAllMatches");
432
- if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
433
- if (extDict) ZSTD_updateTree_extDict(zc, ip, iHighLimit, maxNbAttempts, matchLengthSearch);
434
- else ZSTD_updateTree(zc, ip, iHighLimit, maxNbAttempts, matchLengthSearch);
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(zc, ip, iHighLimit, extDict, maxNbAttempts, 3, sufficient_len, rep, ll0, matches, lengthToBeat);
775
+ case 3 : return ZSTD_insertBtAndGetAllMatches(ms, ip, iHighLimit, dictMode, rep, ll0, matches, lengthToBeat, 3);
438
776
  default :
439
- case 4 : return ZSTD_insertBtAndGetAllMatches(zc, ip, iHighLimit, extDict, maxNbAttempts, 4, sufficient_len, rep, ll0, matches, lengthToBeat);
440
- case 5 : return ZSTD_insertBtAndGetAllMatches(zc, ip, iHighLimit, extDict, maxNbAttempts, 5, sufficient_len, rep, ll0, matches, lengthToBeat);
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(zc, ip, iHighLimit, extDict, maxNbAttempts, 6, sufficient_len, rep, ll0, matches, lengthToBeat);
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
- typedef struct {
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
- U32 startCost;
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
- static U32 ZSTD_fullLiteralsCost_cached(
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 int ZSTD_literalsContribution_cached(
520
- cachedLiteralPrice_t* const cachedLitPrice,
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 contribution = ZSTD_rawLiteralsCost_cached(cachedLitPrice, anchor, litlen, optStatePtr)
525
- + ZSTD_litLengthContribution(litlen, optStatePtr);
526
- return contribution;
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
- FORCE_INLINE_TEMPLATE
530
- size_t ZSTD_compressBlock_opt_generic(ZSTD_CCtx* ctx,
531
- const void* src, size_t srcSize,
532
- const int optLevel, const int extDict)
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
- seqStore_t* const seqStorePtr = &(ctx->seqStore);
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 = ctx->base;
542
- const BYTE* const prefixStart = base + ctx->dictLimit;
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 maxSearches = 1U << ctx->appliedParams.cParams.searchLog;
545
- U32 const sufficient_len = MIN(ctx->appliedParams.cParams.targetLength, ZSTD_OPT_NUM -1);
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
- cachedLiteralPrice_t cachedLitPrice;
552
- U32 rep[ZSTD_REP_NUM];
859
+ ZSTD_optimal_t lastSequence;
553
860
 
554
861
  /* init */
555
- DEBUGLOG(5, "ZSTD_compressBlock_opt_generic");
556
- ctx->nextToUpdate3 = ctx->nextToUpdate;
557
- ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize);
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(ctx, ip, iend, extDict, maxSearches, mls, sufficient_len, rep, ll0, matches, minMatch);
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 = 1;
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
- DEBUGLOG(7, "found %u matches of maxLength=%u and offset=%u at cPos=%u => start new serie",
581
- nbMatches, maxML, matches[nbMatches-1].off, (U32)(ip-prefixStart));
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
- best_mlen = maxML;
585
- best_off = matches[nbMatches-1].off;
586
- DEBUGLOG(7, "large match (%u>%u), immediate encoding",
587
- best_mlen, sufficient_len);
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 = 1;
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 = ZSTD_fullLiteralsCost_cached(&cachedLitPrice, anchor, litlen, optStatePtr);
903
+ { U32 const literalsPrice = opt[0].price + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
595
904
  U32 pos;
596
905
  U32 matchNb;
597
- for (pos = 0; pos < minMatch; pos++) {
598
- opt[pos].mlen = 1;
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 = literalsPrice + ZSTD_getMatchPrice(offset, pos, optStatePtr, optLevel);
607
- DEBUGLOG(7, "rPos:%u => set initial price : %u",
608
- pos, matchPrice);
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 = matchPrice;
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 == 1) ? opt[cur-1].litlen + 1 : 1;
626
- int price; /* note : contribution can be negative */
627
- if (cur > litlen) {
628
- price = opt[cur - litlen].price + ZSTD_literalsContribution(inr-litlen, litlen, optStatePtr);
629
- } else {
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 (%u<%u) using literal",
635
- cur, price, opt[cur].price);
636
- opt[cur].mlen = 1;
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
- if ( (optLevel==0) /*static*/
649
- && (opt[cur+1].price <= opt[cur].price) )
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 != 1);
653
- U32 const litlen = (opt[cur].mlen == 1) ? opt[cur].litlen : 0;
654
- U32 const previousPrice = (cur > litlen) ? opt[cur-litlen].price : 0;
655
- U32 const basePrice = previousPrice + ZSTD_fullLiteralsCost(inr-litlen, litlen, optStatePtr);
656
- U32 const nbMatches = ZSTD_BtGetAllMatches(ctx, inr, iend, extDict, maxSearches, mls, sufficient_len, opt[cur].rep, ll0, matches, minMatch);
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) continue;
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
- | (cur + maxML >= ZSTD_OPT_NUM) ) {
666
- best_mlen = maxML;
667
- best_off = matches[nbMatches-1].off;
668
- last_pos = cur + 1;
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=%u, mlen=%u, llen=%u",
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 (%u<%u)",
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
- if (optLevel==0) break; /* gets ~+10% speed for about -0.01 ratio loss */
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
- best_mlen = opt[last_pos].mlen;
704
- best_off = opt[last_pos].off;
705
- cur = last_pos - best_mlen;
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 == 1);
709
-
710
- /* reverse traversal */
711
- DEBUGLOG(7, "start reverse traversal (last_pos:%u, cur:%u)",
712
- last_pos, cur);
713
- { U32 selectedMatchLength = best_mlen;
714
- U32 selectedOffset = best_off;
715
- U32 pos = cur;
716
- while (1) {
717
- U32 const mlen = opt[pos].mlen;
718
- U32 const off = opt[pos].off;
719
- opt[pos].mlen = selectedMatchLength;
720
- opt[pos].off = selectedOffset;
721
- selectedMatchLength = mlen;
722
- selectedOffset = off;
723
- if (mlen > pos) break;
724
- pos -= mlen;
725
- } }
726
-
727
- /* save sequences */
728
- { U32 pos;
729
- for (pos=0; pos < last_pos; ) {
730
- U32 const llen = (U32)(ip - anchor);
731
- U32 const mlen = opt[pos].mlen;
732
- U32 const offset = opt[pos].off;
733
- if (mlen == 1) { ip++; pos++; continue; } /* literal position => move on */
734
- pos += mlen; ip += mlen;
735
-
736
- /* repcodes update : like ZSTD_updateRep(), but update in place */
737
- if (offset >= ZSTD_REP_NUM) { /* full offset */
738
- rep[2] = rep[1];
739
- rep[1] = rep[0];
740
- rep[0] = offset - ZSTD_REP_MOVE;
741
- } else { /* repcode */
742
- U32 const repCode = offset + (llen==0);
743
- if (repCode) { /* note : if repCode==0, no change */
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
- ZSTD_updateStats(optStatePtr, llen, anchor, offset, mlen);
752
- ZSTD_storeSeq(seqStorePtr, llen, anchor, offset, mlen-MINMATCH);
753
- anchor = ip;
754
- } }
755
- ZSTD_setLog2Prices(optStatePtr);
756
- } /* while (ip < ilimit) */
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
- /* Save reps for next block */
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(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
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(ctx, src, srcSize, 0 /*optLevel*/, 0 /*extDict*/);
1106
+ return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /*optLevel*/, ZSTD_noDict);
770
1107
  }
771
1108
 
772
- size_t ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1109
+
1110
+ /* used in 2-pass strategy */
1111
+ static U32 ZSTD_upscaleStat(unsigned* table, U32 lastEltIndex, int bonus)
773
1112
  {
774
- return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 2 /*optLevel*/, 0 /*extDict*/);
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
- size_t ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1123
+ /* used in 2-pass strategy */
1124
+ MEM_STATIC void ZSTD_upscaleStats(optState_t* optPtr)
778
1125
  {
779
- return ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0 /*optLevel*/, 1 /*extDict*/);
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
- size_t ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
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(ctx, src, srcSize, 2 /*optLevel*/, 1 /*extDict*/);
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) */