Coverage Report

Created: 2026-10-17 07:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tdengine/contrib/TSZ/zstd/compress/zstd_fast.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
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 "zstd_fast.h"
13
14
15
void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
16
                        ZSTD_compressionParameters const* cParams,
17
                        void const* end, ZSTD_dictTableLoadMethod_e dtlm)
18
0
{
19
0
    U32* const hashTable = ms->hashTable;
20
0
    U32  const hBits = cParams->hashLog;
21
0
    U32  const mls = cParams->searchLength;
22
0
    const BYTE* const base = ms->window.base;
23
0
    const BYTE* ip = base + ms->nextToUpdate;
24
0
    const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
25
0
    const U32 fastHashFillStep = 3;
26
27
    /* Always insert every fastHashFillStep position into the hash table.
28
     * Insert the other positions if their hash entry is empty.
29
     */
30
0
    for (; ip + fastHashFillStep - 1 <= iend; ip += fastHashFillStep) {
31
0
        U32 const current = (U32)(ip - base);
32
0
        U32 i;
33
0
        for (i = 0; i < fastHashFillStep; ++i) {
34
0
            size_t const hash = ZSTD_hashPtr(ip + i, hBits, mls);
35
0
            if (i == 0 || hashTable[hash] == 0)
36
0
                hashTable[hash] = current + i;
37
            /* Only load extra positions for ZSTD_dtlm_full */
38
0
            if (dtlm == ZSTD_dtlm_fast)
39
0
                break;
40
0
        }
41
0
    }
42
0
}
43
44
FORCE_INLINE_TEMPLATE
45
size_t ZSTD_compressBlock_fast_generic(
46
        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
47
        void const* src, size_t srcSize,
48
        U32 const hlog, U32 stepSize, U32 const mls,
49
        ZSTD_dictMode_e const dictMode)
50
0
{
51
0
    U32* const hashTable = ms->hashTable;
52
0
    const BYTE* const base = ms->window.base;
53
0
    const BYTE* const istart = (const BYTE*)src;
54
0
    const BYTE* ip = istart;
55
0
    const BYTE* anchor = istart;
56
0
    const U32   prefixStartIndex = ms->window.dictLimit;
57
0
    const BYTE* const prefixStart = base + prefixStartIndex;
58
0
    const BYTE* const iend = istart + srcSize;
59
0
    const BYTE* const ilimit = iend - HASH_READ_SIZE;
60
0
    U32 offset_1=rep[0], offset_2=rep[1];
61
0
    U32 offsetSaved = 0;
62
63
0
    const ZSTD_matchState_t* const dms = ms->dictMatchState;
64
0
    const U32* const dictHashTable = dictMode == ZSTD_dictMatchState ?
65
0
                                     dms->hashTable : NULL;
66
0
    const U32 dictStartIndex       = dictMode == ZSTD_dictMatchState ?
67
0
                                     dms->window.dictLimit : 0;
68
0
    const BYTE* const dictBase     = dictMode == ZSTD_dictMatchState ?
69
0
                                     dms->window.base : NULL;
70
0
    const BYTE* const dictStart    = dictMode == ZSTD_dictMatchState ?
71
0
                                     dictBase + dictStartIndex : NULL;
72
0
    const BYTE* const dictEnd      = dictMode == ZSTD_dictMatchState ?
73
0
                                     dms->window.nextSrc : NULL;
74
0
    const U32 dictIndexDelta       = dictMode == ZSTD_dictMatchState ?
75
0
                                     prefixStartIndex - (U32)(dictEnd - dictBase) :
76
0
                                     0;
77
0
    const U32 dictAndPrefixLength  = (U32)(ip - prefixStart + dictEnd - dictStart);
78
79
0
    assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState);
80
81
    /* otherwise, we would get index underflow when translating a dict index
82
     * into a local index */
83
0
    assert(dictMode != ZSTD_dictMatchState
84
0
        || prefixStartIndex >= (U32)(dictEnd - dictBase));
85
86
    /* init */
