zstd-ruby 1.3.4.0 → 1.3.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/ext/zstdruby/libzstd/Makefile +56 -10
  4. data/ext/zstdruby/libzstd/README.md +4 -0
  5. data/ext/zstdruby/libzstd/common/bitstream.h +6 -19
  6. data/ext/zstdruby/libzstd/common/compiler.h +3 -3
  7. data/ext/zstdruby/libzstd/common/cpu.h +1 -2
  8. data/ext/zstdruby/libzstd/common/debug.c +44 -0
  9. data/ext/zstdruby/libzstd/common/debug.h +123 -0
  10. data/ext/zstdruby/libzstd/common/entropy_common.c +16 -1
  11. data/ext/zstdruby/libzstd/common/fse.h +45 -41
  12. data/ext/zstdruby/libzstd/common/fse_decompress.c +1 -1
  13. data/ext/zstdruby/libzstd/common/huf.h +34 -27
  14. data/ext/zstdruby/libzstd/common/pool.c +89 -32
  15. data/ext/zstdruby/libzstd/common/pool.h +29 -19
  16. data/ext/zstdruby/libzstd/common/zstd_common.c +0 -5
  17. data/ext/zstdruby/libzstd/common/zstd_internal.h +3 -37
  18. data/ext/zstdruby/libzstd/compress/fse_compress.c +28 -163
  19. data/ext/zstdruby/libzstd/compress/hist.c +195 -0
  20. data/ext/zstdruby/libzstd/compress/hist.h +92 -0
  21. data/ext/zstdruby/libzstd/compress/huf_compress.c +14 -6
  22. data/ext/zstdruby/libzstd/compress/zstd_compress.c +798 -350
  23. data/ext/zstdruby/libzstd/compress/zstd_compress_internal.h +120 -34
  24. data/ext/zstdruby/libzstd/compress/zstd_double_fast.c +247 -87
  25. data/ext/zstdruby/libzstd/compress/zstd_double_fast.h +4 -1
  26. data/ext/zstdruby/libzstd/compress/zstd_fast.c +177 -56
  27. data/ext/zstdruby/libzstd/compress/zstd_fast.h +4 -1
  28. data/ext/zstdruby/libzstd/compress/zstd_lazy.c +331 -65
  29. data/ext/zstdruby/libzstd/compress/zstd_lazy.h +13 -0
  30. data/ext/zstdruby/libzstd/compress/zstd_ldm.c +15 -20
  31. data/ext/zstdruby/libzstd/compress/zstd_ldm.h +1 -2
  32. data/ext/zstdruby/libzstd/compress/zstd_opt.c +503 -300
  33. data/ext/zstdruby/libzstd/compress/zstd_opt.h +7 -0
  34. data/ext/zstdruby/libzstd/compress/zstdmt_compress.c +122 -47
  35. data/ext/zstdruby/libzstd/compress/zstdmt_compress.h +5 -5
  36. data/ext/zstdruby/libzstd/decompress/huf_decompress.c +325 -325
  37. data/ext/zstdruby/libzstd/decompress/zstd_decompress.c +80 -43
  38. data/ext/zstdruby/libzstd/dictBuilder/cover.c +9 -2
  39. data/ext/zstdruby/libzstd/dictBuilder/zdict.c +5 -5
  40. data/ext/zstdruby/libzstd/legacy/zstd_v04.c +12 -61
  41. data/ext/zstdruby/libzstd/zstd.h +137 -69
  42. data/lib/zstd-ruby/version.rb +1 -1
  43. metadata +7 -3
