Coverage Report

Created: 2026-02-11 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/zstd/lib/compress/zstd_opt.c
Line
Count
Source
1
/*
2
 * Copyright (c) Meta Platforms, Inc. and affiliates.
3
 * All rights reserved.
4
 *
5
 * This source code is licensed under both the BSD-style license (found in the
6
 * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7
 * in the COPYING file in the root directory of this source tree).
8
 * You may select, at your option, one of the above-listed licenses.
9
 */
10
11
#include "zstd_compress_internal.h"
12
#include "hist.h"
13
#include "zstd_opt.h"
14
15
#if !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) \
16
 || !defined(ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR) \
17
 || !defined(ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR)
18
19
497M
#define ZSTD_LITFREQ_ADD    2   /* scaling factor for litFreq, so that frequencies adapt faster to new stats */
20
1.02G
#define ZSTD_MAX_PRICE     (1<<30)
21
22
157k
#define ZSTD_PREDEF_THRESHOLD 8   /* if srcSize < ZSTD_PREDEF_THRESHOLD, symbols' cost is assumed static, directly determined by pre-defined distributions */
23
24
25
/*-*************************************
26
*  Price functions for optimal parser
27
***************************************/
28
29
#if 0    /* approximation at bit level (for tests) */
30
#  define BITCOST_ACCURACY 0
31
#  define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
32
#  define WEIGHT(stat, opt) ((void)(opt), ZSTD_bitWeight(stat))
33
#elif 0  /* fractional bit accuracy (for tests) */
34
#  define BITCOST_ACCURACY 8
35
#  define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
36
#  define WEIGHT(stat,opt) ((void)(opt), ZSTD_fracWeight(stat))
37
#else    /* opt==approx, ultra==accurate */
38
48.8G
#  define BITCOST_ACCURACY 8
39
35.5G
#  define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
40
14.8G
#  define WEIGHT(stat,opt) ((opt) ? ZSTD_fracWeight(stat) : ZSTD_bitWeight(stat))
41
#endif
42
43
/* ZSTD_bitWeight() :
44
 * provide estimated "cost" of a stat in full bits only */
45
MEM_STATIC U32 ZSTD_bitWeight(U32 stat)
46
1.45G
{
47
1.45G
    return (ZSTD_highbit32(stat+1) * BITCOST_MULTIPLIER);
48
1.45G
}
49
50
/* ZSTD_fracWeight() :
51
 * provide fractional-bit "cost" of a stat,
52
 * using linear interpolation approximation */
53
MEM_STATIC U32 ZSTD_fracWeight(U32 rawStat)
54
13.3G
{
55
13.3G
    U32 const stat = rawStat + 1;
56
13.3G
    U32 const hb = ZSTD_highbit32(stat);
57
13.3G
    U32 const BWeight = hb * BITCOST_MULTIPLIER;
58
    /* Fweight was meant for "Fractional weight"
59
     * but it's effectively a value between 1 and 2
60
     * using fixed point arithmetic */
61
13.3G
    U32 const FWeight = (stat << BITCOST_ACCURACY) >> hb;
62
13.3G
    U32 const weight = BWeight + FWeight;
63
13.3G
    assert(hb + BITCOST_ACCURACY < 31);
64
13.3G
    return weight;
65
13.3G
}
66
67
#if (DEBUGLEVEL>=2)
68
/* debugging function,
69
 * @return price in bytes as fractional value
70
 * for debug messages only */
71
MEM_STATIC double ZSTD_fCost(int price)
72
{
73
    return (double)price / (BITCOST_MULTIPLIER*8);
74
}
75
#endif
76
77
static int ZSTD_compressedLiterals(optState_t const* const optPtr)
78
941M
{
79
941M
    return optPtr->literalCompressionMode != ZSTD_ps_disable;
80
941M
}
81
82
static void ZSTD_setBasePrices(optState_t* optPtr, int optLevel)
83
42.5M
{
84
42.5M
    if (ZSTD_compressedLiterals(optPtr))
85
34.1M
        optPtr->litSumBasePrice = WEIGHT(optPtr->litSum, optLevel);
86
42.5M
    optPtr->litLengthSumBasePrice = WEIGHT(optPtr->litLengthSum, optLevel);
87
42.5M
    optPtr->matchLengthSumBasePrice = WEIGHT(optPtr->matchLengthSum, optLevel);
88
42.5M
    optPtr->offCodeSumBasePrice = WEIGHT(optPtr->offCodeSum, optLevel);
89
42.5M
}
90
91
92
static U32 sum_u32(const unsigned table[], size_t nbElts)
93
2.95M
{
94
2.95M
    size_t n;
95
2.95M
    U32 total = 0;
96
244M
    for (n=0; n<nbElts; n++) {
97
241M
        total += table[n];
98
241M
    }
99
2.95M
    return total;
100
2.95M
}
101
102
typedef enum { base_0possible=0, base_1guaranteed=1 } base_directive_e;
103
104
static U32
105
ZSTD_downscaleStats(unsigned* table, U32 lastEltIndex, U32 shift, base_directive_e base1)
106
218k
{
107
218k
    U32 s, sum=0;
108
218k
    DEBUGLOG(5, "ZSTD_downscaleStats (nbElts=%u, shift=%u)",
109
218k
            (unsigned)lastEltIndex+1, (unsigned)shift );
110
218k
    assert(shift < 30);
111
42.7M
    for (s=0; s<lastEltIndex+1; s++) {
112
42.5M
        unsigned const base = base1 ? 1 : (table[s]>0);
113
42.5M
        unsigned const newStat = base + (table[s] >> shift);
114
42.5M
        sum += newStat;
115
42.5M
        table[s] = newStat;
116
42.5M
    }
117
218k
    return sum;
118
218k
}
119
120
/* ZSTD_scaleStats() :
121
 * reduce all elt frequencies in table if sum too large
122
 * return the resulting sum of elements */
123
static U32 ZSTD_scaleStats(unsigned* table, U32 lastEltIndex, U32 logTarget)
124
2.76M
{
125
2.76M
    U32 const prevsum = sum_u32(table, lastEltIndex+1);
126
2.76M
    U32 const factor = prevsum >> logTarget;
127
2.76M
    DEBUGLOG(5, "ZSTD_scaleStats (nbElts=%u, target=%u)", (unsigned)lastEltIndex+1, (unsigned)logTarget);
128
2.76M
    assert(logTarget < 30);
129
2.76M
    if (factor <= 1) return prevsum;
130
130k
    return ZSTD_downscaleStats(table, lastEltIndex, ZSTD_highbit32(factor), base_1guaranteed);
131
2.76M
}
132
133
/* ZSTD_rescaleFreqs() :
134
 * if first block (detected by optPtr->litLengthSum == 0) : init statistics
135
 *    take hints from dictionary if there is one
136
 *    and init from zero if there is none,
137
 *    using src for literals stats, and baseline stats for sequence symbols
138
 * otherwise downscale existing stats, to be used as seed for next block.
139
 */
140
static void
141
ZSTD_rescaleFreqs(optState_t* const optPtr,
142
            const BYTE* const src, size_t const srcSize,
143
                  int const optLevel)
144
851k
{
145
851k
    int const compressedLiterals = ZSTD_compressedLiterals(optPtr);
146
851k
    DEBUGLOG(5, "ZSTD_rescaleFreqs (srcSize=%u)", (unsigned)srcSize);
147
851k
    optPtr->priceType = zop_dynamic;
148
149
851k
    if (optPtr->litLengthSum == 0) {  /* no literals stats collected -> first block assumed -> init */
150
151
        /* heuristic: use pre-defined stats for too small inputs */
152
122k
        if (srcSize <= ZSTD_PREDEF_THRESHOLD) {
153
3.75k
            DEBUGLOG(5, "srcSize <= %i : use predefined stats", ZSTD_PREDEF_THRESHOLD);
154
3.75k
            optPtr->priceType = zop_predef;
155
3.75k
        }
156
157
122k
        assert(optPtr->symbolCosts != NULL);
158
122k
        if (optPtr->symbolCosts->huf.repeatMode == HUF_repeat_valid) {
159
160
            /* huffman stats covering the full value set : table presumed generated by dictionary */
161
25.0k
            optPtr->priceType = zop_dynamic;
162
163
25.0k
            if (compressedLiterals) {
164
                /* generate literals statistics from huffman table */
165
23.0k
                unsigned lit;
166
23.0k
                assert(optPtr->litFreq != NULL);
167
23.0k
                optPtr->litSum = 0;
168
5.91M
                for (lit=0; lit<=MaxLit; lit++) {
169
5.89M
                    U32 const scaleLog = 11;   /* scale to 2K */
170
5.89M
                    U32 const bitCost = HUF_getNbBitsFromCTable(optPtr->symbolCosts->huf.CTable, lit);
171
5.89M
                    assert(bitCost <= scaleLog);
172
5.89M
                    optPtr->litFreq[lit] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
173
5.89M
                    optPtr->litSum += optPtr->litFreq[lit];
174
5.89M
            }   }
175
176
25.0k
            {   unsigned ll;
177
25.0k
                FSE_CState_t llstate;
178
25.0k
                FSE_initCState(&llstate, optPtr->symbolCosts->fse.litlengthCTable);
179
25.0k
                optPtr->litLengthSum = 0;
180
925k
                for (ll=0; ll<=MaxLL; ll++) {
181
900k
                    U32 const scaleLog = 10;   /* scale to 1K */
182
900k
                    U32 const bitCost = FSE_getMaxNbBits(llstate.symbolTT, ll);
183
900k
                    assert(bitCost < scaleLog);
184
900k
                    optPtr->litLengthFreq[ll] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
185
900k
                    optPtr->litLengthSum += optPtr->litLengthFreq[ll];
186
900k
            }   }
187
188
25.0k
            {   unsigned ml;
189
25.0k
                FSE_CState_t mlstate;
190
25.0k
                FSE_initCState(&mlstate, optPtr->symbolCosts->fse.matchlengthCTable);
191
25.0k
                optPtr->matchLengthSum = 0;
192
1.35M
                for (ml=0; ml<=MaxML; ml++) {
193
1.32M
                    U32 const scaleLog = 10;
194
1.32M
                    U32 const bitCost = FSE_getMaxNbBits(mlstate.symbolTT, ml);
195
1.32M
                    assert(bitCost < scaleLog);
196
1.32M
                    optPtr->matchLengthFreq[ml] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
197
1.32M
                    optPtr->matchLengthSum += optPtr->matchLengthFreq[ml];
198
1.32M
            }   }
199
200
25.0k
            {   unsigned of;
201
25.0k
                FSE_CState_t ofstate;
202
25.0k
                FSE_initCState(&ofstate, optPtr->symbolCosts->fse.offcodeCTable);
203
25.0k
                optPtr->offCodeSum = 0;
204
825k
                for (of=0; of<=MaxOff; of++) {
205
800k
                    U32 const scaleLog = 10;
206
800k
                    U32 const bitCost = FSE_getMaxNbBits(ofstate.symbolTT, of);
207
800k
                    assert(bitCost < scaleLog);
208
800k
                    optPtr->offCodeFreq[of] = bitCost ? 1 << (scaleLog-bitCost) : 1 /*minimum to calculate cost*/;
209
800k
                    optPtr->offCodeSum += optPtr->offCodeFreq[of];
210
800k
            }   }
211
212
97.8k
        } else {  /* first block, no dictionary */
213
214
97.8k
            assert(optPtr->litFreq != NULL);
215
97.8k
            if (compressedLiterals) {
216
                /* base initial cost of literals on direct frequency within src */
217
88.1k
                unsigned lit = MaxLit;
218
88.1k
                HIST_count_simple(optPtr->litFreq, &lit, src, srcSize);   /* use raw first block to init statistics */
219
88.1k
                optPtr->litSum = ZSTD_downscaleStats(optPtr->litFreq, MaxLit, 8, base_0possible);
220
88.1k
            }
221
222
97.8k
            {   unsigned const baseLLfreqs[MaxLL+1] = {
223
97.8k
                    4, 2, 1, 1, 1, 1, 1, 1,
224
97.8k
                    1, 1, 1, 1, 1, 1, 1, 1,
225
97.8k
                    1, 1, 1, 1, 1, 1, 1, 1,
226
97.8k
                    1, 1, 1, 1, 1, 1, 1, 1,
227
97.8k
                    1, 1, 1, 1
228
97.8k
                };
229
97.8k
                ZSTD_memcpy(optPtr->litLengthFreq, baseLLfreqs, sizeof(baseLLfreqs));
230
97.8k
                optPtr->litLengthSum = sum_u32(baseLLfreqs, MaxLL+1);
231
97.8k
            }
232
233
97.8k
            {   unsigned ml;
234
5.28M
                for (ml=0; ml<=MaxML; ml++)
235
5.18M
                    optPtr->matchLengthFreq[ml] = 1;
236
97.8k
            }
237
97.8k
            optPtr->matchLengthSum = MaxML+1;
238
239
97.8k
            {   unsigned const baseOFCfreqs[MaxOff+1] = {
240
97.8k
                    6, 2, 1, 1, 2, 3, 4, 4,
241
97.8k
                    4, 3, 2, 1, 1, 1, 1, 1,
242
97.8k
                    1, 1, 1, 1, 1, 1, 1, 1,
243
97.8k
                    1, 1, 1, 1, 1, 1, 1, 1
244
97.8k
                };
245
97.8k
                ZSTD_memcpy(optPtr->offCodeFreq, baseOFCfreqs, sizeof(baseOFCfreqs));
246
97.8k
                optPtr->offCodeSum = sum_u32(baseOFCfreqs, MaxOff+1);
247
97.8k
            }
248
249
97.8k
        }
250
251
729k
    } else {   /* new block : scale down accumulated statistics */
252
253
729k
        if (compressedLiterals)
254
573k
            optPtr->litSum = ZSTD_scaleStats(optPtr->litFreq, MaxLit, 12);
255
729k
        optPtr->litLengthSum = ZSTD_scaleStats(optPtr->litLengthFreq, MaxLL, 11);
256
729k
        optPtr->matchLengthSum = ZSTD_scaleStats(optPtr->matchLengthFreq, MaxML, 11);
257
729k
        optPtr->offCodeSum = ZSTD_scaleStats(optPtr->offCodeFreq, MaxOff, 11);
258
729k
    }
259
260
851k
    ZSTD_setBasePrices(optPtr, optLevel);
261
851k
}
262
263
/* ZSTD_rawLiteralsCost() :
264
 * price of literals (only) in specified segment (which length can be 0).
265
 * does not include price of literalLength symbol */
