xref: /freebsd/sys/contrib/zstd/lib/compress/zstd_fast.c (revision a0483764f3d68669e9b7db074bcbd45b050166bb)
10c16b537SWarner Losh /*
20c16b537SWarner Losh  * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
30c16b537SWarner Losh  * All rights reserved.
40c16b537SWarner Losh  *
50c16b537SWarner Losh  * This source code is licensed under both the BSD-style license (found in the
60c16b537SWarner Losh  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
70c16b537SWarner Losh  * in the COPYING file in the root directory of this source tree).
80c16b537SWarner Losh  * You may select, at your option, one of the above-listed licenses.
90c16b537SWarner Losh  */
100c16b537SWarner Losh 
11052d3c12SConrad Meyer #include "zstd_compress_internal.h"
120c16b537SWarner Losh #include "zstd_fast.h"
130c16b537SWarner Losh 
140c16b537SWarner Losh 
1519fcbaf1SConrad Meyer void ZSTD_fillHashTable(ZSTD_matchState_t* ms,
160f743729SConrad Meyer                         void const* end, ZSTD_dictTableLoadMethod_e dtlm)
170c16b537SWarner Losh {
180f743729SConrad Meyer     const ZSTD_compressionParameters* const cParams = &ms->cParams;
1919fcbaf1SConrad Meyer     U32* const hashTable = ms->hashTable;
2019fcbaf1SConrad Meyer     U32  const hBits = cParams->hashLog;
21*a0483764SConrad Meyer     U32  const mls = cParams->minMatch;
2219fcbaf1SConrad Meyer     const BYTE* const base = ms->window.base;
2319fcbaf1SConrad Meyer     const BYTE* ip = base + ms->nextToUpdate;
240c16b537SWarner Losh     const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
2519fcbaf1SConrad Meyer     const U32 fastHashFillStep = 3;
260c16b537SWarner Losh 
2719fcbaf1SConrad Meyer     /* Always insert every fastHashFillStep position into the hash table.
2819fcbaf1SConrad Meyer      * Insert the other positions if their hash entry is empty.
2919fcbaf1SConrad Meyer      */
30*a0483764SConrad Meyer     for ( ; ip + fastHashFillStep < iend + 2; ip += fastHashFillStep) {
3119fcbaf1SConrad Meyer         U32 const current = (U32)(ip - base);
32*a0483764SConrad Meyer         size_t const hash0 = ZSTD_hashPtr(ip, hBits, mls);
33*a0483764SConrad Meyer         hashTable[hash0] = current;
34*a0483764SConrad Meyer         if (dtlm == ZSTD_dtlm_fast) continue;
350f743729SConrad Meyer         /* Only load extra positions for ZSTD_dtlm_full */
36*a0483764SConrad Meyer         {   U32 p;
37*a0483764SConrad Meyer             for (p = 1; p < fastHashFillStep; ++p) {
38*a0483764SConrad Meyer                 size_t const hash = ZSTD_hashPtr(ip + p, hBits, mls);
39*a0483764SConrad Meyer                 if (hashTable[hash] == 0) {  /* not yet filled */
40*a0483764SConrad Meyer                     hashTable[hash] = current + p;
41*a0483764SConrad Meyer     }   }   }   }
4219fcbaf1SConrad Meyer }
430c16b537SWarner Losh 
440c16b537SWarner Losh FORCE_INLINE_TEMPLATE
4519fcbaf1SConrad Meyer size_t ZSTD_compressBlock_fast_generic(
4619fcbaf1SConrad Meyer         ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
4719fcbaf1SConrad Meyer         void const* src, size_t srcSize,
480f743729SConrad Meyer         U32 const mls, ZSTD_dictMode_e const dictMode)
490c16b537SWarner Losh {
500f743729SConrad Meyer     const ZSTD_compressionParameters* const cParams = &ms->cParams;
5119fcbaf1SConrad Meyer     U32* const hashTable = ms->hashTable;
520f743729SConrad Meyer     U32 const hlog = cParams->hashLog;
530f743729SConrad Meyer     /* support stepSize of 0 */
540f743729SConrad Meyer     U32 const stepSize = cParams->targetLength + !(cParams->targetLength);
5519fcbaf1SConrad Meyer     const BYTE* const base = ms->window.base;
560c16b537SWarner Losh     const BYTE* const istart = (const BYTE*)src;
570c16b537SWarner Losh     const BYTE* ip = istart;
580c16b537SWarner Losh     const BYTE* anchor = istart;
590f743729SConrad Meyer     const U32   prefixStartIndex = ms->window.dictLimit;
600f743729SConrad Meyer     const BYTE* const prefixStart = base + prefixStartIndex;
610c16b537SWarner Losh     const BYTE* const iend = istart + srcSize;
620c16b537SWarner Losh     const BYTE* const ilimit = iend - HASH_READ_SIZE;
6319fcbaf1SConrad Meyer     U32 offset_1=rep[0], offset_2=rep[1];
640c16b537SWarner Losh     U32 offsetSaved = 0;
650c16b537SWarner Losh 
660f743729SConrad Meyer     const ZSTD_matchState_t* const dms = ms->dictMatchState;
670f743729SConrad Meyer     const ZSTD_compressionParameters* const dictCParams =
680f743729SConrad Meyer                                      dictMode == ZSTD_dictMatchState ?
690f743729SConrad Meyer                                      &dms->cParams : NULL;
700f743729SConrad Meyer     const U32* const dictHashTable = dictMode == ZSTD_dictMatchState ?
710f743729SConrad Meyer                                      dms->hashTable : NULL;
720f743729SConrad Meyer     const U32 dictStartIndex       = dictMode == ZSTD_dictMatchState ?
730f743729SConrad Meyer                                      dms->window.dictLimit : 0;
740f743729SConrad Meyer     const BYTE* const dictBase     = dictMode == ZSTD_dictMatchState ?
750f743729SConrad Meyer                                      dms->window.base : NULL;
760f743729SConrad Meyer     const BYTE* const dictStart    = dictMode == ZSTD_dictMatchState ?
770f743729SConrad Meyer                                      dictBase + dictStartIndex : NULL;
780f743729SConrad Meyer     const BYTE* const dictEnd      = dictMode == ZSTD_dictMatchState ?
790f743729SConrad Meyer                                      dms->window.nextSrc : NULL;
800f743729SConrad Meyer     const U32 dictIndexDelta       = dictMode == ZSTD_dictMatchState ?
810f743729SConrad Meyer                                      prefixStartIndex - (U32)(dictEnd - dictBase) :
820f743729SConrad Meyer                                      0;
830f743729SConrad Meyer     const U32 dictAndPrefixLength  = (U32)(ip - prefixStart + dictEnd - dictStart);
840f743729SConrad Meyer     const U32 dictHLog             = dictMode == ZSTD_dictMatchState ?
850f743729SConrad Meyer                                      dictCParams->hashLog : hlog;
860f743729SConrad Meyer 
870f743729SConrad Meyer     assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState);
880f743729SConrad Meyer 
890f743729SConrad Meyer     /* otherwise, we would get index underflow when translating a dict index
900f743729SConrad Meyer      * into a local index */
910f743729SConrad Meyer     assert(dictMode != ZSTD_dictMatchState
920f743729SConrad Meyer         || prefixStartIndex >= (U32)(dictEnd - dictBase));
930f743729SConrad Meyer 
940c16b537SWarner Losh     /* init */
950f743729SConrad Meyer     ip += (dictAndPrefixLength == 0);
960f743729SConrad Meyer     if (dictMode == ZSTD_noDict) {
970f743729SConrad Meyer         U32 const maxRep = (U32)(ip - prefixStart);
980c16b537SWarner Losh         if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
990c16b537SWarner Losh         if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1000c16b537SWarner Losh     }
1010f743729SConrad Meyer     if (dictMode == ZSTD_dictMatchState) {
1020f743729SConrad Meyer         /* dictMatchState repCode checks don't currently handle repCode == 0
1030f743729SConrad Meyer          * disabling. */
1040f743729SConrad Meyer         assert(offset_1 <= dictAndPrefixLength);
1050f743729SConrad Meyer         assert(offset_2 <= dictAndPrefixLength);
1060f743729SConrad Meyer     }
1070c16b537SWarner Losh 
1080c16b537SWarner Losh     /* Main Search Loop */
1090c16b537SWarner Losh     while (ip < ilimit) {   /* < instead of <=, because repcode check at (ip+1) */
1100c16b537SWarner Losh         size_t mLength;
11119fcbaf1SConrad Meyer         size_t const h = ZSTD_hashPtr(ip, hlog, mls);
1120c16b537SWarner Losh         U32 const current = (U32)(ip-base);
1130c16b537SWarner Losh         U32 const matchIndex = hashTable[h];
1140c16b537SWarner Losh         const BYTE* match = base + matchIndex;
1150f743729SConrad Meyer         const U32 repIndex = current + 1 - offset_1;
1160f743729SConrad Meyer         const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
1170f743729SConrad Meyer                             && repIndex < prefixStartIndex) ?
1180f743729SConrad Meyer                                dictBase + (repIndex - dictIndexDelta) :
1190f743729SConrad Meyer                                base + repIndex;
1200c16b537SWarner Losh         hashTable[h] = current;   /* update hash table */
1210c16b537SWarner Losh 
1220f743729SConrad Meyer         if ( (dictMode == ZSTD_dictMatchState)
1230f743729SConrad Meyer           && ((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */
1240f743729SConrad Meyer           && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1250f743729SConrad Meyer             const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
1260f743729SConrad Meyer             mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
1270f743729SConrad Meyer             ip++;
1280f743729SConrad Meyer             ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
1290f743729SConrad Meyer         } else if ( dictMode == ZSTD_noDict
1300f743729SConrad Meyer                  && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) {
1310c16b537SWarner Losh             mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1320c16b537SWarner Losh             ip++;
13319fcbaf1SConrad Meyer             ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
1340f743729SConrad Meyer         } else if ( (matchIndex <= prefixStartIndex) ) {
1350f743729SConrad Meyer             if (dictMode == ZSTD_dictMatchState) {
1360f743729SConrad Meyer                 size_t const dictHash = ZSTD_hashPtr(ip, dictHLog, mls);
1370f743729SConrad Meyer                 U32 const dictMatchIndex = dictHashTable[dictHash];
1380f743729SConrad Meyer                 const BYTE* dictMatch = dictBase + dictMatchIndex;
1390f743729SConrad Meyer                 if (dictMatchIndex <= dictStartIndex ||
1400f743729SConrad Meyer                     MEM_read32(dictMatch) != MEM_read32(ip)) {
1410f743729SConrad Meyer                     assert(stepSize >= 1);
1420f743729SConrad Meyer                     ip += ((ip-anchor) >> kSearchStrength) + stepSize;
1430f743729SConrad Meyer                     continue;
1440c16b537SWarner Losh                 } else {
1450f743729SConrad Meyer                     /* found a dict match */
1460f743729SConrad Meyer                     U32 const offset = (U32)(current-dictMatchIndex-dictIndexDelta);
1470f743729SConrad Meyer                     mLength = ZSTD_count_2segments(ip+4, dictMatch+4, iend, dictEnd, prefixStart) + 4;
1480f743729SConrad Meyer                     while (((ip>anchor) & (dictMatch>dictStart))
1490f743729SConrad Meyer                          && (ip[-1] == dictMatch[-1])) {
1500f743729SConrad Meyer                         ip--; dictMatch--; mLength++;
1510f743729SConrad Meyer                     } /* catch up */
1520f743729SConrad Meyer                     offset_2 = offset_1;
1530f743729SConrad Meyer                     offset_1 = offset;
1540f743729SConrad Meyer                     ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1550f743729SConrad Meyer                 }
1560f743729SConrad Meyer             } else {
15719fcbaf1SConrad Meyer                 assert(stepSize >= 1);
15819fcbaf1SConrad Meyer                 ip += ((ip-anchor) >> kSearchStrength) + stepSize;
1590c16b537SWarner Losh                 continue;
1600c16b537SWarner Losh             }
1610f743729SConrad Meyer         } else if (MEM_read32(match) != MEM_read32(ip)) {
1620f743729SConrad Meyer             /* it's not a match, and we're not going to check the dictionary */
1630f743729SConrad Meyer             assert(stepSize >= 1);
1640f743729SConrad Meyer             ip += ((ip-anchor) >> kSearchStrength) + stepSize;
1650f743729SConrad Meyer             continue;
1660f743729SConrad Meyer         } else {
1670f743729SConrad Meyer             /* found a regular match */
1680f743729SConrad Meyer             U32 const offset = (U32)(ip-match);
1690c16b537SWarner Losh             mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1700f743729SConrad Meyer             while (((ip>anchor) & (match>prefixStart))
1710f743729SConrad Meyer                  && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1720c16b537SWarner Losh             offset_2 = offset_1;
1730c16b537SWarner Losh             offset_1 = offset;
17419fcbaf1SConrad Meyer             ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1750f743729SConrad Meyer         }
1760c16b537SWarner Losh 
1770c16b537SWarner Losh         /* match found */
1780c16b537SWarner Losh         ip += mLength;
1790c16b537SWarner Losh         anchor = ip;
1800c16b537SWarner Losh 
1810c16b537SWarner Losh         if (ip <= ilimit) {
1820c16b537SWarner Losh             /* Fill Table */
1830f743729SConrad Meyer             assert(base+current+2 > istart);  /* check base overflow */
18419fcbaf1SConrad Meyer             hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2;  /* here because current+2 could be > iend-8 */
18519fcbaf1SConrad Meyer             hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base);
1860f743729SConrad Meyer 
1870c16b537SWarner Losh             /* check immediate repcode */
1880f743729SConrad Meyer             if (dictMode == ZSTD_dictMatchState) {
1890f743729SConrad Meyer                 while (ip <= ilimit) {
1900f743729SConrad Meyer                     U32 const current2 = (U32)(ip-base);
1910f743729SConrad Meyer                     U32 const repIndex2 = current2 - offset_2;
1920f743729SConrad Meyer                     const BYTE* repMatch2 = repIndex2 < prefixStartIndex ?
1930f743729SConrad Meyer                             dictBase - dictIndexDelta + repIndex2 :
1940f743729SConrad Meyer                             base + repIndex2;
1950f743729SConrad Meyer                     if ( ((U32)((prefixStartIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */)
1960f743729SConrad Meyer                        && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1970f743729SConrad Meyer                         const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
1980f743729SConrad Meyer                         size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
1990f743729SConrad Meyer                         U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset;   /* swap offset_2 <=> offset_1 */
2000f743729SConrad Meyer                         ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
2010f743729SConrad Meyer                         hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2;
2020f743729SConrad Meyer                         ip += repLength2;
2030f743729SConrad Meyer                         anchor = ip;
2040f743729SConrad Meyer                         continue;
2050f743729SConrad Meyer                     }
2060f743729SConrad Meyer                     break;
2070f743729SConrad Meyer                 }
2080f743729SConrad Meyer             }
2090f743729SConrad Meyer 
2100f743729SConrad Meyer             if (dictMode == ZSTD_noDict) {
2110c16b537SWarner Losh                 while ( (ip <= ilimit)
2120c16b537SWarner Losh                      && ( (offset_2>0)
2130c16b537SWarner Losh                         & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
2140c16b537SWarner Losh                     /* store sequence */
2150c16b537SWarner Losh                     size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
2160f743729SConrad Meyer                     U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff;  /* swap offset_2 <=> offset_1 */
21719fcbaf1SConrad Meyer                     hashTable[ZSTD_hashPtr(ip, hlog, mls)] = (U32)(ip-base);
21819fcbaf1SConrad Meyer                     ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH);
2190c16b537SWarner Losh                     ip += rLength;
2200c16b537SWarner Losh                     anchor = ip;
2210c16b537SWarner Losh                     continue;   /* faster when present ... (?) */
2220f743729SConrad Meyer     }   }   }   }
2230c16b537SWarner Losh 
2240c16b537SWarner Losh     /* save reps for next block */
22519fcbaf1SConrad Meyer     rep[0] = offset_1 ? offset_1 : offsetSaved;
22619fcbaf1SConrad Meyer     rep[1] = offset_2 ? offset_2 : offsetSaved;
2270c16b537SWarner Losh 
2280c16b537SWarner Losh     /* Return the last literals size */
2290c16b537SWarner Losh     return iend - anchor;
2300c16b537SWarner Losh }
2310c16b537SWarner Losh 
2320c16b537SWarner Losh 
23319fcbaf1SConrad Meyer size_t ZSTD_compressBlock_fast(
23419fcbaf1SConrad Meyer         ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
2350f743729SConrad Meyer         void const* src, size_t srcSize)
2360c16b537SWarner Losh {
2370f743729SConrad Meyer     ZSTD_compressionParameters const* cParams = &ms->cParams;
238*a0483764SConrad Meyer     U32 const mls = cParams->minMatch;
2390f743729SConrad Meyer     assert(ms->dictMatchState == NULL);
2400c16b537SWarner Losh     switch(mls)
2410c16b537SWarner Losh     {
2420c16b537SWarner Losh     default: /* includes case 3 */
2430c16b537SWarner Losh     case 4 :
2440f743729SConrad Meyer         return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_noDict);
2450c16b537SWarner Losh     case 5 :
2460f743729SConrad Meyer         return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_noDict);
2470c16b537SWarner Losh     case 6 :
2480f743729SConrad Meyer         return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_noDict);
2490c16b537SWarner Losh     case 7 :
2500f743729SConrad Meyer         return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_noDict);
2510f743729SConrad Meyer     }
2520f743729SConrad Meyer }
2530f743729SConrad Meyer 
2540f743729SConrad Meyer size_t ZSTD_compressBlock_fast_dictMatchState(
2550f743729SConrad Meyer         ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
2560f743729SConrad Meyer         void const* src, size_t srcSize)
2570f743729SConrad Meyer {
2580f743729SConrad Meyer     ZSTD_compressionParameters const* cParams = &ms->cParams;
259*a0483764SConrad Meyer     U32 const mls = cParams->minMatch;
2600f743729SConrad Meyer     assert(ms->dictMatchState != NULL);
2610f743729SConrad Meyer     switch(mls)
2620f743729SConrad Meyer     {
2630f743729SConrad Meyer     default: /* includes case 3 */
2640f743729SConrad Meyer     case 4 :
2650f743729SConrad Meyer         return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 4, ZSTD_dictMatchState);
2660f743729SConrad Meyer     case 5 :
2670f743729SConrad Meyer         return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 5, ZSTD_dictMatchState);
2680f743729SConrad Meyer     case 6 :
2690f743729SConrad Meyer         return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 6, ZSTD_dictMatchState);
2700f743729SConrad Meyer     case 7 :
2710f743729SConrad Meyer         return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 7, ZSTD_dictMatchState);
2720c16b537SWarner Losh     }
2730c16b537SWarner Losh }
2740c16b537SWarner Losh 
2750c16b537SWarner Losh 
27619fcbaf1SConrad Meyer static size_t ZSTD_compressBlock_fast_extDict_generic(
27719fcbaf1SConrad Meyer         ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
2780f743729SConrad Meyer         void const* src, size_t srcSize, U32 const mls)
2790c16b537SWarner Losh {
2800f743729SConrad Meyer     const ZSTD_compressionParameters* const cParams = &ms->cParams;
2810f743729SConrad Meyer     U32* const hashTable = ms->hashTable;
2820f743729SConrad Meyer     U32 const hlog = cParams->hashLog;
2830f743729SConrad Meyer     /* support stepSize of 0 */
2840f743729SConrad Meyer     U32 const stepSize = cParams->targetLength + !(cParams->targetLength);
28519fcbaf1SConrad Meyer     const BYTE* const base = ms->window.base;
28619fcbaf1SConrad Meyer     const BYTE* const dictBase = ms->window.dictBase;
2870c16b537SWarner Losh     const BYTE* const istart = (const BYTE*)src;
2880c16b537SWarner Losh     const BYTE* ip = istart;
2890c16b537SWarner Losh     const BYTE* anchor = istart;
2900f743729SConrad Meyer     const U32   dictStartIndex = ms->window.lowLimit;
2910f743729SConrad Meyer     const BYTE* const dictStart = dictBase + dictStartIndex;
2920f743729SConrad Meyer     const U32   prefixStartIndex = ms->window.dictLimit;
2930f743729SConrad Meyer     const BYTE* const prefixStart = base + prefixStartIndex;
2940f743729SConrad Meyer     const BYTE* const dictEnd = dictBase + prefixStartIndex;
2950c16b537SWarner Losh     const BYTE* const iend = istart + srcSize;
2960c16b537SWarner Losh     const BYTE* const ilimit = iend - 8;
29719fcbaf1SConrad Meyer     U32 offset_1=rep[0], offset_2=rep[1];
2980c16b537SWarner Losh 
2990c16b537SWarner Losh     /* Search Loop */
3000c16b537SWarner Losh     while (ip < ilimit) {  /* < instead of <=, because (ip+1) */
30119fcbaf1SConrad Meyer         const size_t h = ZSTD_hashPtr(ip, hlog, mls);
3020c16b537SWarner Losh         const U32    matchIndex = hashTable[h];
3030f743729SConrad Meyer         const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base;
3040c16b537SWarner Losh         const BYTE*  match = matchBase + matchIndex;
3050c16b537SWarner Losh         const U32    current = (U32)(ip-base);
3060f743729SConrad Meyer         const U32    repIndex = current + 1 - offset_1;
3070f743729SConrad Meyer         const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base;
3080f743729SConrad Meyer         const BYTE* const repMatch = repBase + repIndex;
3090c16b537SWarner Losh         size_t mLength;
3100c16b537SWarner Losh         hashTable[h] = current;   /* update hash table */
3110f743729SConrad Meyer         assert(offset_1 <= current +1);   /* check repIndex */
3120c16b537SWarner Losh 
3130f743729SConrad Meyer         if ( (((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > dictStartIndex))
3140c16b537SWarner Losh            && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
3150f743729SConrad Meyer             const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
3160f743729SConrad Meyer             mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
3170c16b537SWarner Losh             ip++;
31819fcbaf1SConrad Meyer             ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
3190c16b537SWarner Losh         } else {
3200f743729SConrad Meyer             if ( (matchIndex < dictStartIndex) ||
3210c16b537SWarner Losh                  (MEM_read32(match) != MEM_read32(ip)) ) {
32219fcbaf1SConrad Meyer                 assert(stepSize >= 1);
32319fcbaf1SConrad Meyer                 ip += ((ip-anchor) >> kSearchStrength) + stepSize;
3240c16b537SWarner Losh                 continue;
3250c16b537SWarner Losh             }
3260f743729SConrad Meyer             {   const BYTE* matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
3270f743729SConrad Meyer                 const BYTE* lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
3280c16b537SWarner Losh                 U32 offset;
3290f743729SConrad Meyer                 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
3300c16b537SWarner Losh                 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; }   /* catch up */
3310c16b537SWarner Losh                 offset = current - matchIndex;
3320c16b537SWarner Losh                 offset_2 = offset_1;
3330c16b537SWarner Losh                 offset_1 = offset;
33419fcbaf1SConrad Meyer                 ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
3350c16b537SWarner Losh         }   }
3360c16b537SWarner Losh 
3370c16b537SWarner Losh         /* found a match : store it */
3380c16b537SWarner Losh         ip += mLength;
3390c16b537SWarner Losh         anchor = ip;
3400c16b537SWarner Losh 
3410c16b537SWarner Losh         if (ip <= ilimit) {
3420c16b537SWarner Losh             /* Fill Table */
34319fcbaf1SConrad Meyer             hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2;
34419fcbaf1SConrad Meyer             hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base);
3450c16b537SWarner Losh             /* check immediate repcode */
3460c16b537SWarner Losh             while (ip <= ilimit) {
3470c16b537SWarner Losh                 U32 const current2 = (U32)(ip-base);
3480c16b537SWarner Losh                 U32 const repIndex2 = current2 - offset_2;
3490f743729SConrad Meyer                 const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
3500f743729SConrad Meyer                 if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (repIndex2 > dictStartIndex))  /* intentional overflow */
3510c16b537SWarner Losh                    && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
3520f743729SConrad Meyer                     const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
3530f743729SConrad Meyer                     size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
3540c16b537SWarner Losh                     U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset;   /* swap offset_2 <=> offset_1 */
35519fcbaf1SConrad Meyer                     ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
35619fcbaf1SConrad Meyer                     hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2;
3570c16b537SWarner Losh                     ip += repLength2;
3580c16b537SWarner Losh                     anchor = ip;
3590c16b537SWarner Losh                     continue;
3600c16b537SWarner Losh                 }
3610c16b537SWarner Losh                 break;
3620c16b537SWarner Losh     }   }   }
3630c16b537SWarner Losh 
3640c16b537SWarner Losh     /* save reps for next block */
36519fcbaf1SConrad Meyer     rep[0] = offset_1;
36619fcbaf1SConrad Meyer     rep[1] = offset_2;
3670c16b537SWarner Losh 
3680c16b537SWarner Losh     /* Return the last literals size */
3690c16b537SWarner Losh     return iend - anchor;
3700c16b537SWarner Losh }
3710c16b537SWarner Losh 
3720c16b537SWarner Losh 
37319fcbaf1SConrad Meyer size_t ZSTD_compressBlock_fast_extDict(
37419fcbaf1SConrad Meyer         ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
3750f743729SConrad Meyer         void const* src, size_t srcSize)
3760c16b537SWarner Losh {
3770f743729SConrad Meyer     ZSTD_compressionParameters const* cParams = &ms->cParams;
378*a0483764SConrad Meyer     U32 const mls = cParams->minMatch;
3790c16b537SWarner Losh     switch(mls)
3800c16b537SWarner Losh     {
3810c16b537SWarner Losh     default: /* includes case 3 */
3820c16b537SWarner Losh     case 4 :
3830f743729SConrad Meyer         return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 4);
3840c16b537SWarner Losh     case 5 :
3850f743729SConrad Meyer         return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 5);
3860c16b537SWarner Losh     case 6 :
3870f743729SConrad Meyer         return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 6);
3880c16b537SWarner Losh     case 7 :
3890f743729SConrad Meyer         return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 7);
3900c16b537SWarner Losh     }
3910c16b537SWarner Losh }
392