@@ -27,6 +27,7 @@
27
27
  extern "C" {
28
28
  #endif
29
29
 
30
+
30
31
  /*-*************************************
31
32
  * Constants
32
33
  ***************************************/
@@ -37,7 +38,8 @@ extern "C" {
37
38
  It's not a big deal though : candidate will just be sorted again.
38
39
  Additionnally, candidate position 1 will be lost.
39
40
  But candidate 1 cannot hide a large tree of candidates, so it's a minimal loss.
40
- The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be misdhandled after table re-use with a different strategy */
41
+ The benefit is that ZSTD_DUBT_UNSORTED_MARK cannot be misdhandled after table re-use with a different strategy
42
+ Constant required by ZSTD_compressBlock_btlazy2() and ZSTD_reduceTable_internal() */
41
43
 
42
44
 
43
45
  /*-*************************************
@@ -46,6 +48,12 @@ extern "C" {
46
48
  typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
47
49
  typedef enum { zcss_init=0, zcss_load, zcss_flush } ZSTD_cStreamStage;
48
50
 
51
+ typedef enum {
52
+ ZSTD_dictDefaultAttach = 0,
53
+ ZSTD_dictForceAttach = 1,
54
+ ZSTD_dictForceCopy = -1,
55
+ } ZSTD_dictAttachPref_e;
56
+
49
57
  typedef struct ZSTD_prefixDict_s {
50
58
  const void* dict;
51
59
  size_t dictSize;
@@ -53,14 +61,22 @@ typedef struct ZSTD_prefixDict_s {
53
61
  } ZSTD_prefixDict;
54
62
 
55
63
  typedef struct {
56
- U32 hufCTable[HUF_CTABLE_SIZE_U32(255)];
64
+ U32 CTable[HUF_CTABLE_SIZE_U32(255)];
65
+ HUF_repeat repeatMode;
66
+ } ZSTD_hufCTables_t;
67
+
68
+ typedef struct {
57
69
  FSE_CTable offcodeCTable[FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
58
70
  FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
59
71
  FSE_CTable litlengthCTable[FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
60
- HUF_repeat hufCTable_repeatMode;
61
72
  FSE_repeat offcode_repeatMode;
62
73
  FSE_repeat matchlength_repeatMode;
63
74
  FSE_repeat litlength_repeatMode;
75
+ } ZSTD_fseCTables_t;
76
+
77
+ typedef struct {
78
+ ZSTD_hufCTables_t huf;
79
+ ZSTD_fseCTables_t fse;
64
80
  } ZSTD_entropyCTables_t;
65
81
 
66
82
  typedef struct {
@@ -76,26 +92,27 @@ typedef struct {
76
92
  U32 rep[ZSTD_REP_NUM];
77
93
  } ZSTD_optimal_t;
78
94
 
95
+ typedef enum { zop_dynamic=0, zop_predef } ZSTD_OptPrice_e;
96
+
79
97
  typedef struct {
80
98
  /* All tables are allocated inside cctx->workspace by ZSTD_resetCCtx_internal() */
81
- U32* litFreq; /* table of literals statistics, of size 256 */
82
- U32* litLengthFreq; /* table of litLength statistics, of size (MaxLL+1) */
83
- U32* matchLengthFreq; /* table of matchLength statistics, of size (MaxML+1) */
84
- U32* offCodeFreq; /* table of offCode statistics, of size (MaxOff+1) */
85
- ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_NUM+1 */
86
- ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_NUM+1 */
99
+ U32* litFreq; /* table of literals statistics, of size 256 */
100
+ U32* litLengthFreq; /* table of litLength statistics, of size (MaxLL+1) */
101
+ U32* matchLengthFreq; /* table of matchLength statistics, of size (MaxML+1) */
102
+ U32* offCodeFreq; /* table of offCode statistics, of size (MaxOff+1) */
103
+ ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_NUM+1 */
104
+ ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_NUM+1 */
87
105
 
88
106
  U32 litSum; /* nb of literals */
89
107
  U32 litLengthSum; /* nb of litLength codes */
90
108
  U32 matchLengthSum; /* nb of matchLength codes */
91
109
  U32 offCodeSum; /* nb of offset codes */
92
- /* begin updated by ZSTD_setLog2Prices */
93
- U32 log2litSum; /* pow2 to compare log2(litfreq) to */
94
- U32 log2litLengthSum; /* pow2 to compare log2(llfreq) to */
95
- U32 log2matchLengthSum; /* pow2 to compare log2(mlfreq) to */
96
- U32 log2offCodeSum; /* pow2 to compare log2(offreq) to */
97
- /* end : updated by ZSTD_setLog2Prices */
98
- U32 staticPrices; /* prices follow a pre-defined cost structure, statistics are irrelevant */
110
+ U32 litSumBasePrice; /* to compare to log2(litfreq) */
111
+ U32 litLengthSumBasePrice; /* to compare to log2(llfreq) */
112
+ U32 matchLengthSumBasePrice;/* to compare to log2(mlfreq) */
113
+ U32 offCodeSumBasePrice; /* to compare to log2(offreq) */
114
+ ZSTD_OptPrice_e priceType; /* prices can be determined dynamically, or follow a pre-defined cost structure */
115
+ const ZSTD_entropyCTables_t* symbolCosts; /* pre-calculated dictionary statistics */
99
116
  } optState_t;
100
117
 
101
118
  typedef struct {
@@ -111,17 +128,19 @@ typedef struct {
111
128
  U32 lowLimit; /* below that point, no more data */
112
129
  } ZSTD_window_t;
113
130
 
114
- typedef struct {
115
- ZSTD_window_t window; /* State for window round buffer management */
116
- U32 loadedDictEnd; /* index of end of dictionary */
117
- U32 nextToUpdate; /* index from which to continue table update */
118
- U32 nextToUpdate3; /* index from which to continue table update */
119
- U32 hashLog3; /* dispatch table : larger == faster, more memory */
131
+ typedef struct ZSTD_matchState_t ZSTD_matchState_t;
132
+ struct ZSTD_matchState_t {
133
+ ZSTD_window_t window; /* State for window round buffer management */
134
+ U32 loadedDictEnd; /* index of end of dictionary */
135
+ U32 nextToUpdate; /* index from which to continue table update */
136
+ U32 nextToUpdate3; /* index from which to continue table update */
137
+ U32 hashLog3; /* dispatch table : larger == faster, more memory */
120
138
  U32* hashTable;
121
139
  U32* hashTable3;
122
140
  U32* chainTable;
123
141
  optState_t opt; /* optimal parser state */
124
- } ZSTD_matchState_t;
142
+ const ZSTD_matchState_t *dictMatchState;
143
+ };
125
144
 
126
145
  typedef struct {
127
146
  ZSTD_compressedBlockState_t* prevCBlock;
@@ -161,7 +180,7 @@ typedef struct {
161
180
  rawSeq* seq; /* The start of the sequences */
162
181
  size_t pos; /* The position where reading stopped. <= size. */
163
182
  size_t size; /* The number of sequences. <= capacity. */
164
- size_t capacity; /* The capacity of the `seq` pointer */
183
+ size_t capacity; /* The capacity starting from `seq` pointer */
165
184
  } rawSeqStore_t;
166
185
 
167
186
  struct ZSTD_CCtx_params_s {
@@ -170,10 +189,11 @@ struct ZSTD_CCtx_params_s {
170
189
  ZSTD_frameParameters fParams;
171
190
 
172
191
  int compressionLevel;
173
- int disableLiteralCompression;
174
192
  int forceWindow; /* force back-references to respect limit of
175
193
  * 1<<wLog, even for dictionary */
176
194
 
195
+ ZSTD_dictAttachPref_e attachDictPref;
196
+
177
197
  /* Multithreading: used to pass parameters to mtctx */
178
198
  unsigned nbWorkers;
179
199
  unsigned jobSize;
@@ -193,6 +213,8 @@ struct ZSTD_CCtx_s {
193
213
  ZSTD_CCtx_params requestedParams;
194
214
  ZSTD_CCtx_params appliedParams;
195
215
  U32 dictID;
216
+
217
+ int workSpaceOversizedDuration;
196
218
  void* workSpace;
197
219
  size_t workSpaceSize;
198
220
  size_t blockSize;
@@ -235,11 +257,15 @@ struct ZSTD_CCtx_s {
235
257
  #endif
236
258
  };
237
259
 
260
+ typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e;
261
+
262
+ typedef enum { ZSTD_noDict = 0, ZSTD_extDict = 1, ZSTD_dictMatchState = 2 } ZSTD_dictMode_e;
263
+
238
264
 
239
265
  typedef size_t (*ZSTD_blockCompressor) (
240
266
  ZSTD_matchState_t* bs, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
241
267
  ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize);
242
- ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict);
268
+ ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode);
243
269
 
244
270
 
245
271
  MEM_STATIC U32 ZSTD_LLcode(U32 litLength)
@@ -280,11 +306,11 @@ MEM_STATIC U32 ZSTD_MLcode(U32 mlBase)
280
306
  */
281
307
  MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t mlBase)
282
308
  {
283
- #if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 6)
309
+ #if defined(DEBUGLEVEL) && (DEBUGLEVEL >= 6)
284
310
  static const BYTE* g_start = NULL;
285
311
  if (g_start==NULL) g_start = (const BYTE*)literals; /* note : index only works for compression within a single segment */
286
312
  { U32 const pos = (U32)((const BYTE*)literals - g_start);
287
- DEBUGLOG(6, "Cpos%7u :%3u literals, match%3u bytes at dist.code%7u",
313
+ DEBUGLOG(6, "Cpos%7u :%3u literals, match%4u bytes at offCode%7u",
288
314
  pos, (U32)litLength, (U32)mlBase+MINMATCH, (U32)offsetCode);
289
315
  }
290
316
  #endif
@@ -420,6 +446,11 @@ ZSTD_count_2segments(const BYTE* ip, const BYTE* match,
420
446
  const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
421
447
  size_t const matchLength = ZSTD_count(ip, match, vEnd);
422
448
  if (match + matchLength != mEnd) return matchLength;
449
+ DEBUGLOG(7, "ZSTD_count_2segments: found a 2-parts match (current length==%zu)", matchLength);
450
+ DEBUGLOG(7, "distance from match beginning to end dictionary = %zi", mEnd - match);
451
+ DEBUGLOG(7, "distance from current pos to end buffer = %zi", iEnd - ip);
452
+ DEBUGLOG(7, "next byte : ip==%02X, istart==%02X", ip[matchLength], *iStart);
453
+ DEBUGLOG(7, "final match length = %zu", matchLength + ZSTD_count(ip+matchLength, iStart, iEnd));
423
454
  return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
424
455
  }
425
456
 
@@ -496,6 +527,20 @@ MEM_STATIC U32 ZSTD_window_hasExtDict(ZSTD_window_t const window)
496
527
  return window.lowLimit < window.dictLimit;
497
528
  }
498
529
 
530
+ /**
531
+ * ZSTD_matchState_dictMode():
532
+ * Inspects the provided matchState and figures out what dictMode should be
533
+ * passed to the compressor.
534
+ */
535
+ MEM_STATIC ZSTD_dictMode_e ZSTD_matchState_dictMode(const ZSTD_matchState_t *ms)
536
+ {
537
+ return ZSTD_window_hasExtDict(ms->window) ?
538
+ ZSTD_extDict :
539
+ ms->dictMatchState != NULL ?
540
+ ZSTD_dictMatchState :
541
+ ZSTD_noDict;
542
+ }
543
+
499
544
  /**
500
545
  * ZSTD_window_needOverflowCorrection():
501
546
  * Returns non-zero if the indices are getting too large and need overflow
@@ -563,31 +608,41 @@ MEM_STATIC U32 ZSTD_window_correctOverflow(ZSTD_window_t* window, U32 cycleLog,
563
608
  * ZSTD_window_enforceMaxDist():
564
609
  * Updates lowLimit so that:
565
610
  * (srcEnd - base) - lowLimit == maxDist + loadedDictEnd
611
+ *
566
612
  * This allows a simple check that index >= lowLimit to see if index is valid.
567
613
  * This must be called before a block compression call, with srcEnd as the block
568
614
  * source end.
615
+ *
569
616
  * If loadedDictEndPtr is not NULL, we set it to zero once we update lowLimit.
570
617
  * This is because dictionaries are allowed to be referenced as long as the last
571
618
  * byte of the dictionary is in the window, but once they are out of range,
572
619
  * they cannot be referenced. If loadedDictEndPtr is NULL, we use
573
620
  * loadedDictEnd == 0.
621
+ *
622
+ * In normal dict mode, the dict is between lowLimit and dictLimit. In
623
+ * dictMatchState mode, lowLimit and dictLimit are the same, and the dictionary
624
+ * is below them. forceWindow and dictMatchState are therefore incompatible.
574
625
  */
575
626
  MEM_STATIC void ZSTD_window_enforceMaxDist(ZSTD_window_t* window,
576
627
  void const* srcEnd, U32 maxDist,
577
- U32* loadedDictEndPtr)
628
+ U32* loadedDictEndPtr,
629
+ const ZSTD_matchState_t** dictMatchStatePtr)
578
630
  {
579
631
  U32 const current = (U32)((BYTE const*)srcEnd - window->base);
580
632
  U32 loadedDictEnd = loadedDictEndPtr != NULL ? *loadedDictEndPtr : 0;
633
+ DEBUGLOG(5, "ZSTD_window_enforceMaxDist: current=%u, maxDist=%u", current, maxDist);
581
634
  if (current > maxDist + loadedDictEnd) {
582
635
  U32 const newLowLimit = current - maxDist;
583
636
  if (window->lowLimit < newLowLimit) window->lowLimit = newLowLimit;
584
637
  if (window->dictLimit < window->lowLimit) {
585
- DEBUGLOG(5, "Update dictLimit from %u to %u", window->dictLimit,
586
- window->lowLimit);
638
+ DEBUGLOG(5, "Update dictLimit to match lowLimit, from %u to %u",
639
+ window->dictLimit, window->lowLimit);
587
640
  window->dictLimit = window->lowLimit;
588
641
  }
589
642
  if (loadedDictEndPtr)
590
643
  *loadedDictEndPtr = 0;
644
+ if (dictMatchStatePtr)
645
+ *dictMatchStatePtr = NULL;
591
646
  }
592
647
  }
593
648
 
@@ -603,12 +658,12 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
603
658
  {
604
659
  BYTE const* const ip = (BYTE const*)src;
605
660
  U32 contiguous = 1;
661
+ DEBUGLOG(5, "ZSTD_window_update");
606
662
  /* Check if blocks follow each other */
607
663
  if (src != window->nextSrc) {
608
664
  /* not contiguous */
609
665
  size_t const distanceFromBase = (size_t)(window->nextSrc - window->base);
610
- DEBUGLOG(5, "Non contiguous blocks, new segment starts at %u",
611
- window->dictLimit);
666
+ DEBUGLOG(5, "Non contiguous blocks, new segment starts at %u", window->dictLimit);
612
667
  window->lowLimit = window->dictLimit;
613
668
  assert(distanceFromBase == (size_t)(U32)distanceFromBase); /* should never overflow */
614
669
  window->dictLimit = (U32)distanceFromBase;
@@ -625,10 +680,38 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
625
680
  ptrdiff_t const highInputIdx = (ip + srcSize) - window->dictBase;
626
681
  U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)window->dictLimit) ? window->dictLimit : (U32)highInputIdx;
627
682
  window->lowLimit = lowLimitMax;
683
+ DEBUGLOG(5, "Overlapping extDict and input : new lowLimit = %u", window->lowLimit);
628
684
  }
629
685
  return contiguous;
630
686
  }
631
687
 
688
+
689
+ /* debug functions */
690
+
691
+ MEM_STATIC double ZSTD_fWeight(U32 rawStat)
692
+ {
693
+ U32 const fp_accuracy = 8;
694
+ U32 const fp_multiplier = (1 << fp_accuracy);
695
+ U32 const stat = rawStat + 1;
696
+ U32 const hb = ZSTD_highbit32(stat);
697
+ U32 const BWeight = hb * fp_multiplier;
698
+ U32 const FWeight = (stat << fp_accuracy) >> hb;
699
+ U32 const weight = BWeight + FWeight;
700
+ assert(hb + fp_accuracy < 31);
701
+ return (double)weight / fp_multiplier;
702
+ }
703
+
704
+ MEM_STATIC void ZSTD_debugTable(const U32* table, U32 max)
705
+ {
706
+ unsigned u, sum;
707
+ for (u=0, sum=0; u<=max; u++) sum += table[u];
708
+ DEBUGLOG(2, "total nb elts: %u", sum);
709
+ for (u=0; u<=max; u++) {
710
+ DEBUGLOG(2, "%2u: %5u (%.2f)",
711
+ u, table[u], ZSTD_fWeight(sum) - ZSTD_fWeight(table[u]) );
712
+ }
713
+ }
714
+
632
715
  #if defined (__cplusplus)
633
716
  }
