1e0c1b49fSNick Terrell /* 2e0c1b49fSNick Terrell * Copyright (c) Yann Collet, Facebook, Inc. 3e0c1b49fSNick Terrell * All rights reserved. 4e0c1b49fSNick Terrell * 5e0c1b49fSNick Terrell * This source code is licensed under both the BSD-style license (found in the 6e0c1b49fSNick Terrell * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7e0c1b49fSNick Terrell * in the COPYING file in the root directory of this source tree). 8e0c1b49fSNick Terrell * You may select, at your option, one of the above-listed licenses. 9e0c1b49fSNick Terrell */ 10e0c1b49fSNick Terrell 11e0c1b49fSNick Terrell #include "zstd_compress_internal.h" /* ZSTD_hashPtr, ZSTD_count, ZSTD_storeSeq */ 12e0c1b49fSNick Terrell #include "zstd_fast.h" 13e0c1b49fSNick Terrell 14e0c1b49fSNick Terrell 15e0c1b49fSNick Terrell void ZSTD_fillHashTable(ZSTD_matchState_t* ms, 16e0c1b49fSNick Terrell const void* const end, 17e0c1b49fSNick Terrell ZSTD_dictTableLoadMethod_e dtlm) 18e0c1b49fSNick Terrell { 19e0c1b49fSNick Terrell const ZSTD_compressionParameters* const cParams = &ms->cParams; 20e0c1b49fSNick Terrell U32* const hashTable = ms->hashTable; 21e0c1b49fSNick Terrell U32 const hBits = cParams->hashLog; 22e0c1b49fSNick Terrell U32 const mls = cParams->minMatch; 23e0c1b49fSNick Terrell const BYTE* const base = ms->window.base; 24e0c1b49fSNick Terrell const BYTE* ip = base + ms->nextToUpdate; 25e0c1b49fSNick Terrell const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE; 26e0c1b49fSNick Terrell const U32 fastHashFillStep = 3; 27e0c1b49fSNick Terrell 28e0c1b49fSNick Terrell /* Always insert every fastHashFillStep position into the hash table. 29e0c1b49fSNick Terrell * Insert the other positions if their hash entry is empty. 30e0c1b49fSNick Terrell */ 31e0c1b49fSNick Terrell for ( ; ip + fastHashFillStep < iend + 2; ip += fastHashFillStep) { 32e0c1b49fSNick Terrell U32 const curr = (U32)(ip - base); 33e0c1b49fSNick Terrell size_t const hash0 = ZSTD_hashPtr(ip, hBits, mls); 34e0c1b49fSNick Terrell hashTable[hash0] = curr; 35e0c1b49fSNick Terrell if (dtlm == ZSTD_dtlm_fast) continue; 36e0c1b49fSNick Terrell /* Only load extra positions for ZSTD_dtlm_full */ 37e0c1b49fSNick Terrell { U32 p; 38e0c1b49fSNick Terrell for (p = 1; p < fastHashFillStep; ++p) { 39e0c1b49fSNick Terrell size_t const hash = ZSTD_hashPtr(ip + p, hBits, mls); 40e0c1b49fSNick Terrell if (hashTable[hash] == 0) { /* not yet filled */ 41e0c1b49fSNick Terrell hashTable[hash] = curr + p; 42e0c1b49fSNick Terrell } } } } 43e0c1b49fSNick Terrell } 44e0c1b49fSNick Terrell 45e0c1b49fSNick Terrell 46*2aa14b1aSNick Terrell /* 47*2aa14b1aSNick Terrell * If you squint hard enough (and ignore repcodes), the search operation at any 48*2aa14b1aSNick Terrell * given position is broken into 4 stages: 49*2aa14b1aSNick Terrell * 50*2aa14b1aSNick Terrell * 1. Hash (map position to hash value via input read) 51*2aa14b1aSNick Terrell * 2. Lookup (map hash val to index via hashtable read) 52*2aa14b1aSNick Terrell * 3. Load (map index to value at that position via input read) 53*2aa14b1aSNick Terrell * 4. Compare 54*2aa14b1aSNick Terrell * 55*2aa14b1aSNick Terrell * Each of these steps involves a memory read at an address which is computed 56*2aa14b1aSNick Terrell * from the previous step. This means these steps must be sequenced and their 57*2aa14b1aSNick Terrell * latencies are cumulative. 58*2aa14b1aSNick Terrell * 59*2aa14b1aSNick Terrell * Rather than do 1->2->3->4 sequentially for a single position before moving 60*2aa14b1aSNick Terrell * onto the next, this implementation interleaves these operations across the 61*2aa14b1aSNick Terrell * next few positions: 62*2aa14b1aSNick Terrell * 63*2aa14b1aSNick Terrell * R = Repcode Read & Compare 64*2aa14b1aSNick Terrell * H = Hash 65*2aa14b1aSNick Terrell * T = Table Lookup 66*2aa14b1aSNick Terrell * M = Match Read & Compare 67*2aa14b1aSNick Terrell * 68*2aa14b1aSNick Terrell * Pos | Time --> 69*2aa14b1aSNick Terrell * ----+------------------- 70*2aa14b1aSNick Terrell * N | ... M 71*2aa14b1aSNick Terrell * N+1 | ... TM 72*2aa14b1aSNick Terrell * N+2 | R H T M 73*2aa14b1aSNick Terrell * N+3 | H TM 74*2aa14b1aSNick Terrell * N+4 | R H T M 75*2aa14b1aSNick Terrell * N+5 | H ... 76*2aa14b1aSNick Terrell * N+6 | R ... 77*2aa14b1aSNick Terrell * 78*2aa14b1aSNick Terrell * This is very much analogous to the pipelining of execution in a CPU. And just 79*2aa14b1aSNick Terrell * like a CPU, we have to dump the pipeline when we find a match (i.e., take a 80*2aa14b1aSNick Terrell * branch). 81*2aa14b1aSNick Terrell * 82*2aa14b1aSNick Terrell * When this happens, we throw away our current state, and do the following prep 83*2aa14b1aSNick Terrell * to re-enter the loop: 84*2aa14b1aSNick Terrell * 85*2aa14b1aSNick Terrell * Pos | Time --> 86*2aa14b1aSNick Terrell * ----+------------------- 87*2aa14b1aSNick Terrell * N | H T 88*2aa14b1aSNick Terrell * N+1 | H 89*2aa14b1aSNick Terrell * 90*2aa14b1aSNick Terrell * This is also the work we do at the beginning to enter the loop initially. 91*2aa14b1aSNick Terrell */ 92e0c1b49fSNick Terrell FORCE_INLINE_TEMPLATE size_t 93*2aa14b1aSNick Terrell ZSTD_compressBlock_fast_noDict_generic( 94e0c1b49fSNick Terrell ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 95e0c1b49fSNick Terrell void const* src, size_t srcSize, 96*2aa14b1aSNick Terrell U32 const mls, U32 const hasStep) 97e0c1b49fSNick Terrell { 98e0c1b49fSNick Terrell const ZSTD_compressionParameters* const cParams = &ms->cParams; 99e0c1b49fSNick Terrell U32* const hashTable = ms->hashTable; 100e0c1b49fSNick Terrell U32 const hlog = cParams->hashLog; 101e0c1b49fSNick Terrell /* support stepSize of 0 */ 102*2aa14b1aSNick Terrell size_t const stepSize = hasStep ? (cParams->targetLength + !(cParams->targetLength) + 1) : 2; 103e0c1b49fSNick Terrell const BYTE* const base = ms->window.base; 104e0c1b49fSNick Terrell const BYTE* const istart = (const BYTE*)src; 105e0c1b49fSNick Terrell const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); 106e0c1b49fSNick Terrell const U32 prefixStartIndex = ZSTD_getLowestPrefixIndex(ms, endIndex, cParams->windowLog); 107e0c1b49fSNick Terrell const BYTE* const prefixStart = base + prefixStartIndex; 108e0c1b49fSNick Terrell const BYTE* const iend = istart + srcSize; 109e0c1b49fSNick Terrell const BYTE* const ilimit = iend - HASH_READ_SIZE; 110*2aa14b1aSNick Terrell 111*2aa14b1aSNick Terrell const BYTE* anchor = istart; 112*2aa14b1aSNick Terrell const BYTE* ip0 = istart; 113*2aa14b1aSNick Terrell const BYTE* ip1; 114*2aa14b1aSNick Terrell const BYTE* ip2; 115*2aa14b1aSNick Terrell const BYTE* ip3; 116*2aa14b1aSNick Terrell U32 current0; 117*2aa14b1aSNick Terrell 118*2aa14b1aSNick Terrell U32 rep_offset1 = rep[0]; 119*2aa14b1aSNick Terrell U32 rep_offset2 = rep[1]; 120e0c1b49fSNick Terrell U32 offsetSaved = 0; 121e0c1b49fSNick Terrell 122*2aa14b1aSNick Terrell size_t hash0; /* hash for ip0 */ 123*2aa14b1aSNick Terrell size_t hash1; /* hash for ip1 */ 124*2aa14b1aSNick Terrell U32 idx; /* match idx for ip0 */ 125*2aa14b1aSNick Terrell U32 mval; /* src value at match idx */ 126*2aa14b1aSNick Terrell 127*2aa14b1aSNick Terrell U32 offcode; 128*2aa14b1aSNick Terrell const BYTE* match0; 129*2aa14b1aSNick Terrell size_t mLength; 130*2aa14b1aSNick Terrell 131*2aa14b1aSNick Terrell /* ip0 and ip1 are always adjacent. The targetLength skipping and 132*2aa14b1aSNick Terrell * uncompressibility acceleration is applied to every other position, 133*2aa14b1aSNick Terrell * matching the behavior of #1562. step therefore represents the gap 134*2aa14b1aSNick Terrell * between pairs of positions, from ip0 to ip2 or ip1 to ip3. */ 135*2aa14b1aSNick Terrell size_t step; 136*2aa14b1aSNick Terrell const BYTE* nextStep; 137*2aa14b1aSNick Terrell const size_t kStepIncr = (1 << (kSearchStrength - 1)); 138*2aa14b1aSNick Terrell 139e0c1b49fSNick Terrell DEBUGLOG(5, "ZSTD_compressBlock_fast_generic"); 140e0c1b49fSNick Terrell ip0 += (ip0 == prefixStart); 141e0c1b49fSNick Terrell { U32 const curr = (U32)(ip0 - base); 142e0c1b49fSNick Terrell U32 const windowLow = ZSTD_getLowestPrefixIndex(ms, curr, cParams->windowLog); 143e0c1b49fSNick Terrell U32 const maxRep = curr - windowLow; 144*2aa14b1aSNick Terrell if (rep_offset2 > maxRep) offsetSaved = rep_offset2, rep_offset2 = 0; 145*2aa14b1aSNick Terrell if (rep_offset1 > maxRep) offsetSaved = rep_offset1, rep_offset1 = 0; 146e0c1b49fSNick Terrell } 147e0c1b49fSNick Terrell 148*2aa14b1aSNick Terrell /* start each op */ 149*2aa14b1aSNick Terrell _start: /* Requires: ip0 */ 150e0c1b49fSNick Terrell 151*2aa14b1aSNick Terrell step = stepSize; 152*2aa14b1aSNick Terrell nextStep = ip0 + kStepIncr; 153e0c1b49fSNick Terrell 154*2aa14b1aSNick Terrell /* calculate positions, ip0 - anchor == 0, so we skip step calc */ 155*2aa14b1aSNick Terrell ip1 = ip0 + 1; 156*2aa14b1aSNick Terrell ip2 = ip0 + step; 157*2aa14b1aSNick Terrell ip3 = ip2 + 1; 158e0c1b49fSNick Terrell 159*2aa14b1aSNick Terrell if (ip3 >= ilimit) { 160*2aa14b1aSNick Terrell goto _cleanup; 161*2aa14b1aSNick Terrell } 162e0c1b49fSNick Terrell 163*2aa14b1aSNick Terrell hash0 = ZSTD_hashPtr(ip0, hlog, mls); 164*2aa14b1aSNick Terrell hash1 = ZSTD_hashPtr(ip1, hlog, mls); 165*2aa14b1aSNick Terrell 166*2aa14b1aSNick Terrell idx = hashTable[hash0]; 167*2aa14b1aSNick Terrell 168*2aa14b1aSNick Terrell do { 169*2aa14b1aSNick Terrell /* load repcode match for ip[2]*/ 170*2aa14b1aSNick Terrell const U32 rval = MEM_read32(ip2 - rep_offset1); 171*2aa14b1aSNick Terrell 172*2aa14b1aSNick Terrell /* write back hash table entry */ 173*2aa14b1aSNick Terrell current0 = (U32)(ip0 - base); 174*2aa14b1aSNick Terrell hashTable[hash0] = current0; 175*2aa14b1aSNick Terrell 176*2aa14b1aSNick Terrell /* check repcode at ip[2] */ 177*2aa14b1aSNick Terrell if ((MEM_read32(ip2) == rval) & (rep_offset1 > 0)) { 178*2aa14b1aSNick Terrell ip0 = ip2; 179*2aa14b1aSNick Terrell match0 = ip0 - rep_offset1; 180*2aa14b1aSNick Terrell mLength = ip0[-1] == match0[-1]; 181*2aa14b1aSNick Terrell ip0 -= mLength; 182*2aa14b1aSNick Terrell match0 -= mLength; 183*2aa14b1aSNick Terrell offcode = STORE_REPCODE_1; 184e0c1b49fSNick Terrell mLength += 4; 185e0c1b49fSNick Terrell goto _match; 186e0c1b49fSNick Terrell } 187*2aa14b1aSNick Terrell 188*2aa14b1aSNick Terrell /* load match for ip[0] */ 189*2aa14b1aSNick Terrell if (idx >= prefixStartIndex) { 190*2aa14b1aSNick Terrell mval = MEM_read32(base + idx); 191*2aa14b1aSNick Terrell } else { 192*2aa14b1aSNick Terrell mval = MEM_read32(ip0) ^ 1; /* guaranteed to not match. */ 193*2aa14b1aSNick Terrell } 194*2aa14b1aSNick Terrell 195*2aa14b1aSNick Terrell /* check match at ip[0] */ 196*2aa14b1aSNick Terrell if (MEM_read32(ip0) == mval) { 197*2aa14b1aSNick Terrell /* found a match! */ 198e0c1b49fSNick Terrell goto _offset; 199e0c1b49fSNick Terrell } 200*2aa14b1aSNick Terrell 201*2aa14b1aSNick Terrell /* lookup ip[1] */ 202*2aa14b1aSNick Terrell idx = hashTable[hash1]; 203*2aa14b1aSNick Terrell 204*2aa14b1aSNick Terrell /* hash ip[2] */ 205*2aa14b1aSNick Terrell hash0 = hash1; 206*2aa14b1aSNick Terrell hash1 = ZSTD_hashPtr(ip2, hlog, mls); 207*2aa14b1aSNick Terrell 208*2aa14b1aSNick Terrell /* advance to next positions */ 209e0c1b49fSNick Terrell ip0 = ip1; 210*2aa14b1aSNick Terrell ip1 = ip2; 211*2aa14b1aSNick Terrell ip2 = ip3; 212*2aa14b1aSNick Terrell 213*2aa14b1aSNick Terrell /* write back hash table entry */ 214*2aa14b1aSNick Terrell current0 = (U32)(ip0 - base); 215*2aa14b1aSNick Terrell hashTable[hash0] = current0; 216*2aa14b1aSNick Terrell 217*2aa14b1aSNick Terrell /* load match for ip[0] */ 218*2aa14b1aSNick Terrell if (idx >= prefixStartIndex) { 219*2aa14b1aSNick Terrell mval = MEM_read32(base + idx); 220*2aa14b1aSNick Terrell } else { 221*2aa14b1aSNick Terrell mval = MEM_read32(ip0) ^ 1; /* guaranteed to not match. */ 222*2aa14b1aSNick Terrell } 223*2aa14b1aSNick Terrell 224*2aa14b1aSNick Terrell /* check match at ip[0] */ 225*2aa14b1aSNick Terrell if (MEM_read32(ip0) == mval) { 226*2aa14b1aSNick Terrell /* found a match! */ 227e0c1b49fSNick Terrell goto _offset; 228e0c1b49fSNick Terrell } 229*2aa14b1aSNick Terrell 230*2aa14b1aSNick Terrell /* lookup ip[1] */ 231*2aa14b1aSNick Terrell idx = hashTable[hash1]; 232*2aa14b1aSNick Terrell 233*2aa14b1aSNick Terrell /* hash ip[2] */ 234*2aa14b1aSNick Terrell hash0 = hash1; 235*2aa14b1aSNick Terrell hash1 = ZSTD_hashPtr(ip2, hlog, mls); 236*2aa14b1aSNick Terrell 237*2aa14b1aSNick Terrell /* advance to next positions */ 238*2aa14b1aSNick Terrell ip0 = ip1; 239*2aa14b1aSNick Terrell ip1 = ip2; 240*2aa14b1aSNick Terrell ip2 = ip0 + step; 241*2aa14b1aSNick Terrell ip3 = ip1 + step; 242*2aa14b1aSNick Terrell 243*2aa14b1aSNick Terrell /* calculate step */ 244*2aa14b1aSNick Terrell if (ip2 >= nextStep) { 245*2aa14b1aSNick Terrell step++; 246*2aa14b1aSNick Terrell PREFETCH_L1(ip1 + 64); 247*2aa14b1aSNick Terrell PREFETCH_L1(ip1 + 128); 248*2aa14b1aSNick Terrell nextStep += kStepIncr; 249e0c1b49fSNick Terrell } 250*2aa14b1aSNick Terrell } while (ip3 < ilimit); 251*2aa14b1aSNick Terrell 252*2aa14b1aSNick Terrell _cleanup: 253*2aa14b1aSNick Terrell /* Note that there are probably still a couple positions we could search. 254*2aa14b1aSNick Terrell * However, it seems to be a meaningful performance hit to try to search 255*2aa14b1aSNick Terrell * them. So let's not. */ 256*2aa14b1aSNick Terrell 257*2aa14b1aSNick Terrell /* save reps for next block */ 258*2aa14b1aSNick Terrell rep[0] = rep_offset1 ? rep_offset1 : offsetSaved; 259*2aa14b1aSNick Terrell rep[1] = rep_offset2 ? rep_offset2 : offsetSaved; 260*2aa14b1aSNick Terrell 261*2aa14b1aSNick Terrell /* Return the last literals size */ 262*2aa14b1aSNick Terrell return (size_t)(iend - anchor); 263*2aa14b1aSNick Terrell 264*2aa14b1aSNick Terrell _offset: /* Requires: ip0, idx */ 265*2aa14b1aSNick Terrell 266*2aa14b1aSNick Terrell /* Compute the offset code. */ 267*2aa14b1aSNick Terrell match0 = base + idx; 268*2aa14b1aSNick Terrell rep_offset2 = rep_offset1; 269*2aa14b1aSNick Terrell rep_offset1 = (U32)(ip0-match0); 270*2aa14b1aSNick Terrell offcode = STORE_OFFSET(rep_offset1); 271e0c1b49fSNick Terrell mLength = 4; 272*2aa14b1aSNick Terrell 273*2aa14b1aSNick Terrell /* Count the backwards match length. */ 274*2aa14b1aSNick Terrell while (((ip0>anchor) & (match0>prefixStart)) && (ip0[-1] == match0[-1])) { 275*2aa14b1aSNick Terrell ip0--; 276*2aa14b1aSNick Terrell match0--; 277*2aa14b1aSNick Terrell mLength++; 278*2aa14b1aSNick Terrell } 279e0c1b49fSNick Terrell 280e0c1b49fSNick Terrell _match: /* Requires: ip0, match0, offcode */ 281*2aa14b1aSNick Terrell 282*2aa14b1aSNick Terrell /* Count the forward length. */ 283e0c1b49fSNick Terrell mLength += ZSTD_count(ip0 + mLength, match0 + mLength, iend); 284*2aa14b1aSNick Terrell 285*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, (size_t)(ip0 - anchor), anchor, iend, offcode, mLength); 286*2aa14b1aSNick Terrell 287e0c1b49fSNick Terrell ip0 += mLength; 288e0c1b49fSNick Terrell anchor = ip0; 289e0c1b49fSNick Terrell 290*2aa14b1aSNick Terrell /* write next hash table entry */ 291*2aa14b1aSNick Terrell if (ip1 < ip0) { 292*2aa14b1aSNick Terrell hashTable[hash1] = (U32)(ip1 - base); 293*2aa14b1aSNick Terrell } 294*2aa14b1aSNick Terrell 295*2aa14b1aSNick Terrell /* Fill table and check for immediate repcode. */ 296e0c1b49fSNick Terrell if (ip0 <= ilimit) { 297e0c1b49fSNick Terrell /* Fill Table */ 298e0c1b49fSNick Terrell assert(base+current0+2 > istart); /* check base overflow */ 299e0c1b49fSNick Terrell hashTable[ZSTD_hashPtr(base+current0+2, hlog, mls)] = current0+2; /* here because current+2 could be > iend-8 */ 300e0c1b49fSNick Terrell hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base); 301e0c1b49fSNick Terrell 302*2aa14b1aSNick Terrell if (rep_offset2 > 0) { /* rep_offset2==0 means rep_offset2 is invalidated */ 303*2aa14b1aSNick Terrell while ( (ip0 <= ilimit) && (MEM_read32(ip0) == MEM_read32(ip0 - rep_offset2)) ) { 304e0c1b49fSNick Terrell /* store sequence */ 305*2aa14b1aSNick Terrell size_t const rLength = ZSTD_count(ip0+4, ip0+4-rep_offset2, iend) + 4; 306*2aa14b1aSNick Terrell { U32 const tmpOff = rep_offset2; rep_offset2 = rep_offset1; rep_offset1 = tmpOff; } /* swap rep_offset2 <=> rep_offset1 */ 307e0c1b49fSNick Terrell hashTable[ZSTD_hashPtr(ip0, hlog, mls)] = (U32)(ip0-base); 308e0c1b49fSNick Terrell ip0 += rLength; 309*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, 0 /*litLen*/, anchor, iend, STORE_REPCODE_1, rLength); 310e0c1b49fSNick Terrell anchor = ip0; 311e0c1b49fSNick Terrell continue; /* faster when present (confirmed on gcc-8) ... (?) */ 312e0c1b49fSNick Terrell } } } 313*2aa14b1aSNick Terrell 314*2aa14b1aSNick Terrell goto _start; 315e0c1b49fSNick Terrell } 316e0c1b49fSNick Terrell 317*2aa14b1aSNick Terrell #define ZSTD_GEN_FAST_FN(dictMode, mls, step) \ 318*2aa14b1aSNick Terrell static size_t ZSTD_compressBlock_fast_##dictMode##_##mls##_##step( \ 319*2aa14b1aSNick Terrell ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], \ 320*2aa14b1aSNick Terrell void const* src, size_t srcSize) \ 321*2aa14b1aSNick Terrell { \ 322*2aa14b1aSNick Terrell return ZSTD_compressBlock_fast_##dictMode##_generic(ms, seqStore, rep, src, srcSize, mls, step); \ 323e0c1b49fSNick Terrell } 324e0c1b49fSNick Terrell 325*2aa14b1aSNick Terrell ZSTD_GEN_FAST_FN(noDict, 4, 1) 326*2aa14b1aSNick Terrell ZSTD_GEN_FAST_FN(noDict, 5, 1) 327*2aa14b1aSNick Terrell ZSTD_GEN_FAST_FN(noDict, 6, 1) 328*2aa14b1aSNick Terrell ZSTD_GEN_FAST_FN(noDict, 7, 1) 329*2aa14b1aSNick Terrell 330*2aa14b1aSNick Terrell ZSTD_GEN_FAST_FN(noDict, 4, 0) 331*2aa14b1aSNick Terrell ZSTD_GEN_FAST_FN(noDict, 5, 0) 332*2aa14b1aSNick Terrell ZSTD_GEN_FAST_FN(noDict, 6, 0) 333*2aa14b1aSNick Terrell ZSTD_GEN_FAST_FN(noDict, 7, 0) 334e0c1b49fSNick Terrell 335e0c1b49fSNick Terrell size_t ZSTD_compressBlock_fast( 336e0c1b49fSNick Terrell ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 337e0c1b49fSNick Terrell void const* src, size_t srcSize) 338e0c1b49fSNick Terrell { 339e0c1b49fSNick Terrell U32 const mls = ms->cParams.minMatch; 340e0c1b49fSNick Terrell assert(ms->dictMatchState == NULL); 341*2aa14b1aSNick Terrell if (ms->cParams.targetLength > 1) { 342e0c1b49fSNick Terrell switch(mls) 343e0c1b49fSNick Terrell { 344e0c1b49fSNick Terrell default: /* includes case 3 */ 345e0c1b49fSNick Terrell case 4 : 346*2aa14b1aSNick Terrell return ZSTD_compressBlock_fast_noDict_4_1(ms, seqStore, rep, src, srcSize); 347e0c1b49fSNick Terrell case 5 : 348*2aa14b1aSNick Terrell return ZSTD_compressBlock_fast_noDict_5_1(ms, seqStore, rep, src, srcSize); 349e0c1b49fSNick Terrell case 6 : 350*2aa14b1aSNick Terrell return ZSTD_compressBlock_fast_noDict_6_1(ms, seqStore, rep, src, srcSize); 351e0c1b49fSNick Terrell case 7 : 352*2aa14b1aSNick Terrell return ZSTD_compressBlock_fast_noDict_7_1(ms, seqStore, rep, src, srcSize); 353*2aa14b1aSNick Terrell } 354*2aa14b1aSNick Terrell } else { 355*2aa14b1aSNick Terrell switch(mls) 356*2aa14b1aSNick Terrell { 357*2aa14b1aSNick Terrell default: /* includes case 3 */ 358*2aa14b1aSNick Terrell case 4 : 359*2aa14b1aSNick Terrell return ZSTD_compressBlock_fast_noDict_4_0(ms, seqStore, rep, src, srcSize); 360*2aa14b1aSNick Terrell case 5 : 361*2aa14b1aSNick Terrell return ZSTD_compressBlock_fast_noDict_5_0(ms, seqStore, rep, src, srcSize); 362*2aa14b1aSNick Terrell case 6 : 363*2aa14b1aSNick Terrell return ZSTD_compressBlock_fast_noDict_6_0(ms, seqStore, rep, src, srcSize); 364*2aa14b1aSNick Terrell case 7 : 365*2aa14b1aSNick Terrell return ZSTD_compressBlock_fast_noDict_7_0(ms, seqStore, rep, src, srcSize); 366*2aa14b1aSNick Terrell } 367*2aa14b1aSNick Terrell 368e0c1b49fSNick Terrell } 369e0c1b49fSNick Terrell } 370e0c1b49fSNick Terrell 371e0c1b49fSNick Terrell FORCE_INLINE_TEMPLATE 372e0c1b49fSNick Terrell size_t ZSTD_compressBlock_fast_dictMatchState_generic( 373e0c1b49fSNick Terrell ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 374*2aa14b1aSNick Terrell void const* src, size_t srcSize, U32 const mls, U32 const hasStep) 375e0c1b49fSNick Terrell { 376e0c1b49fSNick Terrell const ZSTD_compressionParameters* const cParams = &ms->cParams; 377e0c1b49fSNick Terrell U32* const hashTable = ms->hashTable; 378e0c1b49fSNick Terrell U32 const hlog = cParams->hashLog; 379e0c1b49fSNick Terrell /* support stepSize of 0 */ 380e0c1b49fSNick Terrell U32 const stepSize = cParams->targetLength + !(cParams->targetLength); 381e0c1b49fSNick Terrell const BYTE* const base = ms->window.base; 382e0c1b49fSNick Terrell const BYTE* const istart = (const BYTE*)src; 383e0c1b49fSNick Terrell const BYTE* ip = istart; 384e0c1b49fSNick Terrell const BYTE* anchor = istart; 385e0c1b49fSNick Terrell const U32 prefixStartIndex = ms->window.dictLimit; 386e0c1b49fSNick Terrell const BYTE* const prefixStart = base + prefixStartIndex; 387e0c1b49fSNick Terrell const BYTE* const iend = istart + srcSize; 388e0c1b49fSNick Terrell const BYTE* const ilimit = iend - HASH_READ_SIZE; 389e0c1b49fSNick Terrell U32 offset_1=rep[0], offset_2=rep[1]; 390e0c1b49fSNick Terrell U32 offsetSaved = 0; 391e0c1b49fSNick Terrell 392e0c1b49fSNick Terrell const ZSTD_matchState_t* const dms = ms->dictMatchState; 393e0c1b49fSNick Terrell const ZSTD_compressionParameters* const dictCParams = &dms->cParams ; 394e0c1b49fSNick Terrell const U32* const dictHashTable = dms->hashTable; 395e0c1b49fSNick Terrell const U32 dictStartIndex = dms->window.dictLimit; 396e0c1b49fSNick Terrell const BYTE* const dictBase = dms->window.base; 397e0c1b49fSNick Terrell const BYTE* const dictStart = dictBase + dictStartIndex; 398e0c1b49fSNick Terrell const BYTE* const dictEnd = dms->window.nextSrc; 399e0c1b49fSNick Terrell const U32 dictIndexDelta = prefixStartIndex - (U32)(dictEnd - dictBase); 400e0c1b49fSNick Terrell const U32 dictAndPrefixLength = (U32)(ip - prefixStart + dictEnd - dictStart); 401e0c1b49fSNick Terrell const U32 dictHLog = dictCParams->hashLog; 402e0c1b49fSNick Terrell 403e0c1b49fSNick Terrell /* if a dictionary is still attached, it necessarily means that 404e0c1b49fSNick Terrell * it is within window size. So we just check it. */ 405e0c1b49fSNick Terrell const U32 maxDistance = 1U << cParams->windowLog; 406e0c1b49fSNick Terrell const U32 endIndex = (U32)((size_t)(ip - base) + srcSize); 407e0c1b49fSNick Terrell assert(endIndex - prefixStartIndex <= maxDistance); 408e0c1b49fSNick Terrell (void)maxDistance; (void)endIndex; /* these variables are not used when assert() is disabled */ 409e0c1b49fSNick Terrell 410*2aa14b1aSNick Terrell (void)hasStep; /* not currently specialized on whether it's accelerated */ 411*2aa14b1aSNick Terrell 412e0c1b49fSNick Terrell /* ensure there will be no underflow 413e0c1b49fSNick Terrell * when translating a dict index into a local index */ 414e0c1b49fSNick Terrell assert(prefixStartIndex >= (U32)(dictEnd - dictBase)); 415e0c1b49fSNick Terrell 416e0c1b49fSNick Terrell /* init */ 417e0c1b49fSNick Terrell DEBUGLOG(5, "ZSTD_compressBlock_fast_dictMatchState_generic"); 418e0c1b49fSNick Terrell ip += (dictAndPrefixLength == 0); 419e0c1b49fSNick Terrell /* dictMatchState repCode checks don't currently handle repCode == 0 420e0c1b49fSNick Terrell * disabling. */ 421e0c1b49fSNick Terrell assert(offset_1 <= dictAndPrefixLength); 422e0c1b49fSNick Terrell assert(offset_2 <= dictAndPrefixLength); 423e0c1b49fSNick Terrell 424e0c1b49fSNick Terrell /* Main Search Loop */ 425e0c1b49fSNick Terrell while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */ 426e0c1b49fSNick Terrell size_t mLength; 427e0c1b49fSNick Terrell size_t const h = ZSTD_hashPtr(ip, hlog, mls); 428e0c1b49fSNick Terrell U32 const curr = (U32)(ip-base); 429e0c1b49fSNick Terrell U32 const matchIndex = hashTable[h]; 430e0c1b49fSNick Terrell const BYTE* match = base + matchIndex; 431e0c1b49fSNick Terrell const U32 repIndex = curr + 1 - offset_1; 432e0c1b49fSNick Terrell const BYTE* repMatch = (repIndex < prefixStartIndex) ? 433e0c1b49fSNick Terrell dictBase + (repIndex - dictIndexDelta) : 434e0c1b49fSNick Terrell base + repIndex; 435e0c1b49fSNick Terrell hashTable[h] = curr; /* update hash table */ 436e0c1b49fSNick Terrell 437e0c1b49fSNick Terrell if ( ((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */ 438e0c1b49fSNick Terrell && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { 439e0c1b49fSNick Terrell const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; 440e0c1b49fSNick Terrell mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4; 441e0c1b49fSNick Terrell ip++; 442*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_REPCODE_1, mLength); 443e0c1b49fSNick Terrell } else if ( (matchIndex <= prefixStartIndex) ) { 444e0c1b49fSNick Terrell size_t const dictHash = ZSTD_hashPtr(ip, dictHLog, mls); 445e0c1b49fSNick Terrell U32 const dictMatchIndex = dictHashTable[dictHash]; 446e0c1b49fSNick Terrell const BYTE* dictMatch = dictBase + dictMatchIndex; 447e0c1b49fSNick Terrell if (dictMatchIndex <= dictStartIndex || 448e0c1b49fSNick Terrell MEM_read32(dictMatch) != MEM_read32(ip)) { 449e0c1b49fSNick Terrell assert(stepSize >= 1); 450e0c1b49fSNick Terrell ip += ((ip-anchor) >> kSearchStrength) + stepSize; 451e0c1b49fSNick Terrell continue; 452e0c1b49fSNick Terrell } else { 453e0c1b49fSNick Terrell /* found a dict match */ 454e0c1b49fSNick Terrell U32 const offset = (U32)(curr-dictMatchIndex-dictIndexDelta); 455e0c1b49fSNick Terrell mLength = ZSTD_count_2segments(ip+4, dictMatch+4, iend, dictEnd, prefixStart) + 4; 456e0c1b49fSNick Terrell while (((ip>anchor) & (dictMatch>dictStart)) 457e0c1b49fSNick Terrell && (ip[-1] == dictMatch[-1])) { 458e0c1b49fSNick Terrell ip--; dictMatch--; mLength++; 459e0c1b49fSNick Terrell } /* catch up */ 460e0c1b49fSNick Terrell offset_2 = offset_1; 461e0c1b49fSNick Terrell offset_1 = offset; 462*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_OFFSET(offset), mLength); 463e0c1b49fSNick Terrell } 464e0c1b49fSNick Terrell } else if (MEM_read32(match) != MEM_read32(ip)) { 465e0c1b49fSNick Terrell /* it's not a match, and we're not going to check the dictionary */ 466e0c1b49fSNick Terrell assert(stepSize >= 1); 467e0c1b49fSNick Terrell ip += ((ip-anchor) >> kSearchStrength) + stepSize; 468e0c1b49fSNick Terrell continue; 469e0c1b49fSNick Terrell } else { 470e0c1b49fSNick Terrell /* found a regular match */ 471e0c1b49fSNick Terrell U32 const offset = (U32)(ip-match); 472e0c1b49fSNick Terrell mLength = ZSTD_count(ip+4, match+4, iend) + 4; 473e0c1b49fSNick Terrell while (((ip>anchor) & (match>prefixStart)) 474e0c1b49fSNick Terrell && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ 475e0c1b49fSNick Terrell offset_2 = offset_1; 476e0c1b49fSNick Terrell offset_1 = offset; 477*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_OFFSET(offset), mLength); 478e0c1b49fSNick Terrell } 479e0c1b49fSNick Terrell 480e0c1b49fSNick Terrell /* match found */ 481e0c1b49fSNick Terrell ip += mLength; 482e0c1b49fSNick Terrell anchor = ip; 483e0c1b49fSNick Terrell 484e0c1b49fSNick Terrell if (ip <= ilimit) { 485e0c1b49fSNick Terrell /* Fill Table */ 486e0c1b49fSNick Terrell assert(base+curr+2 > istart); /* check base overflow */ 487e0c1b49fSNick Terrell hashTable[ZSTD_hashPtr(base+curr+2, hlog, mls)] = curr+2; /* here because curr+2 could be > iend-8 */ 488e0c1b49fSNick Terrell hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base); 489e0c1b49fSNick Terrell 490e0c1b49fSNick Terrell /* check immediate repcode */ 491e0c1b49fSNick Terrell while (ip <= ilimit) { 492e0c1b49fSNick Terrell U32 const current2 = (U32)(ip-base); 493e0c1b49fSNick Terrell U32 const repIndex2 = current2 - offset_2; 494e0c1b49fSNick Terrell const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? 495e0c1b49fSNick Terrell dictBase - dictIndexDelta + repIndex2 : 496e0c1b49fSNick Terrell base + repIndex2; 497e0c1b49fSNick Terrell if ( ((U32)((prefixStartIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */) 498e0c1b49fSNick Terrell && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { 499e0c1b49fSNick Terrell const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; 500e0c1b49fSNick Terrell size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; 501e0c1b49fSNick Terrell U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ 502*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, 0, anchor, iend, STORE_REPCODE_1, repLength2); 503e0c1b49fSNick Terrell hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2; 504e0c1b49fSNick Terrell ip += repLength2; 505e0c1b49fSNick Terrell anchor = ip; 506e0c1b49fSNick Terrell continue; 507e0c1b49fSNick Terrell } 508e0c1b49fSNick Terrell break; 509e0c1b49fSNick Terrell } 510e0c1b49fSNick Terrell } 511e0c1b49fSNick Terrell } 512e0c1b49fSNick Terrell 513e0c1b49fSNick Terrell /* save reps for next block */ 514e0c1b49fSNick Terrell rep[0] = offset_1 ? offset_1 : offsetSaved; 515e0c1b49fSNick Terrell rep[1] = offset_2 ? offset_2 : offsetSaved; 516e0c1b49fSNick Terrell 517e0c1b49fSNick Terrell /* Return the last literals size */ 518e0c1b49fSNick Terrell return (size_t)(iend - anchor); 519e0c1b49fSNick Terrell } 520e0c1b49fSNick Terrell 521*2aa14b1aSNick Terrell 522*2aa14b1aSNick Terrell ZSTD_GEN_FAST_FN(dictMatchState, 4, 0) 523*2aa14b1aSNick Terrell ZSTD_GEN_FAST_FN(dictMatchState, 5, 0) 524*2aa14b1aSNick Terrell ZSTD_GEN_FAST_FN(dictMatchState, 6, 0) 525*2aa14b1aSNick Terrell ZSTD_GEN_FAST_FN(dictMatchState, 7, 0) 526*2aa14b1aSNick Terrell 527e0c1b49fSNick Terrell size_t ZSTD_compressBlock_fast_dictMatchState( 528e0c1b49fSNick Terrell ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 529e0c1b49fSNick Terrell void const* src, size_t srcSize) 530e0c1b49fSNick Terrell { 531e0c1b49fSNick Terrell U32 const mls = ms->cParams.minMatch; 532e0c1b49fSNick Terrell assert(ms->dictMatchState != NULL); 533e0c1b49fSNick Terrell switch(mls) 534e0c1b49fSNick Terrell { 535e0c1b49fSNick Terrell default: /* includes case 3 */ 536e0c1b49fSNick Terrell case 4 : 537*2aa14b1aSNick Terrell return ZSTD_compressBlock_fast_dictMatchState_4_0(ms, seqStore, rep, src, srcSize); 538e0c1b49fSNick Terrell case 5 : 539*2aa14b1aSNick Terrell return ZSTD_compressBlock_fast_dictMatchState_5_0(ms, seqStore, rep, src, srcSize); 540e0c1b49fSNick Terrell case 6 : 541*2aa14b1aSNick Terrell return ZSTD_compressBlock_fast_dictMatchState_6_0(ms, seqStore, rep, src, srcSize); 542e0c1b49fSNick Terrell case 7 : 543*2aa14b1aSNick Terrell return ZSTD_compressBlock_fast_dictMatchState_7_0(ms, seqStore, rep, src, srcSize); 544e0c1b49fSNick Terrell } 545e0c1b49fSNick Terrell } 546e0c1b49fSNick Terrell 547e0c1b49fSNick Terrell 548e0c1b49fSNick Terrell static size_t ZSTD_compressBlock_fast_extDict_generic( 549e0c1b49fSNick Terrell ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 550*2aa14b1aSNick Terrell void const* src, size_t srcSize, U32 const mls, U32 const hasStep) 551e0c1b49fSNick Terrell { 552e0c1b49fSNick Terrell const ZSTD_compressionParameters* const cParams = &ms->cParams; 553e0c1b49fSNick Terrell U32* const hashTable = ms->hashTable; 554e0c1b49fSNick Terrell U32 const hlog = cParams->hashLog; 555e0c1b49fSNick Terrell /* support stepSize of 0 */ 556e0c1b49fSNick Terrell U32 const stepSize = cParams->targetLength + !(cParams->targetLength); 557e0c1b49fSNick Terrell const BYTE* const base = ms->window.base; 558e0c1b49fSNick Terrell const BYTE* const dictBase = ms->window.dictBase; 559e0c1b49fSNick Terrell const BYTE* const istart = (const BYTE*)src; 560e0c1b49fSNick Terrell const BYTE* ip = istart; 561e0c1b49fSNick Terrell const BYTE* anchor = istart; 562e0c1b49fSNick Terrell const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); 563e0c1b49fSNick Terrell const U32 lowLimit = ZSTD_getLowestMatchIndex(ms, endIndex, cParams->windowLog); 564e0c1b49fSNick Terrell const U32 dictStartIndex = lowLimit; 565e0c1b49fSNick Terrell const BYTE* const dictStart = dictBase + dictStartIndex; 566e0c1b49fSNick Terrell const U32 dictLimit = ms->window.dictLimit; 567e0c1b49fSNick Terrell const U32 prefixStartIndex = dictLimit < lowLimit ? lowLimit : dictLimit; 568e0c1b49fSNick Terrell const BYTE* const prefixStart = base + prefixStartIndex; 569e0c1b49fSNick Terrell const BYTE* const dictEnd = dictBase + prefixStartIndex; 570e0c1b49fSNick Terrell const BYTE* const iend = istart + srcSize; 571e0c1b49fSNick Terrell const BYTE* const ilimit = iend - 8; 572e0c1b49fSNick Terrell U32 offset_1=rep[0], offset_2=rep[1]; 573e0c1b49fSNick Terrell 574*2aa14b1aSNick Terrell (void)hasStep; /* not currently specialized on whether it's accelerated */ 575*2aa14b1aSNick Terrell 576e0c1b49fSNick Terrell DEBUGLOG(5, "ZSTD_compressBlock_fast_extDict_generic (offset_1=%u)", offset_1); 577e0c1b49fSNick Terrell 578e0c1b49fSNick Terrell /* switch to "regular" variant if extDict is invalidated due to maxDistance */ 579e0c1b49fSNick Terrell if (prefixStartIndex == dictStartIndex) 580*2aa14b1aSNick Terrell return ZSTD_compressBlock_fast(ms, seqStore, rep, src, srcSize); 581e0c1b49fSNick Terrell 582e0c1b49fSNick Terrell /* Search Loop */ 583e0c1b49fSNick Terrell while (ip < ilimit) { /* < instead of <=, because (ip+1) */ 584e0c1b49fSNick Terrell const size_t h = ZSTD_hashPtr(ip, hlog, mls); 585e0c1b49fSNick Terrell const U32 matchIndex = hashTable[h]; 586e0c1b49fSNick Terrell const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base; 587e0c1b49fSNick Terrell const BYTE* match = matchBase + matchIndex; 588e0c1b49fSNick Terrell const U32 curr = (U32)(ip-base); 589e0c1b49fSNick Terrell const U32 repIndex = curr + 1 - offset_1; 590e0c1b49fSNick Terrell const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base; 591e0c1b49fSNick Terrell const BYTE* const repMatch = repBase + repIndex; 592e0c1b49fSNick Terrell hashTable[h] = curr; /* update hash table */ 593e0c1b49fSNick Terrell DEBUGLOG(7, "offset_1 = %u , curr = %u", offset_1, curr); 594e0c1b49fSNick Terrell 595*2aa14b1aSNick Terrell if ( ( ((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */ 596*2aa14b1aSNick Terrell & (offset_1 <= curr+1 - dictStartIndex) ) /* note: we are searching at curr+1 */ 597e0c1b49fSNick Terrell && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { 598e0c1b49fSNick Terrell const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; 599e0c1b49fSNick Terrell size_t const rLength = ZSTD_count_2segments(ip+1 +4, repMatch +4, iend, repMatchEnd, prefixStart) + 4; 600e0c1b49fSNick Terrell ip++; 601*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_REPCODE_1, rLength); 602e0c1b49fSNick Terrell ip += rLength; 603e0c1b49fSNick Terrell anchor = ip; 604e0c1b49fSNick Terrell } else { 605e0c1b49fSNick Terrell if ( (matchIndex < dictStartIndex) || 606e0c1b49fSNick Terrell (MEM_read32(match) != MEM_read32(ip)) ) { 607e0c1b49fSNick Terrell assert(stepSize >= 1); 608e0c1b49fSNick Terrell ip += ((ip-anchor) >> kSearchStrength) + stepSize; 609e0c1b49fSNick Terrell continue; 610e0c1b49fSNick Terrell } 611e0c1b49fSNick Terrell { const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend; 612e0c1b49fSNick Terrell const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart; 613e0c1b49fSNick Terrell U32 const offset = curr - matchIndex; 614e0c1b49fSNick Terrell size_t mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4; 615e0c1b49fSNick Terrell while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ 616e0c1b49fSNick Terrell offset_2 = offset_1; offset_1 = offset; /* update offset history */ 617*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, iend, STORE_OFFSET(offset), mLength); 618e0c1b49fSNick Terrell ip += mLength; 619e0c1b49fSNick Terrell anchor = ip; 620e0c1b49fSNick Terrell } } 621e0c1b49fSNick Terrell 622e0c1b49fSNick Terrell if (ip <= ilimit) { 623e0c1b49fSNick Terrell /* Fill Table */ 624e0c1b49fSNick Terrell hashTable[ZSTD_hashPtr(base+curr+2, hlog, mls)] = curr+2; 625e0c1b49fSNick Terrell hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base); 626e0c1b49fSNick Terrell /* check immediate repcode */ 627e0c1b49fSNick Terrell while (ip <= ilimit) { 628e0c1b49fSNick Terrell U32 const current2 = (U32)(ip-base); 629e0c1b49fSNick Terrell U32 const repIndex2 = current2 - offset_2; 630e0c1b49fSNick Terrell const BYTE* const repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2; 631*2aa14b1aSNick Terrell if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (offset_2 <= curr - dictStartIndex)) /* intentional overflow */ 632e0c1b49fSNick Terrell && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { 633e0c1b49fSNick Terrell const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; 634e0c1b49fSNick Terrell size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; 635e0c1b49fSNick Terrell { U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; } /* swap offset_2 <=> offset_1 */ 636*2aa14b1aSNick Terrell ZSTD_storeSeq(seqStore, 0 /*litlen*/, anchor, iend, STORE_REPCODE_1, repLength2); 637e0c1b49fSNick Terrell hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2; 638e0c1b49fSNick Terrell ip += repLength2; 639e0c1b49fSNick Terrell anchor = ip; 640e0c1b49fSNick Terrell continue; 641e0c1b49fSNick Terrell } 642e0c1b49fSNick Terrell break; 643e0c1b49fSNick Terrell } } } 644e0c1b49fSNick Terrell 645e0c1b49fSNick Terrell /* save reps for next block */ 646e0c1b49fSNick Terrell rep[0] = offset_1; 647e0c1b49fSNick Terrell rep[1] = offset_2; 648e0c1b49fSNick Terrell 649e0c1b49fSNick Terrell /* Return the last literals size */ 650e0c1b49fSNick Terrell return (size_t)(iend - anchor); 651e0c1b49fSNick Terrell } 652e0c1b49fSNick Terrell 653*2aa14b1aSNick Terrell ZSTD_GEN_FAST_FN(extDict, 4, 0) 654*2aa14b1aSNick Terrell ZSTD_GEN_FAST_FN(extDict, 5, 0) 655*2aa14b1aSNick Terrell ZSTD_GEN_FAST_FN(extDict, 6, 0) 656*2aa14b1aSNick Terrell ZSTD_GEN_FAST_FN(extDict, 7, 0) 657e0c1b49fSNick Terrell 658e0c1b49fSNick Terrell size_t ZSTD_compressBlock_fast_extDict( 659e0c1b49fSNick Terrell ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 660e0c1b49fSNick Terrell void const* src, size_t srcSize) 661e0c1b49fSNick Terrell { 662e0c1b49fSNick Terrell U32 const mls = ms->cParams.minMatch; 663e0c1b49fSNick Terrell switch(mls) 664e0c1b49fSNick Terrell { 665e0c1b49fSNick Terrell default: /* includes case 3 */ 666e0c1b49fSNick Terrell case 4 : 667*2aa14b1aSNick Terrell return ZSTD_compressBlock_fast_extDict_4_0(ms, seqStore, rep, src, srcSize); 668e0c1b49fSNick Terrell case 5 : 669*2aa14b1aSNick Terrell return ZSTD_compressBlock_fast_extDict_5_0(ms, seqStore, rep, src, srcSize); 670e0c1b49fSNick Terrell case 6 : 671*2aa14b1aSNick Terrell return ZSTD_compressBlock_fast_extDict_6_0(ms, seqStore, rep, src, srcSize); 672e0c1b49fSNick Terrell case 7 : 673*2aa14b1aSNick Terrell return ZSTD_compressBlock_fast_extDict_7_0(ms, seqStore, rep, src, srcSize); 674e0c1b49fSNick Terrell } 675e0c1b49fSNick Terrell } 676