266
static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength,
267
                                const optState_t* const optPtr,
268
                                int optLevel)
269
802M
{
270
802M
    DEBUGLOG(8, "ZSTD_rawLiteralsCost (%u literals)", litLength);
271
802M
    if (litLength == 0) return 0;
272
273
802M
    if (!ZSTD_compressedLiterals(optPtr))
274
109M
        return (litLength << 3) * BITCOST_MULTIPLIER;  /* Uncompressed - 8 bytes per literal. */
275
276
692M
    if (optPtr->priceType == zop_predef)
277
0
        return (litLength*6) * BITCOST_MULTIPLIER;  /* 6 bit per literal - no statistic used */
278
279
    /* dynamic statistics */
280
692M
    {   U32 price = optPtr->litSumBasePrice * litLength;
281
692M
        U32 const litPriceMax = optPtr->litSumBasePrice - BITCOST_MULTIPLIER;
282
692M
        U32 u;
283
692M
        assert(optPtr->litSumBasePrice >= BITCOST_MULTIPLIER);
284
1.38G
        for (u=0; u < litLength; u++) {
285
692M
            U32 litPrice = WEIGHT(optPtr->litFreq[literals[u]], optLevel);
286
692M
            if (UNLIKELY(litPrice > litPriceMax)) litPrice = litPriceMax;
287
692M
            price -= litPrice;
288
692M
        }
289
692M
        return price;
290
692M
    }
291
692M
}
292
293
/* ZSTD_litLengthPrice() :
294
 * cost of literalLength symbol */
295
static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optPtr, int optLevel)
296
2.57G
{
297
2.57G
    assert(litLength <= ZSTD_BLOCKSIZE_MAX);
298
2.57G
    if (optPtr->priceType == zop_predef)
299
0
        return WEIGHT(litLength, optLevel);
300
301
    /* ZSTD_LLcode() can't compute litLength price for sizes >= ZSTD_BLOCKSIZE_MAX
302
     * because it isn't representable in the zstd format.
303
     * So instead just pretend it would cost 1 bit more than ZSTD_BLOCKSIZE_MAX - 1.
304
     * In such a case, the block would be all literals.
305
     */
306
2.57G
    if (litLength == ZSTD_BLOCKSIZE_MAX)
307
0
        return BITCOST_MULTIPLIER + ZSTD_litLengthPrice(ZSTD_BLOCKSIZE_MAX - 1, optPtr, optLevel);
308
309
    /* dynamic statistics */
310
2.57G
    {   U32 const llCode = ZSTD_LLcode(litLength);
311
2.57G
        return (LL_bits[llCode] * BITCOST_MULTIPLIER)
312
2.57G
             + optPtr->litLengthSumBasePrice
313
2.57G
             - WEIGHT(optPtr->litLengthFreq[llCode], optLevel);
314
2.57G
    }
315
2.57G
}
316
317
/* ZSTD_getMatchPrice() :
318
 * Provides the cost of the match part (offset + matchLength) of a sequence.
319
 * Must be combined with ZSTD_fullLiteralsCost() to get the full cost of a sequence.
320
 * @offBase : sumtype, representing an offset or a repcode, and using numeric representation of ZSTD_storeSeq()
321
 * @optLevel: when <2, favors small offset for decompression speed (improved cache efficiency)
322
 */
323
FORCE_INLINE_TEMPLATE U32
324
ZSTD_getMatchPrice(U32 const offBase,
325
                   U32 const matchLength,
326
             const optState_t* const optPtr,
327
                   int const optLevel)
328
5.70G
{
329
5.70G
    U32 price;
330
5.70G
    U32 const offCode = ZSTD_highbit32(offBase);
331
5.70G
    U32 const mlBase = matchLength - MINMATCH;
332
5.70G
    assert(matchLength >= MINMATCH);
333
334
5.70G
    if (optPtr->priceType == zop_predef)  /* fixed scheme, does not use statistics */
335
0
        return WEIGHT(mlBase, optLevel)
336
0
             + ((16 + offCode) * BITCOST_MULTIPLIER); /* emulated offset cost */
337
338
    /* dynamic statistics */
339
5.70G
    price = (offCode * BITCOST_MULTIPLIER) + (optPtr->offCodeSumBasePrice - WEIGHT(optPtr->offCodeFreq[offCode], optLevel));
340
5.70G
    if ((optLevel<2) /*static*/ && offCode >= 20)
341
44
        price += (offCode-19)*2 * BITCOST_MULTIPLIER; /* handicap for long distance offsets, favor decompression speed */
342
343
    /* match Length */
344
5.70G
    {   U32 const mlCode = ZSTD_MLcode(mlBase);
345
5.70G
        price += (ML_bits[mlCode] * BITCOST_MULTIPLIER) + (optPtr->matchLengthSumBasePrice - WEIGHT(optPtr->matchLengthFreq[mlCode], optLevel));
346
5.70G
    }
347
348
5.70G
    price += BITCOST_MULTIPLIER / 5;   /* heuristic : make matches a bit more costly to favor less sequences -> faster decompression speed */
349
350
5.70G
    DEBUGLOG(8, "ZSTD_getMatchPrice(ml:%u) = %u", matchLength, price);
351
5.70G
    return price;
352
5.70G
}
353
354
/* ZSTD_updateStats() :
355
 * assumption : literals + litLength <= iend */
356
static void ZSTD_updateStats(optState_t* const optPtr,
357
                             U32 litLength, const BYTE* literals,
358
                             U32 offBase, U32 matchLength)
359
95.7M
{
360
    /* literals */
361
95.7M
    if (ZSTD_compressedLiterals(optPtr)) {
362
79.2M
        U32 u;
363
497M
        for (u=0; u < litLength; u++)
364
418M
            optPtr->litFreq[literals[u]] += ZSTD_LITFREQ_ADD;
365
79.2M
        optPtr->litSum += litLength*ZSTD_LITFREQ_ADD;
366
79.2M
    }
367
368
    /* literal Length */
369
95.7M
    {   U32 const llCode = ZSTD_LLcode(litLength);
370
95.7M
        optPtr->litLengthFreq[llCode]++;
371
95.7M
        optPtr->litLengthSum++;
372
95.7M
    }
373
374
    /* offset code : follows storeSeq() numeric representation */
375
95.7M
    {   U32 const offCode = ZSTD_highbit32(offBase);
376
95.7M
        assert(offCode <= MaxOff);
377
95.7M
        optPtr->offCodeFreq[offCode]++;
378
95.7M
        optPtr->offCodeSum++;
379
95.7M
    }
380
381
    /* match Length */
382
95.7M
    {   U32 const mlBase = matchLength - MINMATCH;
383
95.7M
        U32 const mlCode = ZSTD_MLcode(mlBase);
384
95.7M
        optPtr->matchLengthFreq[mlCode]++;
385
95.7M
        optPtr->matchLengthSum++;
386
95.7M
    }
387
95.7M
}
388
389
390
/* ZSTD_readMINMATCH() :
391
 * function safe only for comparisons
392
 * assumption : memPtr must be at least 4 bytes before end of buffer */
393
MEM_STATIC U32 ZSTD_readMINMATCH(const void* memPtr, U32 length)
394
6.30G
{
395
6.30G
    switch (length)
396
6.30G
    {
397
0
    default :
398
2.91G
    case 4 : return MEM_read32(memPtr);
399
3.39G
    case 3 : if (MEM_isLittleEndian())
400
3.39G
                return MEM_read32(memPtr)<<8;
401
18.4E
             else
402
18.4E
                return MEM_read32(memPtr)>>8;
403
6.30G
    }
404
6.30G
}
405
406
407
/* Update hashTable3 up to ip (excluded)
408
   Assumption : always within prefix (i.e. not within extDict) */
409
static
410
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
411
U32 ZSTD_insertAndFindFirstIndexHash3 (const ZSTD_MatchState_t* ms,
412
                                       U32* nextToUpdate3,
413
                                       const BYTE* const ip)
414
432M
{
415
432M
    U32* const hashTable3 = ms->hashTable3;
416
432M
    U32 const hashLog3 = ms->hashLog3;
417
432M
    const BYTE* const base = ms->window.base;
418
432M
    U32 idx = *nextToUpdate3;
419
432M
    U32 const target = (U32)(ip - base);
420
432M
    size_t const hash3 = ZSTD_hash3Ptr(ip, hashLog3);
421
432M
    assert(hashLog3 > 0);
422
423
1.36G
    while(idx < target) {
424
929M
        hashTable3[ZSTD_hash3Ptr(base+idx, hashLog3)] = idx;
425
929M
        idx++;
426
929M
    }
427
428
433M
    *nextToUpdate3 = target;
429
433M
    return hashTable3[hash3];
430
432M
}
431
432
433
/*-*************************************
434
*  Binary Tree search
435
***************************************/
436
/** ZSTD_insertBt1() : add one or multiple positions to tree.
437
 * @param ip assumed <= iend-8 .
438
 * @param target The target of ZSTD_updateTree_internal() - we are filling to this position
439
 * @return : nb of positions added */
440
static
441
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
442
U32 ZSTD_insertBt1(
443
                const ZSTD_MatchState_t* ms,
444
                const BYTE* const ip, const BYTE* const iend,
445
                U32 const target,
446
                U32 const mls, const int extDict)