634
717
  #endif
@@ -640,7 +723,7 @@ MEM_STATIC U32 ZSTD_window_update(ZSTD_window_t* window,
640
723
  * ============================================================== */
641
724
 
642
725
  /* ZSTD_getCParamsFromCCtxParams() :
643
- * cParams are built depending on compressionLevel, src size hints,
726
+ * cParams are built depending on compressionLevel, src size hints,
644
727
  * LDM and manually set compression parameters.
645
728
  */
646
729
  ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
@@ -656,6 +739,8 @@ size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
656
739
  const ZSTD_CDict* cdict,
657
740
  ZSTD_CCtx_params params, unsigned long long pledgedSrcSize);
658
741
 
742
+ void ZSTD_resetSeqStore(seqStore_t* ssPtr);
743
+
659
744
  /*! ZSTD_compressStream_generic() :
660
745
  * Private use only. To be called from zstdmt_compress.c in single-thread mode. */
661
746
  size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
@@ -672,6 +757,7 @@ ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict);
672
757
  size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
673
758
  const void* dict, size_t dictSize,
674
759
  ZSTD_dictContentType_e dictContentType,
760
+ ZSTD_dictTableLoadMethod_e dtlm,
675
761
  const ZSTD_CDict* cdict,
676
762
  ZSTD_CCtx_params params,