87
0
    stepSize += !stepSize;  /* support stepSize of 0 */
88
0
    ip += (dictAndPrefixLength == 0);
89
0
    if (dictMode == ZSTD_noDict) {
90
0
        U32 const maxRep = (U32)(ip - prefixStart);
91
0
        if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
92
0
        if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
93
0
    }
94
0
    if (dictMode == ZSTD_dictMatchState) {
95
        /* dictMatchState repCode checks don't currently handle repCode == 0
96
         * disabling. */
97
0
        assert(offset_1 <= dictAndPrefixLength);
98
0
        assert(offset_2 <= dictAndPrefixLength);
99
0
    }
100
101
    /* Main Search Loop */
102
0
    while (ip < ilimit) {   /* < instead of <=, because repcode check at (ip+1) */
103
0
        size_t mLength;
104
0
        size_t const h = ZSTD_hashPtr(ip, hlog, mls);
105
0
        U32 const current = (U32)(ip-base);
106
0
        U32 const matchIndex = hashTable[h];
107
0
        const BYTE* match = base + matchIndex;
108
0
        const U32 repIndex = current + 1 - offset_1;
109
0
        const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
110
0
                            && repIndex < prefixStartIndex) ?
111
0
                               dictBase + (repIndex - dictIndexDelta) :
112
0
                               base + repIndex;
113
0
        hashTable[h] = current;   /* update hash table */
114
115
0
        if ( (dictMode == ZSTD_dictMatchState)
116
0
          && ((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */
117
0
          && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
118
0
            const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
119
0
            mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
120
0
            ip++;
121
0
            ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
122
0
        } else if ( dictMode == ZSTD_noDict
123
0
                 && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) {
124
0
            mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
125
0
            ip++;
126
0
            ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
127
0
        } else if ( (matchIndex <= prefixStartIndex)
128
0
                 || (MEM_read32(match) != MEM_read32(ip)) ) {
129
0
            if (dictMode == ZSTD_dictMatchState) {
130
0
                U32 const dictMatchIndex = dictHashTable[h];
131
0
                const BYTE* dictMatch = dictBase + dictMatchIndex;
132
0
                if (dictMatchIndex <= dictStartIndex ||
133
0
                    MEM_read32(dictMatch) != MEM_read32(ip)) {
134
0
                    assert(stepSize >= 1);
135
0
                    ip += ((ip-anchor) >> kSearchStrength) + stepSize;
136
0
                    continue;
137
0
                } else {
138
                    /* found a dict match */
139
0
                    U32 const offset = (U32)(current-dictMatchIndex-dictIndexDelta);
140
0
                    mLength = ZSTD_count_2segments(ip+4, dictMatch+4, iend, dictEnd, prefixStart) + 4;
141
0
                    while (((ip>anchor) & (dictMatch>dictStart))
142
0
                         && (ip[-1] == dictMatch[-1])) {
143
0
                        ip--; dictMatch--; mLength++;
144
0
                    } /* catch up */
145
0
                    offset_2 = offset_1;
146
0
                    offset_1 = offset;
147
0
                    ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
148
0
                }
149
0
            } else {
150
0
                assert(stepSize >= 1);
151
0
                ip += ((ip-anchor) >> kSearchStrength) + stepSize;
152
0
                continue;
153
0
            }
154
0
        } else {
155
            /* found a regular match */
156
0
            U32 const offset = (U32)(ip-match);
157
0
            mLength = ZSTD_count(ip+4, match+4, iend) + 4;
158
0
            while (((ip>anchor) & (match>prefixStart))
159
0
                 && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
160
0
            offset_2 = offset_1;
161
0
            offset_1 = offset;
162
0
            ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
163
0
        }
164
165
        /* match found */
166
0
        ip += mLength;
167
0
        anchor = ip;
168
169
0
        if (ip <= ilimit) {
170
            /* Fill Table */
171
0
            hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2;  /* here because current+2 could be > iend-8 */
172
0
            hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base);
173
174
            /* check immediate repcode */
175
0
            if (dictMode == ZSTD_dictMatchState) {
176
0
                while (ip <= ilimit) {
177
0
                    U32 const current2 = (U32)(ip-base);
178
0
                    U32 const repIndex2 = current2 - offset_2;
179
0
                    const BYTE* repMatch2 = repIndex2 < prefixStartIndex ?
180
0
                            dictBase - dictIndexDelta + repIndex2 :
181
0
                            base + repIndex2;
182
0
                    if ( ((U32)((prefixStartIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */)
183
0
                       && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
184
0
                        const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
185
0
                        size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
186
0
                        U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset;   /* swap offset_2 <=> offset_1 */
187
0
                        ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
188
0
                        hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2;
189
0
                        ip += repLength2;
190
0
                        anchor = ip;
191
0
                        continue;
192
0
                    }
193
0
                    break;
194
0
                }
195
0
            }
196
197
0
            if (dictMode == ZSTD_noDict) {
198
0
                while ( (ip <= ilimit)
199
0
                     && ( (offset_2>0)
200
0
                        & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
201
                    /* store sequence */
202
0
                    size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
203
0
                    U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff;  /* swap offset_2 <=> offset_1 */
204
0
                    hashTable[ZSTD_hashPtr(ip, hlog, mls)] = (U32)(ip-base);
205
0
                    ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH);
206
0
                    ip += rLength;
207
0
                    anchor = ip;
208
0
                    continue;   /* faster when present ... (?) */
209
0
    }   }   }   }
210
211
    /* save reps for next block */
212
0
    rep[0] = offset_1 ? offset_1 : offsetSaved;
213
0
    rep[1] = offset_2 ? offset_2 : offsetSaved;
214
215
    /* Return the last literals size */
216
0
    return iend - anchor;
217
0
}
218
219
220
size_t ZSTD_compressBlock_fast(
221
        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
222
        ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
223
0
{
224
0
    U32 const hlog = cParams->hashLog;
225
0
    U32 const mls = cParams->searchLength;
226
0
    U32 const stepSize = cParams->targetLength;
227
0
    assert(ms->dictMatchState == NULL);
228
0
    switch(mls)
229
0
    {
230
0
    default: /* includes case 3 */
231
0
    case 4 :
232
0
        return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 4, ZSTD_noDict);
233
0
    case 5 :
234
0
        return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 5, ZSTD_noDict);
235
0
    case 6 :
236
0
        return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 6, ZSTD_noDict);
237
0
    case 7 :
238
0
        return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 7, ZSTD_noDict);
239
0
    }