447
309M
{
448
309M
    const ZSTD_compressionParameters* const cParams = &ms->cParams;
449
309M
    U32*   const hashTable = ms->hashTable;
450
309M
    U32    const hashLog = cParams->hashLog;
451
309M
    size_t const h  = ZSTD_hashPtr(ip, hashLog, mls);
452
309M
    U32*   const bt = ms->chainTable;
453
309M
    U32    const btLog  = cParams->chainLog - 1;
454
309M
    U32    const btMask = (1 << btLog) - 1;
455
309M
    U32 matchIndex = hashTable[h];
456
309M
    size_t commonLengthSmaller=0, commonLengthLarger=0;
457
309M
    const BYTE* const base = ms->window.base;
458
309M
    const BYTE* const dictBase = ms->window.dictBase;
459
309M
    const U32 dictLimit = ms->window.dictLimit;
460
309M
    const BYTE* const dictEnd = dictBase + dictLimit;
461
309M
    const BYTE* const prefixStart = base + dictLimit;
462
309M
    const BYTE* match;
463
309M
    const U32 curr = (U32)(ip-base);
464
309M
    const U32 btLow = btMask >= curr ? 0 : curr - btMask;
465
309M
    U32* smallerPtr = bt + 2*(curr&btMask);
466
309M
    U32* largerPtr  = smallerPtr + 1;
467
309M
    U32 dummy32;   /* to be nullified at the end */
468
    /* windowLow is based on target because
469
     * we only need positions that will be in the window at the end of the tree update.
470
     */
471
309M
    U32 const windowLow = ZSTD_getLowestMatchIndex(ms, target, cParams->windowLog);
472
309M
    U32 matchEndIdx = curr+8+1;
473
309M
    size_t bestLength = 8;
474
309M
    U32 nbCompares = 1U << cParams->searchLog;
475
#ifdef ZSTD_C_PREDICT
476
    U32 predictedSmall = *(bt + 2*((curr-1)&btMask) + 0);
477
    U32 predictedLarge = *(bt + 2*((curr-1)&btMask) + 1);
478
    predictedSmall += (predictedSmall>0);
479
    predictedLarge += (predictedLarge>0);
480
#endif /* ZSTD_C_PREDICT */
481
482
309M
    DEBUGLOG(8, "ZSTD_insertBt1 (%u)", curr);
483
484
309M
    assert(curr <= target);
485
309M
    assert(ip <= iend-8);   /* required for h calculation */
486
309M
    hashTable[h] = curr;   /* Update Hash Table */
487
488
309M
    assert(windowLow > 0);
489
1.53G
    for (; nbCompares && (matchIndex >= windowLow); --nbCompares) {
490
1.33G
        U32* const nextPtr = bt + 2*(matchIndex & btMask);
491
1.33G
        size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
492
1.33G
        assert(matchIndex < curr);
493
494
#ifdef ZSTD_C_PREDICT   /* note : can create issues when hlog small <= 11 */
495
        const U32* predictPtr = bt + 2*((matchIndex-1) & btMask);   /* written this way, as bt is a roll buffer */
496
        if (matchIndex == predictedSmall) {
497
            /* no need to check length, result known */
498
            *smallerPtr = matchIndex;
499
            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
500
            smallerPtr = nextPtr+1;               /* new "smaller" => larger of match */
501
            matchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */
502
            predictedSmall = predictPtr[1] + (predictPtr[1]>0);
503
            continue;
504
        }
505
        if (matchIndex == predictedLarge) {
506
            *largerPtr = matchIndex;
507
            if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
508
            largerPtr = nextPtr;
509
            matchIndex = nextPtr[0];
510
            predictedLarge = predictPtr[0] + (predictPtr[0]>0);
511
            continue;
512
        }
513
#endif
514
515
1.33G
        if (!extDict || (matchIndex+matchLength >= dictLimit)) {
516
1.31G
            assert(matchIndex+matchLength >= dictLimit);   /* might be wrong if actually extDict */
517
1.31G
            match = base + matchIndex;
518
1.31G
            matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
519
1.31G
        } else {
520
12.3M
            match = dictBase + matchIndex;
521
12.3M
            matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
522
12.3M
            if (matchIndex+matchLength >= dictLimit)
523
75.4k
                match = base + matchIndex;   /* to prepare for next usage of match[matchLength] */
524
12.3M
        }
525
526
1.33G
        if (matchLength > bestLength) {
527
227M
            bestLength = matchLength;
528
227M
            if (matchLength > matchEndIdx - matchIndex)
529
5.90M
                matchEndIdx = matchIndex + (U32)matchLength;
530
227M
        }
531
532
1.33G
        if (ip+matchLength == iend) {   /* equal : no way to know if inf or sup */
533
840k
            break;   /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt tree */
534
840k
        }
535
536
1.32G
        if (match[matchLength] < ip[matchLength]) {  /* necessarily within buffer */
537
            /* match is smaller than current */
538
443M
            *smallerPtr = matchIndex;             /* update smaller idx */
539
443M
            commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */
540
443M
            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop searching */
541
394M
            smallerPtr = nextPtr+1;               /* new "candidate" => larger than match, which was smaller than target */
542
394M
            matchIndex = nextPtr[1];              /* new matchIndex, larger than previous and closer to current */
543
886M
        } else {
544
            /* match is larger than current */
545
886M
            *largerPtr = matchIndex;
546
886M
            commonLengthLarger = matchLength;
547
886M
            if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop searching */
548
836M
            largerPtr = nextPtr;
549
836M
            matchIndex = nextPtr[0];
550
836M
    }   }
551
552
309M
    *smallerPtr = *largerPtr = 0;
553
309M
    {   U32 positions = 0;
554
309M
        if (bestLength > 384) positions = MIN(192, (U32)(bestLength - 384));   /* speed optimization */
555
309M
        assert(matchEndIdx > curr + 8);
556
309M
        return MAX(positions, matchEndIdx - (curr + 8));
557
309M
    }
558
309M
}
559
560
FORCE_INLINE_TEMPLATE
561
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
562
void ZSTD_updateTree_internal(
563
                ZSTD_MatchState_t* ms,
564
                const BYTE* const ip, const BYTE* const iend,
565
                const U32 mls, const ZSTD_dictMode_e dictMode)
566
1.07G
{
567
1.07G
    const BYTE* const base = ms->window.base;
568
1.07G
    U32 const target = (U32)(ip - base);
569
1.07G
    U32 idx = ms->nextToUpdate;
570
1.07G
    DEBUGLOG(7, "ZSTD_updateTree_internal, from %u to %u  (dictMode:%u)",
571
1.07G
                idx, target, dictMode);
572
573
1.38G
    while(idx < target) {
574
309M
        U32 const forward = ZSTD_insertBt1(ms, base+idx, iend, target, mls, dictMode == ZSTD_extDict);
575
309M
        assert(idx < (U32)(idx + forward));
576
309M
        idx += forward;
577
309M
    }
578
1.07G
    assert((size_t)(ip - base) <= (size_t)(U32)(-1));
579
1.07G
    assert((size_t)(iend - base) <= (size_t)(U32)(-1));
580
1.07G
    ms->nextToUpdate = target;
581
1.07G
}
582
583
63.0k
void ZSTD_updateTree(ZSTD_MatchState_t* ms, const BYTE* ip, const BYTE* iend) {
584
63.0k
    ZSTD_updateTree_internal(ms, ip, iend, ms->cParams.minMatch, ZSTD_noDict);
585
63.0k
}
586
587
FORCE_INLINE_TEMPLATE
588
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
589
U32
590
ZSTD_insertBtAndGetAllMatches (
591
                ZSTD_match_t* matches,  /* store result (found matches) in this table (presumed large enough) */
592
                ZSTD_MatchState_t* ms,
593
                U32* nextToUpdate3,
594
                const BYTE* const ip, const BYTE* const iLimit,
595
                const ZSTD_dictMode_e dictMode,
596
                const U32 rep[ZSTD_REP_NUM],
597
                const U32 ll0,  /* tells if associated literal length is 0 or not. This value must be 0 or 1 */
598
                const U32 lengthToBeat,
599
                const U32 mls /* template */)
600
1.07G
{
601
1.07G
    const ZSTD_compressionParameters* const cParams = &ms->cParams;
602
1.07G
    U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
603
1.07G
    const BYTE* const base = ms->window.base;
604
1.07G
    U32 const curr = (U32)(ip-base);
605
1.07G
    U32 const hashLog = cParams->hashLog;
606
1.07G
    U32 const minMatch = (mls==3) ? 3 : 4;
607
1.07G
    U32* const hashTable = ms->hashTable;
608
1.07G
    size_t const h  = ZSTD_hashPtr(ip, hashLog, mls);
609
1.07G
    U32 matchIndex  = hashTable[h];
610
1.07G
    U32* const bt   = ms->chainTable;
611
1.07G
    U32 const btLog = cParams->chainLog - 1;
612
1.07G
    U32 const btMask= (1U << btLog) - 1;
613
1.07G
    size_t commonLengthSmaller=0, commonLengthLarger=0;
614
1.07G
    const BYTE* const dictBase = ms->window.dictBase;
615
1.07G
    U32 const dictLimit = ms->window.dictLimit;
616
1.07G
    const BYTE* const dictEnd = dictBase + dictLimit;
617
1.07G
    const BYTE* const prefixStart = base + dictLimit;
618
1.07G
    U32 const btLow = (btMask >= curr) ? 0 : curr - btMask;
619
1.07G
    U32 const windowLow = ZSTD_getLowestMatchIndex(ms, curr, cParams->windowLog);
620
18.4E
    U32 const matchLow = windowLow ? windowLow : 1;
621
1.07G
    U32* smallerPtr = bt + 2*(curr&btMask);
622
1.07G
    U32* largerPtr  = bt + 2*(curr&btMask) + 1;
623
1.07G
    U32 matchEndIdx = curr+8+1;   /* farthest referenced position of any match => detects repetitive patterns */
624
1.07G
    U32 dummy32;   /* to be nullified at the end */
625
1.07G
    U32 mnum = 0;
626
1.07G
    U32 nbCompares = 1U << cParams->searchLog;
627
628
1.07G
    const ZSTD_MatchState_t* dms    = dictMode == ZSTD_dictMatchState ? ms->dictMatchState : NULL;
629
1.07G
    const ZSTD_compressionParameters* const dmsCParams =
630
1.07G
                                      dictMode == ZSTD_dictMatchState ? &dms->cParams : NULL;
631
1.07G
    const BYTE* const dmsBase       = dictMode == ZSTD_dictMatchState ? dms->window.base : NULL;
632
1.07G
    const BYTE* const dmsEnd        = dictMode == ZSTD_dictMatchState ? dms->window.nextSrc : NULL;
633
1.07G
    U32         const dmsHighLimit  = dictMode == ZSTD_dictMatchState ? (U32)(dmsEnd - dmsBase) : 0;
634
1.07G
    U32         const dmsLowLimit   = dictMode == ZSTD_dictMatchState ? dms->window.lowLimit : 0;
635
1.07G
    U32         const dmsIndexDelta = dictMode == ZSTD_dictMatchState ? windowLow - dmsHighLimit : 0;
636
1.07G
    U32         const dmsHashLog    = dictMode == ZSTD_dictMatchState ? dmsCParams->hashLog : hashLog;
637
1.07G
    U32         const dmsBtLog      = dictMode == ZSTD_dictMatchState ? dmsCParams->chainLog - 1 : btLog;
638
1.07G
    U32         const dmsBtMask     = dictMode == ZSTD_dictMatchState ? (1U << dmsBtLog) - 1 : 0;
639
1.07G
    U32         const dmsBtLow      = dictMode == ZSTD_dictMatchState && dmsBtMask < dmsHighLimit - dmsLowLimit ? dmsHighLimit - dmsBtMask : dmsLowLimit;
640
641
1.07G
    size_t bestLength = lengthToBeat-1;
642
1.07G
    DEBUGLOG(8, "ZSTD_insertBtAndGetAllMatches: current=%u", curr);
643
644
    /* check repCode */
645
1.07G
    assert(ll0 <= 1);   /* necessarily 1 or 0 */
646
1.07G
    {   U32 const lastR = ZSTD_REP_NUM + ll0;
647
1.07G
        U32 repCode;
648
4.28G
        for (repCode = ll0; repCode < lastR; repCode++) {
649
3.20G
            U32 const repOffset = (repCode==ZSTD_REP_NUM) ? (rep[0] - 1) : rep[repCode];
650
3.20G
            U32 const repIndex = curr - repOffset;
651
3.20G
            U32 repLen = 0;
652
3.20G
            assert(curr >= dictLimit);
653
3.20G
            if (repOffset-1 /* intentional overflow, discards 0 and -1 */ < curr-dictLimit) {  /* equivalent to `curr > repIndex >= dictLimit` */
654
                /* We must validate the repcode offset because when we're using a dictionary the
655
                 * valid offset range shrinks when the dictionary goes out of bounds.
656
                 */
657
3.09G
                if ((repIndex >= windowLow) & (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(ip - repOffset, minMatch))) {
658
312M
                    repLen = (U32)ZSTD_count(ip+minMatch, ip+minMatch-repOffset, iLimit) + minMatch;
659
312M
                }
660
3.09G
            } else {  /* repIndex < dictLimit || repIndex >= curr */
661
113M
                const BYTE* const repMatch = dictMode == ZSTD_dictMatchState ?
662
3.28M
                                             dmsBase + repIndex - dmsIndexDelta :
663
113M
                                             dictBase + repIndex;
664
113M
                assert(curr >= windowLow);
665
115M
                if ( dictMode == ZSTD_extDict
666
71.4M
                  && ( ((repOffset-1) /*intentional overflow*/ < curr - windowLow)  /* equivalent to `curr > repIndex >= windowLow` */
667
71.4M
                     & (ZSTD_index_overlap_check(dictLimit, repIndex)) )
668
69.1M
                  && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
669
1.14M
                    repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dictEnd, prefixStart) + minMatch;
670
1.14M
                }
671
115M
                if (dictMode == ZSTD_dictMatchState
672
3.28M
                  && ( ((repOffset-1) /*intentional overflow*/ < curr - (dmsLowLimit + dmsIndexDelta))  /* equivalent to `curr > repIndex >= dmsLowLimit` */
673
3.28M
                     & (ZSTD_index_overlap_check(dictLimit, repIndex)) )
674
2.84M
                  && (ZSTD_readMINMATCH(ip, minMatch) == ZSTD_readMINMATCH(repMatch, minMatch)) ) {
675
171k
                    repLen = (U32)ZSTD_count_2segments(ip+minMatch, repMatch+minMatch, iLimit, dmsEnd, prefixStart) + minMatch;
676
171k
            }   }
677
            /* save longer solution */
678
3.20G
            if (repLen > bestLength) {
679
227M
                DEBUGLOG(8, "found repCode %u (ll0:%u, offset:%u) of length %u",
680
227M
                            repCode, ll0, repOffset, repLen);
681
227M
                bestLength = repLen;
682
455M
                matches[mnum].off = REPCODE_TO_OFFBASE(repCode - ll0 + 1);  /* expect value between 1 and 3 */
683
455M
                matches[mnum].len = (U32)repLen;
684
455M
                mnum++;
685
455M
                if ( (repLen > sufficient_len)
686
227M
                   | (ip+repLen == iLimit) ) {  /* best possible */
687
3.07M
                    return mnum;
688
3.07M
    }   }   }   }
