extzstd 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
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) */