677
763
  unsigned long long pledgedSrcSize);
@@ -14,7 +14,7 @@
14
14
 
15
15
  void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
16
16
  ZSTD_compressionParameters const* cParams,
17
- void const* end)
17
+ void const* end, ZSTD_dictTableLoadMethod_e dtlm)
18
18
  {
19
19
  U32* const hashLarge = ms->hashTable;
20
20
  U32 const hBitsL = cParams->hashLog;
@@ -40,6 +40,9 @@ void ZSTD_fillDoubleHashTable(ZSTD_matchState_t* ms,
40
40
  hashSmall[smHash] = current + i;
41
41
  if (i == 0 || hashLarge[lgHash] == 0)
42
42
  hashLarge[lgHash] = current + i;
43
+ /* Only load extra positions for ZSTD_dtlm_full */
44
+ if (dtlm == ZSTD_dtlm_fast)
45
+ break;
43
46
  }
44
47
  }
45
48
  }
@@ -49,7 +52,7 @@ FORCE_INLINE_TEMPLATE
49
52
  size_t ZSTD_compressBlock_doubleFast_generic(
50
53
  ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
51
54
  ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize,
52
- U32 const mls /* template */)
55
+ U32 const mls /* template */, ZSTD_dictMode_e const dictMode)
53
56
  {
54
57
  U32* const hashLong = ms->hashTable;
55
58
  const U32 hBitsL = cParams->hashLog;
@@ -59,70 +62,178 @@ size_t ZSTD_compressBlock_doubleFast_generic(
59
62
  const BYTE* const istart = (const BYTE*)src;
60
63
  const BYTE* ip = istart;
61
64
  const BYTE* anchor = istart;
62
- const U32 lowestIndex = ms->window.dictLimit;
63
- const BYTE* const lowest = base + lowestIndex;
65
+ const U32 prefixLowestIndex = ms->window.dictLimit;
66
+ const BYTE* const prefixLowest = base + prefixLowestIndex;
64
67
  const BYTE* const iend = istart + srcSize;
65
68
  const BYTE* const ilimit = iend - HASH_READ_SIZE;
66
69
  U32 offset_1=rep[0], offset_2=rep[1];
67
70
  U32 offsetSaved = 0;
68
71
 
72
+ const ZSTD_matchState_t* const dms = ms->dictMatchState;
73
+ const U32* const dictHashLong = dictMode == ZSTD_dictMatchState ?
74
+ dms->hashTable : NULL;
75
+ const U32* const dictHashSmall = dictMode == ZSTD_dictMatchState ?
76
+ dms->chainTable : NULL;
77
+ const U32 dictStartIndex = dictMode == ZSTD_dictMatchState ?
78
+ dms->window.dictLimit : 0;
79
+ const BYTE* const dictBase = dictMode == ZSTD_dictMatchState ?
80
+ dms->window.base : NULL;
81
+ const BYTE* const dictStart = dictMode == ZSTD_dictMatchState ?
82
+ dictBase + dictStartIndex : NULL;
83
+ const BYTE* const dictEnd = dictMode == ZSTD_dictMatchState ?
84
+ dms->window.nextSrc : NULL;
85
+ const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ?
86
+ prefixLowestIndex - (U32)(dictEnd - dictBase) :
87
+ 0;
88
+ const U32 dictAndPrefixLength = (U32)(ip - prefixLowest + dictEnd - dictStart);
89
+
90
+ assert(dictMode == ZSTD_noDict || dictMode == ZSTD_dictMatchState);
91
+
69
92
  /* init */
70
- ip += (ip==lowest);
71
- { U32 const maxRep = (U32)(ip-lowest);
93
+ ip += (dictAndPrefixLength == 0);
94
+ if (dictMode == ZSTD_noDict) {
95
+ U32 const maxRep = (U32)(ip - prefixLowest);
72
96
  if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
73
97
  if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
74
98
  }
99
+ if (dictMode == ZSTD_dictMatchState) {
100
+ /* dictMatchState repCode checks don't currently handle repCode == 0
101
+ * disabling. */
102
+ assert(offset_1 <= dictAndPrefixLength);
103
+ assert(offset_2 <= dictAndPrefixLength);
104
+ }
75
105
 
76
106
  /* Main Search Loop */
77
107
  while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
78
108
  size_t mLength;
109
+ U32 offset;
79
110
  size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
80
111
  size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
81
112
  U32 const current = (U32)(ip-base);
82
113
  U32 const matchIndexL = hashLong[h2];
83
- U32 const matchIndexS = hashSmall[h];
114
+ U32 matchIndexS = hashSmall[h];
84
115
  const BYTE* matchLong = base + matchIndexL;
85
116
  const BYTE* match = base + matchIndexS;
117
+ const U32 repIndex = current + 1 - offset_1;
118
+ const BYTE* repMatch = (dictMode == ZSTD_dictMatchState
119
+ && repIndex < prefixLowestIndex) ?
120
+ dictBase + (repIndex - dictIndexDelta) :
121
+ base + repIndex;
86
122
  hashLong[h2] = hashSmall[h] = current; /* update hash tables */
87
123
 
88
- assert(offset_1 <= current); /* supposed guaranteed by construction */
89
- if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
90
- /* favor repcode */
124
+ /* check dictMatchState repcode */
125
+ if (dictMode == ZSTD_dictMatchState
126
+ && ((U32)((prefixLowestIndex-1) - repIndex) >= 3 /* intentional underflow */)
127
+ && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
128
+ const BYTE* repMatchEnd = repIndex < prefixLowestIndex ? dictEnd : iend;
129
+ mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixLowest) + 4;
130
+ ip++;
131
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
132
+ goto _match_stored;
133
+ }
134
+
135
+ /* check noDict repcode */
136
+ if ( dictMode == ZSTD_noDict
137
+ && ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)))) {
91
138
  mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
92
139
  ip++;
93
140
  ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
94
- } else {
95
- U32 offset;
96
- if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
97
- mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
98
- offset = (U32)(ip-matchLong);
99
- while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
100
- } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
101
- size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
102
- U32 const matchIndexL3 = hashLong[hl3];
103
- const BYTE* matchL3 = base + matchIndexL3;
104
- hashLong[hl3] = current + 1;
105
- if ( (matchIndexL3 > lowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) {
106
- mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
141
+ goto _match_stored;
142
+ }
143
+
144
+ /* check prefix long match */
145
+ if ( (matchIndexL > prefixLowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
146
+ mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
147
+ offset = (U32)(ip-matchLong);
148
+ while (((ip>anchor) & (matchLong>prefixLowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
149
+ goto _match_found;
150
+ }
151
+
152
+ /* check dictMatchState long match */
153
+ if (dictMode == ZSTD_dictMatchState) {
154
+ U32 const dictMatchIndexL = dictHashLong[h2];
155
+ const BYTE* dictMatchL = dictBase + dictMatchIndexL;
156
+ assert(dictMatchL < dictEnd);
157
+
158
+ if (dictMatchL > dictStart && MEM_read64(dictMatchL) == MEM_read64(ip)) {
159
+ mLength = ZSTD_count_2segments(ip+8, dictMatchL+8, iend, dictEnd, prefixLowest) + 8;
160
+ offset = (U32)(current - dictMatchIndexL - dictIndexDelta);
161
+ while (((ip>anchor) & (dictMatchL>dictStart)) && (ip[-1] == dictMatchL[-1])) { ip--; dictMatchL--; mLength++; } /* catch up */
162
+ goto _match_found;
163
+ }
164
+ }
165
+
166
+ /* check prefix short match */
167
+ if ( (matchIndexS > prefixLowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
168
+ goto _search_next_long;
169
+ }
170
+
171
+ /* check dictMatchState short match */
172
+ if (dictMode == ZSTD_dictMatchState) {
173
+ U32 const dictMatchIndexS = dictHashSmall[h];
174
+ match = dictBase + dictMatchIndexS;
175
+ matchIndexS = dictMatchIndexS + dictIndexDelta;
176
+
177
+ if (match > dictStart && MEM_read32(match) == MEM_read32(ip)) {
178
+ goto _search_next_long;
179
+ }
180
+ }
181
+
182
+ ip += ((ip-anchor) >> kSearchStrength) + 1;
183
+ continue;
184
+
185
+ _search_next_long:
186
+
187
+ {
188
+ size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
189
+ U32 const matchIndexL3 = hashLong[hl3];
190
+ const BYTE* matchL3 = base + matchIndexL3;
191
+ hashLong[hl3] = current + 1;
192
+
193
+ /* check prefix long +1 match */
194
+ if ( (matchIndexL3 > prefixLowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) {
195
+ mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
196
+ ip++;
197
+ offset = (U32)(ip-matchL3);
198
+ while (((ip>anchor) & (matchL3>prefixLowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
199
+ goto _match_found;
200
+ }
201
+
202
+ /* check dict long +1 match */
203
+ if (dictMode == ZSTD_dictMatchState) {
204
+ U32 const dictMatchIndexL3 = dictHashLong[hl3];
205
+ const BYTE* dictMatchL3 = dictBase + dictMatchIndexL3;
206
+ assert(dictMatchL3 < dictEnd);
207
+ if (dictMatchL3 > dictStart && MEM_read64(dictMatchL3) == MEM_read64(ip+1)) {
208
+ mLength = ZSTD_count_2segments(ip+1+8, dictMatchL3+8, iend, dictEnd, prefixLowest) + 8;
107
209
  ip++;
108
- offset = (U32)(ip-matchL3);
109
- while (((ip>anchor) & (matchL3>lowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
110
- } else {
111
- mLength = ZSTD_count(ip+4, match+4, iend) + 4;
112
- offset = (U32)(ip-match);
113
- while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
210
+ offset = (U32)(current + 1 - dictMatchIndexL3 - dictIndexDelta);
211
+ while (((ip>anchor) & (dictMatchL3>dictStart)) && (ip[-1] == dictMatchL3[-1])) { ip--; dictMatchL3--; mLength++; } /* catch up */
212
+ goto _match_found;
114
213
  }
115
- } else {
116
- ip += ((ip-anchor) >> kSearchStrength) + 1;
117
- continue;
118
214
  }
215
+ }
119
216
 
120
- offset_2 = offset_1;
121
- offset_1 = offset;
122
-
123
- ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
217
+ /* if no long +1 match, explore the short match we found */
218
+ if (dictMode == ZSTD_dictMatchState && matchIndexS < prefixLowestIndex) {
219
+ mLength = ZSTD_count_2segments(ip+4, match+4, iend, dictEnd, prefixLowest) + 4;
220
+ offset = (U32)(current - matchIndexS);
221
+ while (((ip>anchor) & (match>dictStart)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
222
+ } else {
223
+ mLength = ZSTD_count(ip+4, match+4, iend) + 4;
224
+ offset = (U32)(ip - match);
225
+ while (((ip>anchor) & (match>prefixLowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
124
226
  }
125
227
 
228
+ /* fall-through */
229
+
230
+ _match_found:
231
+ offset_2 = offset_1;
232
+ offset_1 = offset;
233
+
234
+ ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
235
+
236
+ _match_stored:
126
237
  /* match found */
127
238
  ip += mLength;
128
239
  anchor = ip;
@@ -135,19 +246,44 @@ size_t ZSTD_compressBlock_doubleFast_generic(
135
246
  hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
136
247
 
137
248
  /* check immediate repcode */
138
- while ( (ip <= ilimit)
139
- && ( (offset_2>0)
140
- & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
141
- /* store sequence */
142
- size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
143
- { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
144
- hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
145
- hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
146
- ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH);
147
- ip += rLength;
148
- anchor = ip;
149
- continue; /* faster when present ... (?) */
150
- } } }
249
+ if (dictMode == ZSTD_dictMatchState) {
250
+ while (ip <= ilimit) {
251
+ U32 const current2 = (U32)(ip-base);
252
+ U32 const repIndex2 = current2 - offset_2;
253
+ const BYTE* repMatch2 = dictMode == ZSTD_dictMatchState
254
+ && repIndex2 < prefixLowestIndex ?
255
+ dictBase - dictIndexDelta + repIndex2 :
256
+ base + repIndex2;
257
+ if ( ((U32)((prefixLowestIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */)
258
+ && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
259
+ const BYTE* const repEnd2 = repIndex2 < prefixLowestIndex ? dictEnd : iend;
260
+ size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixLowest) + 4;
261
+ U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
262
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
263
+ hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
264
+ hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
265
+ ip += repLength2;
266
+ anchor = ip;
267
+ continue;
268
+ }
269
+ break;
270
+ }
271
+ }
272
+
273
+ if (dictMode == ZSTD_noDict) {
274
+ while ( (ip <= ilimit)
275
+ && ( (offset_2>0)
276
+ & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
277
+ /* store sequence */
278
+ size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
279
+ U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */
280
+ hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
281
+ hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
282
+ ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH);
283
+ ip += rLength;
284
+ anchor = ip;
285
+ continue; /* faster when present ... (?) */
286
+ } } } }
151
287
 
152
288
  /* save reps for next block */
153
289
  rep[0] = offset_1 ? offset_1 : offsetSaved;
@@ -167,13 +303,33 @@ size_t ZSTD_compressBlock_doubleFast(
167
303
  {
168
304
  default: /* includes case 3 */
169
305
  case 4 :
170
- return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 4);
306
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 4, ZSTD_noDict);
171
307
  case 5 :
172
- return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 5);
308
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 5, ZSTD_noDict);
173
309
  case 6 :
174
- return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 6);
310
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 6, ZSTD_noDict);
175
311
  case 7 :
176
- return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 7);
312
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 7, ZSTD_noDict);
313
+ }
314
+ }
315
+
316
+
317
+ size_t ZSTD_compressBlock_doubleFast_dictMatchState(
318
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
319
+ ZSTD_compressionParameters const* cParams, void const* src, size_t srcSize)
320
+ {
321
+ const U32 mls = cParams->searchLength;
322
+ switch(mls)
323
+ {
324
+ default: /* includes case 3 */
325
+ case 4 :
326
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 4, ZSTD_dictMatchState);
327
+ case 5 :
328
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 5, ZSTD_dictMatchState);
329
+ case 6 :
330
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 6, ZSTD_dictMatchState);
331
+ case 7 :
332
+ return ZSTD_compressBlock_doubleFast_generic(ms, seqStore, rep, cParams, src, srcSize, 7, ZSTD_dictMatchState);
177
333
  }
178
334
  }
179
335
 
@@ -187,75 +343,78 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
187
343
  U32 const hBitsL = cParams->hashLog;
188
344
  U32* const hashSmall = ms->chainTable;
189
345
  U32 const hBitsS = cParams->chainLog;
190
- const BYTE* const base = ms->window.base;
191
- const BYTE* const dictBase = ms->window.dictBase;
192
346
  const BYTE* const istart = (const BYTE*)src;
193
347
  const BYTE* ip = istart;
194
348
  const BYTE* anchor = istart;
195
- const U32 lowestIndex = ms->window.lowLimit;
196
- const BYTE* const dictStart = dictBase + lowestIndex;
197
- const U32 dictLimit = ms->window.dictLimit;
198
- const BYTE* const lowPrefixPtr = base + dictLimit;
199
- const BYTE* const dictEnd = dictBase + dictLimit;
200
349
  const BYTE* const iend = istart + srcSize;
201
350
  const BYTE* const ilimit = iend - 8;
351
+ const U32 prefixStartIndex = ms->window.dictLimit;
352
+ const BYTE* const base = ms->window.base;
353
+ const BYTE* const prefixStart = base + prefixStartIndex;
354
+ const U32 dictStartIndex = ms->window.lowLimit;
355
+ const BYTE* const dictBase = ms->window.dictBase;
356
+ const BYTE* const dictStart = dictBase + dictStartIndex;
357
+ const BYTE* const dictEnd = dictBase + prefixStartIndex;
202
358
  U32 offset_1=rep[0], offset_2=rep[1];
203
359
 
360
+ DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_extDict_generic (srcSize=%zu)", srcSize);
361
+
204
362
  /* Search Loop */
205
363
  while (ip < ilimit) { /* < instead of <=, because (ip+1) */
206
364
  const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
207
365
  const U32 matchIndex = hashSmall[hSmall];
208
- const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
366
+ const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base;
209
367
  const BYTE* match = matchBase + matchIndex;
210
368
 
211
369
  const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
212
370
  const U32 matchLongIndex = hashLong[hLong];
213
- const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
371
+ const BYTE* const matchLongBase = matchLongIndex < prefixStartIndex ? dictBase : base;
214
372
  const BYTE* matchLong = matchLongBase + matchLongIndex;
215
373
 
216
374
  const U32 current = (U32)(ip-base);
217
375
  const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
218
- const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
219
- const BYTE* repMatch = repBase + repIndex;
376
+ const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base;
377
+ const BYTE* const repMatch = repBase + repIndex;
220
378
  size_t mLength;
221
379
  hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
222
380
 
223
- if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
224
- && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
225
- const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
226
- mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
381
+ if ((((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex doesn't overlap dict + prefix */
382
+ & (repIndex > dictStartIndex))
383
+ && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
384
+ const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend;
385
+ mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4;
227
386
  ip++;
228
387
  ZSTD_storeSeq(seqStore, ip-anchor, anchor, 0, mLength-MINMATCH);
229
388
  } else {
230
- if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
231
- const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
232
- const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
389
+ if ((matchLongIndex > dictStartIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
390
+ const BYTE* const matchEnd = matchLongIndex < prefixStartIndex ? dictEnd : iend;
391
+ const BYTE* const lowMatchPtr = matchLongIndex < prefixStartIndex ? dictStart : prefixStart;
233
392
  U32 offset;
234
- mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
393
+ mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, prefixStart) + 8;
235
394
  offset = current - matchLongIndex;
236
395
  while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
237
396
  offset_2 = offset_1;
238
397
  offset_1 = offset;
239
398
  ZSTD_storeSeq(seqStore, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
240
399
 
241
- } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
400
+ } else if ((matchIndex > dictStartIndex) && (MEM_read32(match) == MEM_read32(ip))) {
242
401
  size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
243
402
  U32 const matchIndex3 = hashLong[h3];
244
- const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
403
+ const BYTE* const match3Base = matchIndex3 < prefixStartIndex ? dictBase : base;
245
404
  const BYTE* match3 = match3Base + matchIndex3;
246
405
  U32 offset;
247
406
  hashLong[h3] = current + 1;
248
- if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
249
- const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
250
- const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
251
- mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
407
+ if ( (matchIndex3 > dictStartIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
408
+ const BYTE* const matchEnd = matchIndex3 < prefixStartIndex ? dictEnd : iend;
409
+ const BYTE* const lowMatchPtr = matchIndex3 < prefixStartIndex ? dictStart : prefixStart;
410
+ mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, prefixStart) + 8;
252
411
  ip++;
253
412
  offset = current+1 - matchIndex3;
254
413
  while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
255
414
  } else {
256
- const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
257
- const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
258
- mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
415
+ const BYTE* const matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend;
416
+ const BYTE* const lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart;
417
+ mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4;
259
418
  offset = current - matchIndex;
260
419
  while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
261
420
  }
@@ -282,12 +441,13 @@ static size_t ZSTD_compressBlock_doubleFast_extDict_generic(
282
441
  while (ip <= ilimit) {
283
442
  U32 const current2 = (U32)(ip-base);
284
443
  U32 const repIndex2 = current2 - offset_2;
285
- const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
286
- if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
287
- && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
288
- const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
289
- size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
290
- U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
444
+ const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2;
445
+ if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) /* intentional overflow : ensure repIndex2 doesn't overlap dict + prefix */
446
+ & (repIndex2 > dictStartIndex))
447
+ && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
448
+ const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend;
449
+ size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4;
450
+ U32 const tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
291
451
  ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH);
292
452
  hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
293
453
  hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;