689
690
    /* HC3 match finder */
691
1.07G
    if ((mls == 3) /*static*/ && (bestLength < mls)) {
692
432M
        U32 const matchIndex3 = ZSTD_insertAndFindFirstIndexHash3(ms, nextToUpdate3, ip);
693
432M
        if ((matchIndex3 >= matchLow)
694
432M
          & (curr - matchIndex3 < (1<<18)) /*heuristic : longer distance likely too expensive*/ ) {
695
276M
            size_t mlen;
696
276M
            if ((dictMode == ZSTD_noDict) /*static*/ || (dictMode == ZSTD_dictMatchState) /*static*/ || (matchIndex3 >= dictLimit)) {
697
274M
                const BYTE* const match = base + matchIndex3;
698
274M
                mlen = ZSTD_count(ip, match, iLimit);
699
274M
            } else {
700
1.81M
                const BYTE* const match = dictBase + matchIndex3;
701
1.81M
                mlen = ZSTD_count_2segments(ip, match, iLimit, dictEnd, prefixStart);
702
1.81M
            }
703
704
            /* save best solution */
705
276M
            if (mlen >= mls /* == 3 > bestLength */) {
706
182M
                DEBUGLOG(8, "found small match with hlog3, of length %u",
707
182M
                            (U32)mlen);
708
182M
                bestLength = mlen;
709
182M
                assert(curr > matchIndex3);
710
182M
                assert(mnum==0);  /* no prior solution */
711
182M
                matches[0].off = OFFSET_TO_OFFBASE(curr - matchIndex3);
712
182M
                matches[0].len = (U32)mlen;
713
182M
                mnum = 1;
714
182M
                if ( (mlen > sufficient_len) |
715
182M
                     (ip+mlen == iLimit) ) {  /* best possible length */
716
4.85M
                    ms->nextToUpdate = curr+1;  /* skip insertion */
717
4.85M
                    return 1;
718
4.85M
        }   }   }
719
        /* no dictMatchState lookup: dicts don't have a populated HC3 table */
720
432M
    }  /* if (mls == 3) */
721
722
1.07G
    hashTable[h] = curr;   /* Update Hash Table */
723
724
3.64G
    for (; nbCompares && (matchIndex >= matchLow); --nbCompares) {
725
2.86G
        U32* const nextPtr = bt + 2*(matchIndex & btMask);
726
2.86G
        const BYTE* match;
727
2.86G
        size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
728
2.86G
        assert(curr > matchIndex);
729
730
2.86G
        if ((dictMode == ZSTD_noDict) || (dictMode == ZSTD_dictMatchState) || (matchIndex+matchLength >= dictLimit)) {
731
2.84G
            assert(matchIndex+matchLength >= dictLimit);  /* ensure the condition is correct when !extDict */
732
2.84G
            match = base + matchIndex;
733
2.84G
            if (matchIndex >= dictLimit) assert(memcmp(match, ip, matchLength) == 0);  /* ensure early section of match is equal as expected */
734
2.84G
            matchLength += ZSTD_count(ip+matchLength, match+matchLength, iLimit);
735
2.84G
        } else {
736
23.6M
            match = dictBase + matchIndex;
737
23.6M
            assert(memcmp(match, ip, matchLength) == 0);  /* ensure early section of match is equal as expected */
738
23.6M
            matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dictEnd, prefixStart);
739
23.6M
            if (matchIndex+matchLength >= dictLimit)
740
114k
                match = base + matchIndex;   /* prepare for match[matchLength] read */
741
23.6M
        }
742
743
2.86G
        if (matchLength > bestLength) {
744
320M
            DEBUGLOG(8, "found match of length %u at distance %u (offBase=%u)",
745
320M
                    (U32)matchLength, curr - matchIndex, OFFSET_TO_OFFBASE(curr - matchIndex));
746
320M
            assert(matchEndIdx > matchIndex);
747
320M
            if (matchLength > matchEndIdx - matchIndex)
748
2.16M
                matchEndIdx = matchIndex + (U32)matchLength;
749
320M
            bestLength = matchLength;
750
320M
            matches[mnum].off = OFFSET_TO_OFFBASE(curr - matchIndex);
751
320M
            matches[mnum].len = (U32)matchLength;
752
320M
            mnum++;
753
320M
            if ( (matchLength > ZSTD_OPT_NUM)
754
320M
               | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) {
755
211k
                if (dictMode == ZSTD_dictMatchState) nbCompares = 0; /* break should also skip searching dms */
756
211k
                break; /* drop, to preserve bt consistency (miss a little bit of compression) */
757
211k
        }   }
758
759
2.86G
        if (match[matchLength] < ip[matchLength]) {
760
            /* match smaller than current */
761
1.01G
            *smallerPtr = matchIndex;             /* update smaller idx */
762
1.01G
            commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */
763
1.01G
            if (matchIndex <= btLow) { smallerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
764
869M
            smallerPtr = nextPtr+1;               /* new candidate => larger than match, which was smaller than current */
765
869M
            matchIndex = nextPtr[1];              /* new matchIndex, larger than previous, closer to current */
766
1.85G
        } else {
767
1.85G
            *largerPtr = matchIndex;
768
1.85G
            commonLengthLarger = matchLength;
769
1.85G
            if (matchIndex <= btLow) { largerPtr=&dummy32; break; }   /* beyond tree size, stop the search */
770
1.70G
            largerPtr = nextPtr;
771
1.70G
            matchIndex = nextPtr[0];
772
1.70G
    }   }
773
774
1.07G
    *smallerPtr = *largerPtr = 0;
775
776
1.07G
    assert(nbCompares <= (1U << ZSTD_SEARCHLOG_MAX)); /* Check we haven't underflowed. */
777
1.07G
    if (dictMode == ZSTD_dictMatchState && nbCompares) {
778
4.02M
        size_t const dmsH = ZSTD_hashPtr(ip, dmsHashLog, mls);
779
4.02M
        U32 dictMatchIndex = dms->hashTable[dmsH];
780
4.02M
        const U32* const dmsBt = dms->chainTable;
781
4.02M
        commonLengthSmaller = commonLengthLarger = 0;
782
9.66M
        for (; nbCompares && (dictMatchIndex > dmsLowLimit); --nbCompares) {
783
7.32M
            const U32* const nextPtr = dmsBt + 2*(dictMatchIndex & dmsBtMask);
784
7.32M
            size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger);   /* guaranteed minimum nb of common bytes */
785
7.32M
            const BYTE* match = dmsBase + dictMatchIndex;
786
7.32M
            matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iLimit, dmsEnd, prefixStart);
787
7.32M
            if (dictMatchIndex+matchLength >= dmsHighLimit)
788
97.2k
                match = base + dictMatchIndex + dmsIndexDelta;   /* to prepare for next usage of match[matchLength] */
789
790
7.32M
            if (matchLength > bestLength) {
791
877k
                matchIndex = dictMatchIndex + dmsIndexDelta;
792
877k
                DEBUGLOG(8, "found dms match of length %u at distance %u (offBase=%u)",
793
877k
                        (U32)matchLength, curr - matchIndex, OFFSET_TO_OFFBASE(curr - matchIndex));
794
877k
                if (matchLength > matchEndIdx - matchIndex)
795
414
                    matchEndIdx = matchIndex + (U32)matchLength;
796
877k
                bestLength = matchLength;
797
877k
                matches[mnum].off = OFFSET_TO_OFFBASE(curr - matchIndex);
798
877k
                matches[mnum].len = (U32)matchLength;
799
877k
                mnum++;
800
877k
                if ( (matchLength > ZSTD_OPT_NUM)
801
877k
                   | (ip+matchLength == iLimit) /* equal : no way to know if inf or sup */) {
802
8.68k
                    break;   /* drop, to guarantee consistency (miss a little bit of compression) */
803
8.68k
            }   }
804
805
7.31M
            if (dictMatchIndex <= dmsBtLow) { break; }   /* beyond tree size, stop the search */
806
5.64M
            if (match[matchLength] < ip[matchLength]) {
807
2.81M
                commonLengthSmaller = matchLength;    /* all smaller will now have at least this guaranteed common length */
808
2.81M
                dictMatchIndex = nextPtr[1];              /* new matchIndex larger than previous (closer to current) */
809
2.82M
            } else {
810
                /* match is larger than current */
811
2.82M
                commonLengthLarger = matchLength;
812
2.82M
                dictMatchIndex = nextPtr[0];
813
2.82M
    }   }   }  /* if (dictMode == ZSTD_dictMatchState) */
814
815
1.06G
    assert(matchEndIdx > curr+8);
816
1.06G
    ms->nextToUpdate = matchEndIdx - 8;  /* skip repetitive patterns */
817
1.06G
    return mnum;
818
1.06G
}
819
820
typedef U32 (*ZSTD_getAllMatchesFn)(
821
    ZSTD_match_t*,
822
    ZSTD_MatchState_t*,
823
    U32*,
824
    const BYTE*,
825
    const BYTE*,
826
    const U32 rep[ZSTD_REP_NUM],
827
    U32 const ll0,
828
    U32 const lengthToBeat);