240
0
}
241
242
size_t ZSTD_compressBlock_fast_dictMatchState(
243
        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
244
        ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
245
0
{
246
0
    U32 const hlog = cParams->hashLog;
247
0
    U32 const mls = cParams->searchLength;
248
0
    U32 const stepSize = cParams->targetLength;
249
0
    assert(ms->dictMatchState != NULL);
250
0
    switch(mls)
251
0
    {
252
0
    default: /* includes case 3 */
253
0
    case 4 :
254
0
        return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 4, ZSTD_dictMatchState);
255
0
    case 5 :
256
0
        return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 5, ZSTD_dictMatchState);
257
0
    case 6 :
258
0
        return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 6, ZSTD_dictMatchState);
259
0
    case 7 :
260
0
        return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 7, ZSTD_dictMatchState);
261
0
    }
262
0
}
263
264
265
static size_t ZSTD_compressBlock_fast_extDict_generic(
266
        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
267
        void const* src, size_t srcSize,
268
        U32 const hlog, U32 stepSize, U32 const mls)
269
0
{
270
0
    U32* hashTable = ms->hashTable;
271
0
    const BYTE* const base = ms->window.base;
272
0
    const BYTE* const dictBase = ms->window.dictBase;
273
0
    const BYTE* const istart = (const BYTE*)src;
274
0
    const BYTE* ip = istart;
275
0
    const BYTE* anchor = istart;
276
0
    const U32   dictStartIndex = ms->window.lowLimit;
277
0
    const BYTE* const dictStart = dictBase + dictStartIndex;
278
0
    const U32   prefixStartIndex = ms->window.dictLimit;
279
0
    const BYTE* const prefixStart = base + prefixStartIndex;
280
0
    const BYTE* const dictEnd = dictBase + prefixStartIndex;
281
0
    const BYTE* const iend = istart + srcSize;
282
0
    const BYTE* const ilimit = iend - 8;
283
0
    U32 offset_1=rep[0], offset_2=rep[1];
284
285
0
    stepSize += !stepSize;   /* support stepSize == 0 */
286
287
    /* Search Loop */
288
0
    while (ip < ilimit) {  /* < instead of <=, because (ip+1) */
289
0
        const size_t h = ZSTD_hashPtr(ip, hlog, mls);
290
0
        const U32    matchIndex = hashTable[h];
291
0
        const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base;
292
0
        const BYTE*  match = matchBase + matchIndex;
293
0
        const U32    current = (U32)(ip-base);
294
0
        const U32    repIndex = current + 1 - offset_1;
295
0
        const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base;
296
0
        const BYTE* const repMatch = repBase + repIndex;
297
0
        size_t mLength;
298
0
        hashTable[h] = current;   /* update hash table */
299
0
        assert(offset_1 <= current +1);   /* check repIndex */
300
301
0
        if ( (((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > dictStartIndex))
302
0
           && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
303
0
            const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
304
0
            mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
305
0
            ip++;
306
0
            ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
307
0
        } else {
308
0
            if ( (matchIndex < dictStartIndex) ||
309
0
                 (MEM_read32(match) != MEM_read32(ip)) ) {
310
0
                assert(stepSize >= 1);
311
0
                ip += ((ip-anchor) >> kSearchStrength) + stepSize;
312
0
                continue;
313
0
            }
314
0
            {   const BYTE* matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
315
0
                const BYTE* lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
316
0
                U32 offset;
317
0
                mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
318
0
                while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; }   /* catch up */
319
0
                offset = current - matchIndex;
320
0
                offset_2 = offset_1;
321
0
                offset_1 = offset;
322
0
                ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
323
0
        }   }
324
325
        /* found a match : store it */
326
0
        ip += mLength;
327
0
        anchor = ip;
328
329
0
        if (ip <= ilimit) {
330
            /* Fill Table */
331
0
            hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2;
332
0
            hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base);
333
            /* check immediate repcode */
334
0
            while (ip <= ilimit) {
335
0
                U32 const current2 = (U32)(ip-base);
336
0
                U32 const repIndex2 = current2 - offset_2;
337
0
                const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
338
0
                if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (repIndex2 > dictStartIndex))  /* intentional overflow */
339
0
                   && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
340
0
                    const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
341
0
                    size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
342
0
                    U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset;   /* swap offset_2 <=> offset_1 */
343
0
                    ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
344
0
                    hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2;
345
0
                    ip += repLength2;
346
0
                    anchor = ip;
347
0
                    continue;
348
0
                }
349
0
                break;
350
0
    }   }   }
351
352
    /* save reps for next block */
353
0
    rep[0] = offset_1;
354
0
    rep[1] = offset_2;
355
356
    /* Return the last literals size */
357
0
    return iend - anchor;
358
0
}
359
360
361
size_t ZSTD_compressBlock_fast_extDict(
362
        ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
363
        ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
364
0
{
365
0
    U32 const hlog = cParams->hashLog;
366
0
    U32 const mls = cParams->searchLength;
367
0
    U32 const stepSize = cParams->targetLength;
368
0
    switch(mls)
369
0
    {
370
0
    default: /* includes case 3 */
371
0
    case 4 :
372
0
        return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 4);
373
0
    case 5 :
374
0
        return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 5);
375
0
    case 6 :
376
0
        return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 6);
377
0
    case 7 :
378
0
        return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, hlog, stepSize, 7);
379
0
    }
380
0
}