829
830
FORCE_INLINE_TEMPLATE
831
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
832
U32 ZSTD_btGetAllMatches_internal(
833
        ZSTD_match_t* matches,
834
        ZSTD_MatchState_t* ms,
835
        U32* nextToUpdate3,
836
        const BYTE* ip,
837
        const BYTE* const iHighLimit,
838
        const U32 rep[ZSTD_REP_NUM],
839
        U32 const ll0,
840
        U32 const lengthToBeat,
841
        const ZSTD_dictMode_e dictMode,
842
        const U32 mls)
843
1.11G
{
844
1.11G
    assert(BOUNDED(3, ms->cParams.minMatch, 6) == mls);
845
1.11G
    DEBUGLOG(8, "ZSTD_BtGetAllMatches(dictMode=%d, mls=%u)", (int)dictMode, mls);
846
1.11G
    if (ip < ms->window.base + ms->nextToUpdate)
847
40.8M
        return 0;   /* skipped area */
848
1.07G
    ZSTD_updateTree_internal(ms, ip, iHighLimit, mls, dictMode);
849
1.07G
    return ZSTD_insertBtAndGetAllMatches(matches, ms, nextToUpdate3, ip, iHighLimit, dictMode, rep, ll0, lengthToBeat, mls);
850
1.11G
}
851
852
10.2M
#define ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, mls) ZSTD_btGetAllMatches_##dictMode##_##mls
853
854
#define GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, mls)            \
855
    static U32 ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, mls)(      \
856
            ZSTD_match_t* matches,                             \
857
            ZSTD_MatchState_t* ms,                             \
858
            U32* nextToUpdate3,                                \
859
            const BYTE* ip,                                    \
860
            const BYTE* const iHighLimit,                      \
861
            const U32 rep[ZSTD_REP_NUM],                       \
862
            U32 const ll0,                                     \
863
            U32 const lengthToBeat)                            \
864
1.11G
    {                                                          \
865
1.11G
        return ZSTD_btGetAllMatches_internal(                  \
866
1.11G
                matches, ms, nextToUpdate3, ip, iHighLimit,    \
867
1.11G
                rep, ll0, lengthToBeat, ZSTD_##dictMode, mls); \
868
1.11G
    }
zstd_opt.c:ZSTD_btGetAllMatches_noDict_3
Line
Count
Source
864
562M
    {                                                          \
865
562M
        return ZSTD_btGetAllMatches_internal(                  \
866
562M
                matches, ms, nextToUpdate3, ip, iHighLimit,    \
867
562M
                rep, ll0, lengthToBeat, ZSTD_##dictMode, mls); \
868
562M
    }
zstd_opt.c:ZSTD_btGetAllMatches_noDict_4
Line
Count
Source
864
107M
    {                                                          \
865
107M
        return ZSTD_btGetAllMatches_internal(                  \
866
107M
                matches, ms, nextToUpdate3, ip, iHighLimit,    \
867
107M
                rep, ll0, lengthToBeat, ZSTD_##dictMode, mls); \
868
107M
    }
zstd_opt.c:ZSTD_btGetAllMatches_noDict_5
Line
Count
Source
864
150M
    {                                                          \
865
150M
        return ZSTD_btGetAllMatches_internal(                  \
866
150M
                matches, ms, nextToUpdate3, ip, iHighLimit,    \
867
150M
                rep, ll0, lengthToBeat, ZSTD_##dictMode, mls); \
868
150M
    }
zstd_opt.c:ZSTD_btGetAllMatches_noDict_6
Line
Count
Source
864
203M
    {                                                          \
865
203M
        return ZSTD_btGetAllMatches_internal(                  \
866
203M
                matches, ms, nextToUpdate3, ip, iHighLimit,    \
867
203M
                rep, ll0, lengthToBeat, ZSTD_##dictMode, mls); \
868
203M
    }
zstd_opt.c:ZSTD_btGetAllMatches_extDict_3
Line
Count
Source
864
33.5M
    {                                                          \
865
33.5M
        return ZSTD_btGetAllMatches_internal(                  \
866
33.5M
                matches, ms, nextToUpdate3, ip, iHighLimit,    \
867
33.5M
                rep, ll0, lengthToBeat, ZSTD_##dictMode, mls); \
868
33.5M
    }
zstd_opt.c:ZSTD_btGetAllMatches_extDict_4
Line
Count
Source
864
36.1M
    {                                                          \
865
36.1M
        return ZSTD_btGetAllMatches_internal(                  \
866
36.1M
                matches, ms, nextToUpdate3, ip, iHighLimit,    \
867
36.1M
                rep, ll0, lengthToBeat, ZSTD_##dictMode, mls); \
868
36.1M
    }
zstd_opt.c:ZSTD_btGetAllMatches_extDict_5
Line
Count
Source
864
8.80M
    {                                                          \
865
8.80M
        return ZSTD_btGetAllMatches_internal(                  \
866
8.80M
                matches, ms, nextToUpdate3, ip, iHighLimit,    \
867
8.80M
                rep, ll0, lengthToBeat, ZSTD_##dictMode, mls); \
868
8.80M
    }
zstd_opt.c:ZSTD_btGetAllMatches_extDict_6
Line
Count
Source
864
10.0M
    {                                                          \
865
10.0M
        return ZSTD_btGetAllMatches_internal(                  \
866
10.0M
                matches, ms, nextToUpdate3, ip, iHighLimit,    \
867
10.0M
                rep, ll0, lengthToBeat, ZSTD_##dictMode, mls); \
868
10.0M
    }
zstd_opt.c:ZSTD_btGetAllMatches_dictMatchState_3
Line
Count
Source
864
1.98M
    {                                                          \
865
1.98M
        return ZSTD_btGetAllMatches_internal(                  \
866
1.98M
                matches, ms, nextToUpdate3, ip, iHighLimit,    \
867
1.98M
                rep, ll0, lengthToBeat, ZSTD_##dictMode, mls); \
868
1.98M
    }
zstd_opt.c:ZSTD_btGetAllMatches_dictMatchState_4
Line
Count
Source
864
673k
    {                                                          \
865
673k
        return ZSTD_btGetAllMatches_internal(                  \
866
673k
                matches, ms, nextToUpdate3, ip, iHighLimit,    \
867
673k
                rep, ll0, lengthToBeat, ZSTD_##dictMode, mls); \
868
673k
    }
zstd_opt.c:ZSTD_btGetAllMatches_dictMatchState_5
Line
Count
Source
864
1.00M
    {                                                          \
865
1.00M
        return ZSTD_btGetAllMatches_internal(                  \
866
1.00M
                matches, ms, nextToUpdate3, ip, iHighLimit,    \
867
1.00M
                rep, ll0, lengthToBeat, ZSTD_##dictMode, mls); \
868
1.00M
    }
zstd_opt.c:ZSTD_btGetAllMatches_dictMatchState_6
Line
Count
Source
864
1.13M
    {                                                          \
865
1.13M
        return ZSTD_btGetAllMatches_internal(                  \
866
1.13M
                matches, ms, nextToUpdate3, ip, iHighLimit,    \
867
1.13M
                rep, ll0, lengthToBeat, ZSTD_##dictMode, mls); \
868
1.13M
    }
869
870
#define GEN_ZSTD_BT_GET_ALL_MATCHES(dictMode)  \
871
    GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 3)  \
872
    GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 4)  \
873
    GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 5)  \
874
    GEN_ZSTD_BT_GET_ALL_MATCHES_(dictMode, 6)
875
876
GEN_ZSTD_BT_GET_ALL_MATCHES(noDict)
877
GEN_ZSTD_BT_GET_ALL_MATCHES(extDict)
878
GEN_ZSTD_BT_GET_ALL_MATCHES(dictMatchState)
879
880
#define ZSTD_BT_GET_ALL_MATCHES_ARRAY(dictMode)  \
881
2.55M
    {                                            \
882
2.55M
        ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 3), \
883
2.55M
        ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 4), \
884
2.55M
        ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 5), \
885
2.55M
        ZSTD_BT_GET_ALL_MATCHES_FN(dictMode, 6)  \
886
2.55M
    }
887
888
static ZSTD_getAllMatchesFn
889
ZSTD_selectBtGetAllMatches(ZSTD_MatchState_t const* ms, ZSTD_dictMode_e const dictMode)
890
851k
{
891
851k
    ZSTD_getAllMatchesFn const getAllMatchesFns[3][4] = {
892
851k
        ZSTD_BT_GET_ALL_MATCHES_ARRAY(noDict),
893
851k
        ZSTD_BT_GET_ALL_MATCHES_ARRAY(extDict),
894
851k
        ZSTD_BT_GET_ALL_MATCHES_ARRAY(dictMatchState)
895
851k
    };
896
851k
    U32 const mls = BOUNDED(3, ms->cParams.minMatch, 6);
897
851k
    assert((U32)dictMode < 3);
898
851k
    assert(mls - 3 < 4);
899
851k
    return getAllMatchesFns[(int)dictMode][mls - 3];
900
851k
}
901
902
/*************************
903
*  LDM helper functions  *
904
*************************/
905
906
/* Struct containing info needed to make decision about ldm inclusion */
907
typedef struct {
908
    RawSeqStore_t seqStore;   /* External match candidates store for this block */
909
    U32 startPosInBlock;      /* Start position of the current match candidate */
910
    U32 endPosInBlock;        /* End position of the current match candidate */
911
    U32 offset;               /* Offset of the match candidate */
912
} ZSTD_optLdm_t;
913
914
/* ZSTD_optLdm_skipRawSeqStoreBytes():
915
 * Moves forward in @rawSeqStore by @nbBytes,
916
 * which will update the fields 'pos' and 'posInSequence'.
917
 */
918
static void ZSTD_optLdm_skipRawSeqStoreBytes(RawSeqStore_t* rawSeqStore, size_t nbBytes)
919
499k
{
920
499k
    U32 currPos = (U32)(rawSeqStore->posInSequence + nbBytes);
921
977k
    while (currPos && rawSeqStore->pos < rawSeqStore->size) {
922
540k
        rawSeq currSeq = rawSeqStore->seq[rawSeqStore->pos];
923
540k
        if (currPos >= currSeq.litLength + currSeq.matchLength) {
924
477k
            currPos -= currSeq.litLength + currSeq.matchLength;
925
477k
            rawSeqStore->pos++;
926
477k
        } else {
927
62.9k
            rawSeqStore->posInSequence = currPos;
928
62.9k
            break;
929
62.9k
        }
930
540k
    }
931
499k
    if (currPos == 0 || rawSeqStore->pos == rawSeqStore->size) {
932
436k
        rawSeqStore->posInSequence = 0;
933
436k
    }
934
499k
}
935
936
/* ZSTD_opt_getNextMatchAndUpdateSeqStore():
937
 * Calculates the beginning and end of the next match in the current block.
938
 * Updates 'pos' and 'posInSequence' of the ldmSeqStore.
939
 */
940
static void
941
ZSTD_opt_getNextMatchAndUpdateSeqStore(ZSTD_optLdm_t* optLdm, U32 currPosInBlock,
942
                                       U32 blockBytesRemaining)
943
1.24M
{
944
1.24M
    rawSeq currSeq;
945
1.24M
    U32 currBlockEndPos;
946
1.24M
    U32 literalsBytesRemaining;
947
1.24M
    U32 matchBytesRemaining;
948
949
    /* Setting match end position to MAX to ensure we never use an LDM during this block */
950
1.24M
    if (optLdm->seqStore.size == 0 || optLdm->seqStore.pos >= optLdm->seqStore.size) {
951
783k
        optLdm->startPosInBlock = UINT_MAX;
952
783k
        optLdm->endPosInBlock = UINT_MAX;
953
783k
        return;
954
783k
    }
955
    /* Calculate appropriate bytes left in matchLength and litLength
956
     * after adjusting based on ldmSeqStore->posInSequence */
957
463k
    currSeq = optLdm->seqStore.seq[optLdm->seqStore.pos];
958
463k
    assert(optLdm->seqStore.posInSequence <= currSeq.litLength + currSeq.matchLength);
959
463k
    currBlockEndPos = currPosInBlock + blockBytesRemaining;
960
463k
    literalsBytesRemaining = (optLdm->seqStore.posInSequence < currSeq.litLength) ?
961
340k
            currSeq.litLength - (U32)optLdm->seqStore.posInSequence :
962
463k
            0;
963
463k
    matchBytesRemaining = (literalsBytesRemaining == 0) ?
964
123k
            currSeq.matchLength - ((U32)optLdm->seqStore.posInSequence - currSeq.litLength) :
965
463k
            currSeq.matchLength;
966
967
    /* If there are more literal bytes than bytes remaining in block, no ldm is possible */
968
463k
    if (literalsBytesRemaining >= blockBytesRemaining) {
969
36.9k
        optLdm->startPosInBlock = UINT_MAX;
970
36.9k
        optLdm->endPosInBlock = UINT_MAX;
971
36.9k
        ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, blockBytesRemaining);
972
36.9k
        return;
973
36.9k
    }
974
975
    /* Matches may be < minMatch by this process. In that case, we will reject them
976
       when we are deciding whether or not to add the ldm */
977
426k
    optLdm->startPosInBlock = currPosInBlock + literalsBytesRemaining;
978
426k
    optLdm->endPosInBlock = optLdm->startPosInBlock + matchBytesRemaining;
979
426k
    optLdm->offset = currSeq.offset;
980
981
426k
    if (optLdm->endPosInBlock > currBlockEndPos) {
982
        /* Match ends after the block ends, we can't use the whole match */
983
658
        optLdm->endPosInBlock = currBlockEndPos;
984
658
        ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, currBlockEndPos - currPosInBlock);
985
425k
    } else {
986
        /* Consume nb of bytes equal to size of sequence left */
987
425k
        ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, literalsBytesRemaining + matchBytesRemaining);
988
425k
    }
989
426k
}
990
991
/* ZSTD_optLdm_maybeAddMatch():
992
 * Adds a match if it's long enough,
993
 * based on it's 'matchStartPosInBlock' and 'matchEndPosInBlock',
994
 * into 'matches'. Maintains the correct ordering of 'matches'.
995
 */
996
static void ZSTD_optLdm_maybeAddMatch(ZSTD_match_t* matches, U32* nbMatches,
997
                                      const ZSTD_optLdm_t* optLdm, U32 currPosInBlock,
998
                                      U32 minMatch)
999
32.0M
{
1000
32.0M
    U32 const posDiff = currPosInBlock - optLdm->startPosInBlock;
1001
    /* Note: ZSTD_match_t actually contains offBase and matchLength (before subtracting MINMATCH) */
1002
32.0M
    U32 const candidateMatchLength = optLdm->endPosInBlock - optLdm->startPosInBlock - posDiff;
1003
1004
    /* Ensure that current block position is not outside of the match */
1005
32.0M
    if (currPosInBlock < optLdm->startPosInBlock
1006
4.02M
      || currPosInBlock >= optLdm->endPosInBlock
1007
28.9M
      || candidateMatchLength < minMatch) {
1008
28.9M
        return;
1009
28.9M
    }
1010
1011
3.15M
    if (*nbMatches == 0 || ((candidateMatchLength > matches[*nbMatches-1].len) && *nbMatches < ZSTD_OPT_NUM)) {
1012
974k
        U32 const candidateOffBase = OFFSET_TO_OFFBASE(optLdm->offset);
1013
974k
        DEBUGLOG(6, "ZSTD_optLdm_maybeAddMatch(): Adding ldm candidate match (offBase: %u matchLength %u) at block position=%u",
1014
974k
                 candidateOffBase, candidateMatchLength, currPosInBlock);
1015
974k
        matches[*nbMatches].len = candidateMatchLength;
1016
974k
        matches[*nbMatches].off = candidateOffBase;
1017
974k
        (*nbMatches)++;
1018
974k
    }
1019
3.15M
}
1020
1021
/* ZSTD_optLdm_processMatchCandidate():
1022
 * Wrapper function to update ldm seq store and call ldm functions as necessary.
1023
 */
1024
static void
1025
ZSTD_optLdm_processMatchCandidate(ZSTD_optLdm_t* optLdm,
1026
                                  ZSTD_match_t* matches, U32* nbMatches,
1027
                                  U32 currPosInBlock, U32 remainingBytes,
1028
                                  U32 minMatch)
1029
1.11G
{
1030
1.11G
    if (optLdm->seqStore.size == 0 || optLdm->seqStore.pos >= optLdm->seqStore.size) {
1031
1.08G
        return;
1032
1.08G
    }
1033
1034
31.9M
    if (currPosInBlock >= optLdm->endPosInBlock) {
1035
395k
        if (currPosInBlock > optLdm->endPosInBlock) {
1036
            /* The position at which ZSTD_optLdm_processMatchCandidate() is called is not necessarily
1037
             * at the end of a match from the ldm seq store, and will often be some bytes
1038
             * over beyond matchEndPosInBlock. As such, we need to correct for these "overshoots"
1039
             */
1040
35.8k
            U32 const posOvershoot = currPosInBlock - optLdm->endPosInBlock;
1041
35.8k
            ZSTD_optLdm_skipRawSeqStoreBytes(&optLdm->seqStore, posOvershoot);
1042
35.8k
        }
1043
395k
        ZSTD_opt_getNextMatchAndUpdateSeqStore(optLdm, currPosInBlock, remainingBytes);
1044
395k
    }
1045
31.9M
    ZSTD_optLdm_maybeAddMatch(matches, nbMatches, optLdm, currPosInBlock, minMatch);
1046
31.9M
}
1047
1048
1049
/*-*******************************
1050
*  Optimal parser
1051
*********************************/
1052
1053
#if 0 /* debug */
1054
1055
static void
1056
listStats(const U32* table, int lastEltID)
1057
{
1058
    int const nbElts = lastEltID + 1;
1059
    int enb;
1060
    for (enb=0; enb < nbElts; enb++) {
1061
        (void)table;
1062
        /* RAWLOG(2, "%3i:%3i,  ", enb, table[enb]); */
1063
        RAWLOG(2, "%4i,", table[enb]);
1064
    }
1065
    RAWLOG(2, " \n");
1066
}
1067
1068
#endif
1069
1070
802M
#define LIT_PRICE(_p) (int)ZSTD_rawLiteralsCost(_p, 1, optStatePtr, optLevel)
1071
2.58G
#define LL_PRICE(_l) (int)ZSTD_litLengthPrice(_l, optStatePtr, optLevel)
1072
891M
#define LL_INCPRICE(_l) (LL_PRICE(_l) - LL_PRICE(_l-1))
1073
1074
FORCE_INLINE_TEMPLATE
1075
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
1076
size_t
1077
ZSTD_compressBlock_opt_generic(ZSTD_MatchState_t* ms,
1078
                               SeqStore_t* seqStore,
1079
                               U32 rep[ZSTD_REP_NUM],
1080
                         const void* src, size_t srcSize,
1081
                         const int optLevel,
1082
                         const ZSTD_dictMode_e dictMode)
1083
851k
{
1084
851k
    optState_t* const optStatePtr = &ms->opt;
1085
851k
    const BYTE* const istart = (const BYTE*)src;
1086
851k
    const BYTE* ip = istart;
1087
851k
    const BYTE* anchor = istart;
1088
851k
    const BYTE* const iend = istart + srcSize;
1089
851k
    const BYTE* const ilimit = iend - 8;
1090
851k
    const BYTE* const base = ms->window.base;
1091
851k
    const BYTE* const prefixStart = base + ms->window.dictLimit;
1092
851k
    const ZSTD_compressionParameters* const cParams = &ms->cParams;
1093
1094
851k
    ZSTD_getAllMatchesFn getAllMatches = ZSTD_selectBtGetAllMatches(ms, dictMode);
1095
1096
851k
    U32 const sufficient_len = MIN(cParams->targetLength, ZSTD_OPT_NUM -1);
1097
851k
    U32 const minMatch = (cParams->minMatch == 3) ? 3 : 4;
1098
851k
    U32 nextToUpdate3 = ms->nextToUpdate;
1099
1100
851k
    ZSTD_optimal_t* const opt = optStatePtr->priceTable;
1101
851k
    ZSTD_match_t* const matches = optStatePtr->matchTable;
1102
851k
    ZSTD_optimal_t lastStretch;
1103
851k
    ZSTD_optLdm_t optLdm;
1104
1105
851k
    ZSTD_memset(&lastStretch, 0, sizeof(ZSTD_optimal_t));
1106
1107
851k
    optLdm.seqStore = ms->ldmSeqStore ? *ms->ldmSeqStore : kNullRawSeqStore;
1108
851k
    optLdm.endPosInBlock = optLdm.startPosInBlock = optLdm.offset = 0;
1109
851k
    ZSTD_opt_getNextMatchAndUpdateSeqStore(&optLdm, (U32)(ip-istart), (U32)(iend-ip));
1110
1111
    /* init */
1112
851k
    DEBUGLOG(5, "ZSTD_compressBlock_opt_generic: current=%u, prefix=%u, nextToUpdate=%u",
1113
851k
                (U32)(ip - base), ms->window.dictLimit, ms->nextToUpdate);
1114
851k
    assert(optLevel <= 2);
1115
851k
    ZSTD_rescaleFreqs(optStatePtr, (const BYTE*)src, srcSize, optLevel);
1116
851k
    ip += (ip==prefixStart);
1117
1118
    /* Match Loop */
1119
538M
    while (ip < ilimit) {
1120
537M
        U32 cur, last_pos = 0;
1121
1122
        /* find first match */
1123
537M
        {   U32 const litlen = (U32)(ip - anchor);
1124
537M
            U32 const ll0 = !litlen;
1125
537M
            U32 nbMatches = getAllMatches(matches, ms, &nextToUpdate3, ip, iend, rep, ll0, minMatch);
1126
537M
            ZSTD_optLdm_processMatchCandidate(&optLdm, matches, &nbMatches,
1127
537M
                                              (U32)(ip-istart), (U32)(iend-ip),
1128
537M
                                              minMatch);
1129
537M
            if (!nbMatches) {
1130
492M
                DEBUGLOG(8, "no match found at cPos %u", (unsigned)(ip-istart));
1131
492M
                ip++;
1132
492M
                continue;
1133
492M
            }
1134
1135
            /* Match found: let's store this solution, and eventually find more candidates.
1136
             * During this forward pass, @opt is used to store stretches,
1137
             * defined as "a match followed by N literals".
1138
             * Note how this is different from a Sequence, which is "N literals followed by a match".
1139
             * Storing stretches allows us to store different match predecessors
1140
             * for each literal position part of a literals run. */
1141
1142
            /* initialize opt[0] */
1143
44.7M
            opt[0].mlen = 0;  /* there are only literals so far */
1144
44.7M
            opt[0].litlen = litlen;
1145
            /* No need to include the actual price of the literals before the first match
1146
             * because it is static for the duration of the forward pass, and is included
1147
             * in every subsequent price. But, we include the literal length because
1148
             * the cost variation of litlen depends on the value of litlen.
1149
             */
1150
44.7M
            opt[0].price = LL_PRICE(litlen);
1151
44.7M
            ZSTD_STATIC_ASSERT(sizeof(opt[0].rep[0]) == sizeof(rep[0]));
1152
44.7M
            ZSTD_memcpy(&opt[0].rep, rep, sizeof(opt[0].rep));
1153
1154
            /* large match -> immediate encoding */
1155
44.7M
            {   U32 const maxML = matches[nbMatches-1].len;
1156
44.7M
                U32 const maxOffBase = matches[nbMatches-1].off;
1157
44.7M
                DEBUGLOG(6, "found %u matches of maxLength=%u and maxOffBase=%u at cPos=%u => start new series",
1158
44.7M
                            nbMatches, maxML, maxOffBase, (U32)(ip-prefixStart));
1159
1160
44.7M
                if (maxML > sufficient_len) {
1161
9.41M
                    lastStretch.litlen = 0;
1162
9.41M
                    lastStretch.mlen = maxML;
1163
9.41M
                    lastStretch.off = maxOffBase;
1164
9.41M
                    DEBUGLOG(6, "large match (%u>%u) => immediate encoding",
1165
9.41M
                                maxML, sufficient_len);
1166
9.41M
                    cur = 0;
1167
9.41M
                    last_pos = maxML;
1168
9.41M
                    goto _shortestPath;
1169
9.41M
            }   }
1170
1171
            /* set prices for first matches starting position == 0 */
1172
44.7M
            assert(opt[0].price >= 0);
1173
35.3M
            {   U32 pos;
1174
35.3M
                U32 matchNb;
1175
118M
                for (pos = 1; pos < minMatch; pos++) {
1176
83.3M
                    opt[pos].price = ZSTD_MAX_PRICE;
1177
83.3M
                    opt[pos].mlen = 0;
1178
83.3M
                    opt[pos].litlen = litlen + pos;
1179
83.3M
                }
1180
80.6M
                for (matchNb = 0; matchNb < nbMatches; matchNb++) {
1181
45.2M
                    U32 const offBase = matches[matchNb].off;
1182
45.2M
                    U32 const end = matches[matchNb].len;
1183
219M
                    for ( ; pos <= end ; pos++ ) {
1184
174M
                        int const matchPrice = (int)ZSTD_getMatchPrice(offBase, pos, optStatePtr, optLevel);
1185
174M
                        int const sequencePrice = opt[0].price + matchPrice;
1186
174M
                        DEBUGLOG(7, "rPos:%u => set initial price : %.2f",
1187
174M
                                    pos, ZSTD_fCost(sequencePrice));
1188
174M
                        opt[pos].mlen = pos;
1189
174M
                        opt[pos].off = offBase;
1190
174M
                        opt[pos].litlen = 0; /* end of match */
1191
174M
                        opt[pos].price = sequencePrice + LL_PRICE(0);
1192
174M
                    }
1193
45.2M
                }
1194
35.3M
                last_pos = pos-1;
1195
35.3M
                opt[pos].price = ZSTD_MAX_PRICE;
1196
35.3M
            }
1197
35.3M
        }
1198
1199
        /* check further positions */
1200
711M
        for (cur = 1; cur <= last_pos; cur++) {
1201
710M
            const BYTE* const inr = ip + cur;
1202
710M
            assert(cur <= ZSTD_OPT_NUM);
1203
710M
            DEBUGLOG(7, "cPos:%i==rPos:%u", (int)(inr-istart), cur);
1204
1205
            /* Fix current position with one literal if cheaper */
1206
710M
            {   U32 const litlen = opt[cur-1].litlen + 1;
1207
710M
                int const price = opt[cur-1].price
1208
710M
                                + LIT_PRICE(ip+cur-1)
1209
710M
                                + LL_INCPRICE(litlen);
1210
710M
                assert(price < 1000000000); /* overflow check */
1211
711M
                if (price <= opt[cur].price) {
1212
237M
                    ZSTD_optimal_t const prevMatch = opt[cur];
1213
237M
                    DEBUGLOG(7, "cPos:%i==rPos:%u : better price (%.2f<=%.2f) using literal (ll==%u) (hist:%u,%u,%u)",
1214
237M
                                (int)(inr-istart), cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price), litlen,
1215
237M
                                opt[cur-1].rep[0], opt[cur-1].rep[1], opt[cur-1].rep[2]);
1216
237M
                    opt[cur] = opt[cur-1];
1217
237M
                    opt[cur].litlen = litlen;
1218
237M
                    opt[cur].price = price;
1219
237M
                    if ( (optLevel >= 1) /* additional check only for higher modes */
1220
160M
                      && (prevMatch.litlen == 0) /* replace a match */
1221
89.2M
                      && (LL_INCPRICE(1) < 0) /* ll1 is cheaper than ll0 */
1222
45.7M
                      && LIKELY(ip + cur < iend)
1223
237M
                    ) {
1224
                        /* check next position, in case it would be cheaper */
1225
45.7M
                        int with1literal = prevMatch.price + LIT_PRICE(ip+cur) + LL_INCPRICE(1);
1226
45.7M
                        int withMoreLiterals = price + LIT_PRICE(ip+cur) + LL_INCPRICE(litlen+1);
1227
45.7M
                        DEBUGLOG(7, "then at next rPos %u : match+1lit %.2f vs %ulits %.2f",
1228
45.7M
                                cur+1, ZSTD_fCost(with1literal), litlen+1, ZSTD_fCost(withMoreLiterals));
1229
45.7M
                        if ( (with1literal < withMoreLiterals)
1230
12.7M
                          && (with1literal < opt[cur+1].price) ) {
1231
                            /* update offset history - before it disappears */
1232
6.22M
                            U32 const prev = cur - prevMatch.mlen;
1233
6.22M
                            Repcodes_t const newReps = ZSTD_newRep(opt[prev].rep, prevMatch.off, opt[prev].litlen==0);
1234
6.22M
                            assert(cur >= prevMatch.mlen);
1235
6.22M
                            DEBUGLOG(7, "==> match+1lit is cheaper (%.2f < %.2f) (hist:%u,%u,%u) !",
1236
6.22M
                                        ZSTD_fCost(with1literal), ZSTD_fCost(withMoreLiterals),
1237
6.22M
                                        newReps.rep[0], newReps.rep[1], newReps.rep[2] );
1238
6.22M
                            opt[cur+1] = prevMatch;  /* mlen & offbase */
1239
6.22M
                            ZSTD_memcpy(opt[cur+1].rep, &newReps, sizeof(Repcodes_t));
1240
6.22M
                            opt[cur+1].litlen = 1;
1241
6.22M
                            opt[cur+1].price = with1literal;
1242
6.22M
                            if (last_pos < cur+1) last_pos = cur+1;
1243
6.22M
                        }
1244
45.7M
                    }
1245
474M
                } else {
1246
474M
                    DEBUGLOG(7, "cPos:%i==rPos:%u : literal would cost more (%.2f>%.2f)",
1247
474M
                                (int)(inr-istart), cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price));
1248
474M
                }
1249
711M
            }
1250
1251
            /* Offset history is not updated during match comparison.
1252
             * Do it here, now that the match is selected and confirmed.
1253
             */
1254
711M
            ZSTD_STATIC_ASSERT(sizeof(opt[cur].rep) == sizeof(Repcodes_t));
1255
711M
            assert(cur >= opt[cur].mlen);
1256
711M
            if (opt[cur].litlen == 0) {
1257
                /* just finished a match => alter offset history */
1258
468M
                U32 const prev = cur - opt[cur].mlen;
1259
468M
                Repcodes_t const newReps = ZSTD_newRep(opt[prev].rep, opt[cur].off, opt[prev].litlen==0);
1260
468M
                ZSTD_memcpy(opt[cur].rep, &newReps, sizeof(Repcodes_t));
1261
468M
            }
1262
1263
            /* last match must start at a minimum distance of 8 from oend */
1264
711M
            if (inr > ilimit) continue;
1265
1266
710M
            if (cur == last_pos) break;
1267
1268
676M
            if ( (optLevel==0) /*static_test*/
1269
205M
              && (opt[cur+1].price <= opt[cur].price + (BITCOST_MULTIPLIER/2)) ) {
1270
95.7M
                DEBUGLOG(7, "skip current position : next rPos(%u) price is cheaper", cur+1);
1271
95.7M
                continue;  /* skip unpromising positions; about ~+6% speed, -0.01 ratio */
1272
95.7M
            }
1273
1274
676M
            assert(opt[cur].price >= 0);
1275
580M
            {   U32 const ll0 = (opt[cur].litlen == 0);
1276
580M
                int const previousPrice = opt[cur].price;
1277
580M
                int const basePrice = previousPrice + LL_PRICE(0);
1278
580M
                U32 nbMatches = getAllMatches(matches, ms, &nextToUpdate3, inr, iend, opt[cur].rep, ll0, minMatch);
1279
580M
                U32 matchNb;
1280
1281
580M
                ZSTD_optLdm_processMatchCandidate(&optLdm, matches, &nbMatches,
1282
580M
                                                  (U32)(inr-istart), (U32)(iend-inr),
1283
580M
                                                  minMatch);
1284
1285
580M
                if (!nbMatches) {
1286
141M
                    DEBUGLOG(7, "rPos:%u : no match found", cur);
1287
141M
                    continue;
1288
141M
                }
1289
1290
439M
                {   U32 const longestML = matches[nbMatches-1].len;
1291
439M
                    DEBUGLOG(7, "cPos:%i==rPos:%u, found %u matches, of longest ML=%u",
1292
439M
                                (int)(inr-istart), cur, nbMatches, longestML);
1293
1294
439M
                    if ( (longestML > sufficient_len)
1295
437M
                      || (cur + longestML >= ZSTD_OPT_NUM)
1296
437M
                      || (ip + cur + longestML >= iend) ) {
1297
997k
                        lastStretch.mlen = longestML;
1298
997k
                        lastStretch.off = matches[nbMatches-1].off;
1299
997k
                        lastStretch.litlen = 0;
1300
997k
                        last_pos = cur + longestML;
1301
997k
                        goto _shortestPath;
1302
997k
                }   }
1303
1304
                /* set prices using matches found at position == cur */
1305
1.11G
                for (matchNb = 0; matchNb < nbMatches; matchNb++) {
1306
674M
                    U32 const offset = matches[matchNb].off;
1307
674M
                    U32 const lastML = matches[matchNb].len;
1308
674M
                    U32 const startML = (matchNb>0) ? matches[matchNb-1].len+1 : minMatch;
1309
674M
                    U32 mlen;
1310
1311
674M
                    DEBUGLOG(7, "testing match %u => offBase=%4u, mlen=%2u, llen=%2u",
1312
674M
                                matchNb, matches[matchNb].off, lastML, opt[cur].litlen);
1313
1314
6.12G
                    for (mlen = lastML; mlen >= startML; mlen--) {  /* scan downward */
1315
5.53G
                        U32 const pos = cur + mlen;
1316
5.53G
                        int const price = basePrice + (int)ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel);
1317
1318
5.53G
                        if ((pos > last_pos) || (price < opt[pos].price)) {
1319
732M
                            DEBUGLOG(7, "rPos:%u (ml=%2u) => new better price (%.2f<%.2f)",
1320
732M
                                        pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price));
1321
1.20G
                            while (last_pos < pos) {
1322
                                /* fill empty positions, for future comparisons */
1323
468M
                                last_pos++;
1324
468M
                                opt[last_pos].price = ZSTD_MAX_PRICE;
1325
468M
                                opt[last_pos].litlen = !0;  /* just needs to be != 0, to mean "not an end of match" */
1326
468M
                            }
1327
732M
                            opt[pos].mlen = mlen;
1328
732M
                            opt[pos].off = offset;
1329
732M
                            opt[pos].litlen = 0;
1330
732M
                            opt[pos].price = price;
1331
4.79G
                        } else {
1332
4.79G
                            DEBUGLOG(7, "rPos:%u (ml=%2u) => new price is worse (%.2f>=%.2f)",
1333
4.79G
                                        pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price));
1334
4.79G
                            if (optLevel==0) break;  /* early update abort; gets ~+10% speed for about -0.01 ratio loss */
1335
4.79G
                        }
1336
5.53G
            }   }   }
1337
438M
            opt[last_pos+1].price = ZSTD_MAX_PRICE;
1338
438M
        }  /* for (cur = 1; cur <= last_pos; cur++) */
1339
1340
35.0M
        lastStretch = opt[last_pos];
1341
35.0M
        assert(cur >= lastStretch.mlen);
1342
35.0M
        cur = last_pos - lastStretch.mlen;
1343
1344
44.8M
_shortestPath:   /* cur, last_pos, best_mlen, best_off have to be set */
1345
44.8M
        assert(opt[0].mlen == 0);
1346
44.8M
        assert(last_pos >= lastStretch.mlen);
1347
44.8M
        assert(cur == last_pos - lastStretch.mlen);
1348
1349
44.8M
        if (lastStretch.mlen==0) {
1350
            /* no solution : all matches have been converted into literals */
1351
3.11M
            assert(lastStretch.litlen == (ip - anchor) + last_pos);
1352
3.11M
            ip += last_pos;
1353
3.11M
            continue;
1354
3.11M
        }
1355
44.8M
        assert(lastStretch.off > 0);
1356
1357
        /* Update offset history */
1358
41.6M
        if (lastStretch.litlen == 0) {
1359
            /* finishing on a match : update offset history */
1360
36.4M
            Repcodes_t const reps = ZSTD_newRep(opt[cur].rep, lastStretch.off, opt[cur].litlen==0);
1361
36.4M
            ZSTD_memcpy(rep, &reps, sizeof(Repcodes_t));
1362
36.4M
        } else {
1363
5.25M
            ZSTD_memcpy(rep, lastStretch.rep, sizeof(Repcodes_t));
1364
5.25M
            assert(cur >= lastStretch.litlen);
1365
5.25M
            cur -= lastStretch.litlen;
1366
5.25M
        }
1367
1368
        /* Let's write the shortest path solution.
1369
         * It is stored in @opt in reverse order,
1370
         * starting from @storeEnd (==cur+2),
1371
         * effectively partially @opt overwriting.
1372
         * Content is changed too:
1373
         * - So far, @opt stored stretches, aka a match followed by literals
1374
         * - Now, it will store sequences, aka literals followed by a match
1375
         */
1376
41.6M
        {   U32 const storeEnd = cur + 2;
1377
41.6M
            U32 storeStart = storeEnd;
1378
41.6M
            U32 stretchPos = cur;
1379
1380
41.6M
            DEBUGLOG(6, "start reverse traversal (last_pos:%u, cur:%u)",
1381
41.6M
                        last_pos, cur); (void)last_pos;
1382
41.6M
            assert(storeEnd < ZSTD_OPT_SIZE);
1383
41.7M
            DEBUGLOG(6, "last stretch copied into pos=%u (llen=%u,mlen=%u,ofc=%u)",
1384
41.7M
                        storeEnd, lastStretch.litlen, lastStretch.mlen, lastStretch.off);
1385
41.7M
            opt[storeEnd] = lastStretch;  /* note: litlen will be fixed */
1386
41.7M
            storeStart = storeEnd;
1387
95.7M
            while (1) {
1388
95.7M
                ZSTD_optimal_t nextStretch = opt[stretchPos];
1389
95.7M
                opt[storeStart].litlen = nextStretch.litlen;
1390
95.7M
                DEBUGLOG(6, "selected sequence (llen=%u,mlen=%u,ofc=%u)",
1391
95.7M
                            opt[storeStart].litlen, opt[storeStart].mlen, opt[storeStart].off);
1392
95.7M
                if (nextStretch.mlen == 0) {
1393
                    /* reaching beginning of segment */
1394
41.7M
                    break;
1395
41.7M
                }
1396
54.0M
                storeStart--;
1397
54.0M
                opt[storeStart] = nextStretch; /* note: litlen will be fixed */
1398
54.0M
                assert(nextStretch.litlen + nextStretch.mlen <= stretchPos);
1399
54.0M
                stretchPos -= nextStretch.litlen + nextStretch.mlen;
1400
54.0M
            }
1401
1402
            /* save sequences */
1403
41.7M
            DEBUGLOG(6, "sending selected sequences into seqStore");
1404
41.7M
            {   U32 storePos;
1405
137M
                for (storePos=storeStart; storePos <= storeEnd; storePos++) {
1406
95.7M
                    U32 const llen = opt[storePos].litlen;
1407
95.7M
                    U32 const mlen = opt[storePos].mlen;
1408
95.7M
                    U32 const offBase = opt[storePos].off;
1409
95.7M
                    U32 const advance = llen + mlen;
1410
95.7M
                    DEBUGLOG(6, "considering seq starting at %i, llen=%u, mlen=%u",
1411
95.7M
                                (int)(anchor - istart), (unsigned)llen, (unsigned)mlen);
1412
1413
95.7M
                    if (mlen==0) {  /* only literals => must be last "sequence", actually starting a new stream of sequences */
1414
0
                        assert(storePos == storeEnd);   /* must be last sequence */
1415
0
                        ip = anchor + llen;     /* last "sequence" is a bunch of literals => don't progress anchor */
1416
0
                        continue;   /* will finish */
1417
0
                    }
1418
1419
95.7M
                    assert(anchor + llen <= iend);
1420
95.7M
                    ZSTD_updateStats(optStatePtr, llen, anchor, offBase, mlen);
1421
95.7M
                    ZSTD_storeSeq(seqStore, llen, anchor, iend, offBase, mlen);
1422
95.7M
                    anchor += advance;
1423
95.7M
                    ip = anchor;
1424
95.7M
            }   }
1425
41.7M
            DEBUGLOG(7, "new offset history : %u, %u, %u", rep[0], rep[1], rep[2]);
1426
1427
            /* update all costs */
1428
41.7M
            ZSTD_setBasePrices(optStatePtr, optLevel);
1429
41.7M
        }
1430
41.7M
    }   /* while (ip < ilimit) */
1431
1432
    /* Return the last literals size */
1433
894k
    return (size_t)(iend - anchor);
1434
851k
}
1435
#endif /* build exclusions */
1436
1437
#ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR
1438
static size_t ZSTD_compressBlock_opt0(
1439
        ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
1440
        const void* src, size_t srcSize, const ZSTD_dictMode_e dictMode)
1441
247k
{
1442
247k
    return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 0 /* optLevel */, dictMode);
1443
247k
}
1444
#endif
1445
1446
#ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR
1447
static size_t ZSTD_compressBlock_opt2(
1448
        ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
1449
        const void* src, size_t srcSize, const ZSTD_dictMode_e dictMode)
1450
604k
{
1451
604k
    return ZSTD_compressBlock_opt_generic(ms, seqStore, rep, src, srcSize, 2 /* optLevel */, dictMode);
1452
604k
}
1453
#endif
1454
1455
#ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR
1456
size_t ZSTD_compressBlock_btopt(
1457
        ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
1458
        const void* src, size_t srcSize)
1459
211k
{
1460
211k
    DEBUGLOG(5, "ZSTD_compressBlock_btopt");
1461
211k
    return ZSTD_compressBlock_opt0(ms, seqStore, rep, src, srcSize, ZSTD_noDict);
1462
211k
}
1463
#endif
1464
1465
1466
1467
1468
#ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR
1469
/* ZSTD_initStats_ultra():
1470
 * make a first compression pass, just to seed stats with more accurate starting values.
1471
 * only works on first block, with no dictionary and no ldm.
1472
 * this function cannot error out, its narrow contract must be respected.
1473
 */
1474
static
1475
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
1476
void ZSTD_initStats_ultra(ZSTD_MatchState_t* ms,
1477
                          SeqStore_t* seqStore,
1478
                          U32 rep[ZSTD_REP_NUM],
1479
                    const void* src, size_t srcSize)
1480
34.0k
{
1481
34.0k
    U32 tmpRep[ZSTD_REP_NUM];  /* updated rep codes will sink here */
1482
34.0k
    ZSTD_memcpy(tmpRep, rep, sizeof(tmpRep));
1483
1484
34.0k
    DEBUGLOG(4, "ZSTD_initStats_ultra (srcSize=%zu)", srcSize);
1485
34.0k
    assert(ms->opt.litLengthSum == 0);    /* first block */
1486
34.0k
    assert(seqStore->sequences == seqStore->sequencesStart);   /* no ldm */
1487
34.0k
    assert(ms->window.dictLimit == ms->window.lowLimit);   /* no dictionary */
1488
34.0k
    assert(ms->window.dictLimit - ms->nextToUpdate <= 1);  /* no prefix (note: intentional overflow, defined as 2-complement) */
1489
1490
34.0k
    ZSTD_compressBlock_opt2(ms, seqStore, tmpRep, src, srcSize, ZSTD_noDict);   /* generate stats into ms->opt*/
1491
1492
    /* invalidate first scan from history, only keep entropy stats */
1493
34.0k
    ZSTD_resetSeqStore(seqStore);
1494
34.0k
    ms->window.base -= srcSize;
1495
34.0k
    ms->window.dictLimit += (U32)srcSize;
1496
34.0k
    ms->window.lowLimit = ms->window.dictLimit;
1497
34.0k
    ms->nextToUpdate = ms->window.dictLimit;
1498
1499
34.0k
}
1500
1501
size_t ZSTD_compressBlock_btultra(
1502
        ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
1503
        const void* src, size_t srcSize)
1504
207k
{
1505
207k
    DEBUGLOG(5, "ZSTD_compressBlock_btultra (srcSize=%zu)", srcSize);
1506
207k
    return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_noDict);
1507
207k
}
1508
1509
size_t ZSTD_compressBlock_btultra2(
1510
        ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
1511
        const void* src, size_t srcSize)
1512
299k
{
1513
299k
    U32 const curr = (U32)((const BYTE*)src - ms->window.base);
1514
299k
    DEBUGLOG(5, "ZSTD_compressBlock_btultra2 (srcSize=%zu)", srcSize);
1515
1516
    /* 2-passes strategy:
1517
     * this strategy makes a first pass over first block to collect statistics
1518
     * in order to seed next round's statistics with it.
1519
     * After 1st pass, function forgets history, and starts a new block.
1520
     * Consequently, this can only work if no data has been previously loaded in tables,
1521
     * aka, no dictionary, no prefix, no ldm preprocessing.
1522
     * The compression ratio gain is generally small (~0.5% on first block),
1523
     * the cost is 2x cpu time on first block. */
1524
299k
    assert(srcSize <= ZSTD_BLOCKSIZE_MAX);
1525
299k
    if ( (ms->opt.litLengthSum==0)   /* first block */
1526
45.3k
      && (seqStore->sequences == seqStore->sequencesStart)  /* no ldm */
1527
45.3k
      && (ms->window.dictLimit == ms->window.lowLimit)   /* no dictionary */
1528
45.3k
      && (curr == ms->window.dictLimit)    /* start of frame, nothing already loaded nor skipped */
1529
34.8k
      && (srcSize > ZSTD_PREDEF_THRESHOLD) /* input large enough to not employ default stats */
1530
299k
      ) {
1531
34.0k
        ZSTD_initStats_ultra(ms, seqStore, rep, src, srcSize);
1532
34.0k
    }
1533
1534
299k
    return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_noDict);
1535
299k
}
1536
#endif
1537
1538
#ifndef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR
1539
size_t ZSTD_compressBlock_btopt_dictMatchState(
1540
        ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
1541
        const void* src, size_t srcSize)
1542
15.1k
{
1543
15.1k
    return ZSTD_compressBlock_opt0(ms, seqStore, rep, src, srcSize, ZSTD_dictMatchState);
1544
15.1k
}
1545
1546
size_t ZSTD_compressBlock_btopt_extDict(
1547
        ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
1548
        const void* src, size_t srcSize)
1549
20.3k
{
1550
20.3k
    return ZSTD_compressBlock_opt0(ms, seqStore, rep, src, srcSize, ZSTD_extDict);
1551
20.3k
}
1552
#endif
1553
1554
#ifndef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR
1555
size_t ZSTD_compressBlock_btultra_dictMatchState(
1556
        ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
1557
        const void* src, size_t srcSize)
1558
15.4k
{
1559
15.4k
    return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_dictMatchState);
1560
15.4k
}
1561
1562
size_t ZSTD_compressBlock_btultra_extDict(
1563
        ZSTD_MatchState_t* ms, SeqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
1564
        const void* src, size_t srcSize)
1565
47.6k
{
1566
47.6k
    return ZSTD_compressBlock_opt2(ms, seqStore, rep, src, srcSize, ZSTD_extDict);
1567
47.6k
}
1568
#endif
1569
1570
/* note : no btultra2 variant for extDict nor dictMatchState,
1571
 * because btultra2 is not meant to work with dictionaries
1572
 * and is only specific for the first block (no prefix) */