zstd-ruby 1.4.5.0 → 1.4.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +35 -0
  3. data/README.md +2 -2
  4. data/ext/zstdruby/libzstd/Makefile +237 -138
  5. data/ext/zstdruby/libzstd/README.md +28 -0
  6. data/ext/zstdruby/libzstd/common/bitstream.h +25 -16
  7. data/ext/zstdruby/libzstd/common/compiler.h +118 -4
  8. data/ext/zstdruby/libzstd/common/cpu.h +1 -3
  9. data/ext/zstdruby/libzstd/common/debug.c +1 -1
  10. data/ext/zstdruby/libzstd/common/debug.h +12 -19
  11. data/ext/zstdruby/libzstd/common/entropy_common.c +189 -43
  12. data/ext/zstdruby/libzstd/common/error_private.c +2 -1
  13. data/ext/zstdruby/libzstd/common/error_private.h +2 -2
  14. data/ext/zstdruby/libzstd/common/fse.h +40 -12
  15. data/ext/zstdruby/libzstd/common/fse_decompress.c +124 -17
  16. data/ext/zstdruby/libzstd/common/huf.h +27 -6
  17. data/ext/zstdruby/libzstd/common/mem.h +67 -94
  18. data/ext/zstdruby/libzstd/common/pool.c +23 -17
  19. data/ext/zstdruby/libzstd/common/pool.h +2 -2
  20. data/ext/zstdruby/libzstd/common/threading.c +6 -5
  21. data/ext/zstdruby/libzstd/common/xxhash.c +19 -57
  22. data/ext/zstdruby/libzstd/common/xxhash.h +2 -2
  23. data/ext/zstdruby/libzstd/common/zstd_common.c +10 -10
  24. data/ext/zstdruby/libzstd/common/zstd_deps.h +111 -0
  25. data/ext/zstdruby/libzstd/common/zstd_errors.h +2 -1
  26. data/ext/zstdruby/libzstd/common/zstd_internal.h +90 -59
  27. data/ext/zstdruby/libzstd/common/zstd_trace.c +42 -0
  28. data/ext/zstdruby/libzstd/common/zstd_trace.h +152 -0
  29. data/ext/zstdruby/libzstd/compress/fse_compress.c +31 -24
  30. data/ext/zstdruby/libzstd/compress/hist.c +27 -29
  31. data/ext/zstdruby/libzstd/compress/hist.h +2 -2
  32. data/ext/zstdruby/libzstd/compress/huf_compress.c +217 -101
  33. data/ext/zstdruby/libzstd/compress/zstd_compress.c +1495 -478
  34. data/ext/zstdruby/libzstd/compress/zstd_compress_internal.h +143 -44
  35. data/ext/zstdruby/libzstd/compress/zstd_compress_literals.c +7 -7
  36. data/ext/zstdruby/libzstd/compress/zstd_compress_literals.h +1 -1
  37. data/ext/zstdruby/libzstd/compress/zstd_compress_sequences.c +18 -4
  38. data/ext/zstdruby/libzstd/compress/zstd_compress_sequences.h +1 -1
  39. data/ext/zstdruby/libzstd/compress/zstd_compress_superblock.c +25 -21
  40. data/ext/zstdruby/libzstd/compress/zstd_compress_superblock.h +1 -1
  41. data/ext/zstdruby/libzstd/compress/zstd_cwksp.h +62 -26
  42. data/ext/zstdruby/libzstd/compress/zstd_double_fast.c +23 -23
  43. data/ext/zstdruby/libzstd/compress/zstd_double_fast.h +1 -1
  44. data/ext/zstdruby/libzstd/compress/zstd_fast.c +21 -21
  45. data/ext/zstdruby/libzstd/compress/zstd_fast.h +1 -1
  46. data/ext/zstdruby/libzstd/compress/zstd_lazy.c +352 -78
  47. data/ext/zstdruby/libzstd/compress/zstd_lazy.h +21 -1
  48. data/ext/zstdruby/libzstd/compress/zstd_ldm.c +276 -209
  49. data/ext/zstdruby/libzstd/compress/zstd_ldm.h +8 -2
  50. data/ext/zstdruby/libzstd/compress/zstd_ldm_geartab.h +103 -0
  51. data/ext/zstdruby/libzstd/compress/zstd_opt.c +191 -46
  52. data/ext/zstdruby/libzstd/compress/zstd_opt.h +1 -1
  53. data/ext/zstdruby/libzstd/compress/zstdmt_compress.c +79 -410
  54. data/ext/zstdruby/libzstd/compress/zstdmt_compress.h +27 -109
  55. data/ext/zstdruby/libzstd/decompress/huf_decompress.c +303 -201
  56. data/ext/zstdruby/libzstd/decompress/zstd_ddict.c +9 -9
  57. data/ext/zstdruby/libzstd/decompress/zstd_ddict.h +2 -2
  58. data/ext/zstdruby/libzstd/decompress/zstd_decompress.c +370 -87
  59. data/ext/zstdruby/libzstd/decompress/zstd_decompress_block.c +153 -45
  60. data/ext/zstdruby/libzstd/decompress/zstd_decompress_block.h +6 -3
  61. data/ext/zstdruby/libzstd/decompress/zstd_decompress_internal.h +28 -11
  62. data/ext/zstdruby/libzstd/deprecated/zbuff.h +1 -1
  63. data/ext/zstdruby/libzstd/deprecated/zbuff_common.c +1 -1
  64. data/ext/zstdruby/libzstd/deprecated/zbuff_compress.c +1 -1
  65. data/ext/zstdruby/libzstd/deprecated/zbuff_decompress.c +1 -1
  66. data/ext/zstdruby/libzstd/dictBuilder/cover.c +40 -31
  67. data/ext/zstdruby/libzstd/dictBuilder/cover.h +2 -2
  68. data/ext/zstdruby/libzstd/dictBuilder/divsufsort.c +1 -1
  69. data/ext/zstdruby/libzstd/dictBuilder/fastcover.c +26 -25
  70. data/ext/zstdruby/libzstd/dictBuilder/zdict.c +22 -24
  71. data/ext/zstdruby/libzstd/dictBuilder/zdict.h +5 -4
  72. data/ext/zstdruby/libzstd/dll/example/Makefile +1 -1
  73. data/ext/zstdruby/libzstd/dll/example/README.md +16 -22
  74. data/ext/zstdruby/libzstd/legacy/zstd_legacy.h +1 -1
  75. data/ext/zstdruby/libzstd/legacy/zstd_v01.c +6 -2
  76. data/ext/zstdruby/libzstd/legacy/zstd_v01.h +1 -1
  77. data/ext/zstdruby/libzstd/legacy/zstd_v02.c +6 -2
  78. data/ext/zstdruby/libzstd/legacy/zstd_v02.h +1 -1
  79. data/ext/zstdruby/libzstd/legacy/zstd_v03.c +6 -2
  80. data/ext/zstdruby/libzstd/legacy/zstd_v03.h +1 -1
  81. data/ext/zstdruby/libzstd/legacy/zstd_v04.c +7 -3
  82. data/ext/zstdruby/libzstd/legacy/zstd_v04.h +1 -1
  83. data/ext/zstdruby/libzstd/legacy/zstd_v05.c +10 -6
  84. data/ext/zstdruby/libzstd/legacy/zstd_v05.h +1 -1
  85. data/ext/zstdruby/libzstd/legacy/zstd_v06.c +10 -6
  86. data/ext/zstdruby/libzstd/legacy/zstd_v06.h +1 -1
  87. data/ext/zstdruby/libzstd/legacy/zstd_v07.c +10 -6
  88. data/ext/zstdruby/libzstd/legacy/zstd_v07.h +1 -1
  89. data/ext/zstdruby/libzstd/libzstd.pc.in +3 -3
  90. data/ext/zstdruby/libzstd/zstd.h +414 -54
  91. data/lib/zstd-ruby/version.rb +1 -1
  92. metadata +7 -3
  93. data/.travis.yml +0 -14
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
2
+ * Copyright (c) 2016-2021, Yann Collet, Facebook, Inc.
3
3
  * All rights reserved.
4
4
  *
5
5
  * This source code is licensed under both the BSD-style license (found in the
@@ -17,8 +17,18 @@ extern "C" {
17
17
 
18
18
  #include "zstd_compress_internal.h"
19
19
 
20
+ /**
21
+ * Dedicated Dictionary Search Structure bucket log. In the
22
+ * ZSTD_dedicatedDictSearch mode, the hashTable has
23
+ * 2 ** ZSTD_LAZY_DDSS_BUCKET_LOG entries in each bucket, rather than just
24
+ * one.
25
+ */
26
+ #define ZSTD_LAZY_DDSS_BUCKET_LOG 2
27
+
20
28
  U32 ZSTD_insertAndFindFirstIndex(ZSTD_matchState_t* ms, const BYTE* ip);
21
29
 
30
+ void ZSTD_dedicatedDictSearch_lazy_loadDictionary(ZSTD_matchState_t* ms, const BYTE* const ip);
31
+
22
32
  void ZSTD_preserveUnsortedMark (U32* const table, U32 const size, U32 const reducerValue); /*! used in ZSTD_reduceIndex(). preemptively increase value of ZSTD_DUBT_UNSORTED_MARK */
23
33
 
24
34
  size_t ZSTD_compressBlock_btlazy2(
@@ -47,6 +57,16 @@ size_t ZSTD_compressBlock_greedy_dictMatchState(
47
57
  ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
48
58
  void const* src, size_t srcSize);
49
59
 
60
+ size_t ZSTD_compressBlock_lazy2_dedicatedDictSearch(
61
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
62
+ void const* src, size_t srcSize);
63
+ size_t ZSTD_compressBlock_lazy_dedicatedDictSearch(
64
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
65
+ void const* src, size_t srcSize);
66
+ size_t ZSTD_compressBlock_greedy_dedicatedDictSearch(
67
+ ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
68
+ void const* src, size_t srcSize);
69
+
50
70
  size_t ZSTD_compressBlock_greedy_extDict(
51
71
  ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
52
72
  void const* src, size_t srcSize);
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
2
+ * Copyright (c) 2016-2021, Yann Collet, Facebook, Inc.
3
3
  * All rights reserved.
4
4
  *
5
5
  * This source code is licensed under both the BSD-style license (found in the
@@ -11,13 +11,99 @@
11
11
  #include "zstd_ldm.h"
12
12
 
13
13
  #include "../common/debug.h"
14
+ #include "../common/xxhash.h"
14
15
  #include "zstd_fast.h" /* ZSTD_fillHashTable() */
15
16
  #include "zstd_double_fast.h" /* ZSTD_fillDoubleHashTable() */
17
+ #include "zstd_ldm_geartab.h"
16
18
 
17
19
  #define LDM_BUCKET_SIZE_LOG 3
18
20
  #define LDM_MIN_MATCH_LENGTH 64
19
21
  #define LDM_HASH_RLOG 7
20
- #define LDM_HASH_CHAR_OFFSET 10
22
+
23
+ typedef struct {
24
+ U64 rolling;
25
+ U64 stopMask;
26
+ } ldmRollingHashState_t;
27
+
28
+ /** ZSTD_ldm_gear_init():
29
+ *
30
+ * Initializes the rolling hash state such that it will honor the
31
+ * settings in params. */
32
+ static void ZSTD_ldm_gear_init(ldmRollingHashState_t* state, ldmParams_t const* params)
33
+ {
34
+ unsigned maxBitsInMask = MIN(params->minMatchLength, 64);
35
+ unsigned hashRateLog = params->hashRateLog;
36
+
37
+ state->rolling = ~(U32)0;
38
+
39
+ /* The choice of the splitting criterion is subject to two conditions:
40
+ * 1. it has to trigger on average every 2^(hashRateLog) bytes;
41
+ * 2. ideally, it has to depend on a window of minMatchLength bytes.
42
+ *
43
+ * In the gear hash algorithm, bit n depends on the last n bytes;
44
+ * so in order to obtain a good quality splitting criterion it is
45
+ * preferable to use bits with high weight.
46
+ *
47
+ * To match condition 1 we use a mask with hashRateLog bits set
48
+ * and, because of the previous remark, we make sure these bits
49
+ * have the highest possible weight while still respecting
50
+ * condition 2.
51
+ */
52
+ if (hashRateLog > 0 && hashRateLog <= maxBitsInMask) {
53
+ state->stopMask = (((U64)1 << hashRateLog) - 1) << (maxBitsInMask - hashRateLog);
54
+ } else {
55
+ /* In this degenerate case we simply honor the hash rate. */
56
+ state->stopMask = ((U64)1 << hashRateLog) - 1;
57
+ }
58
+ }
59
+
60
+ /** ZSTD_ldm_gear_feed():
61
+ *
62
+ * Registers in the splits array all the split points found in the first
63
+ * size bytes following the data pointer. This function terminates when
64
+ * either all the data has been processed or LDM_BATCH_SIZE splits are
65
+ * present in the splits array.
66
+ *
67
+ * Precondition: The splits array must not be full.
68
+ * Returns: The number of bytes processed. */
69
+ static size_t ZSTD_ldm_gear_feed(ldmRollingHashState_t* state,
70
+ BYTE const* data, size_t size,
71
+ size_t* splits, unsigned* numSplits)
72
+ {
73
+ size_t n;
74
+ U64 hash, mask;
75
+
76
+ hash = state->rolling;
77
+ mask = state->stopMask;
78
+ n = 0;
79
+
80
+ #define GEAR_ITER_ONCE() do { \
81
+ hash = (hash << 1) + ZSTD_ldm_gearTab[data[n] & 0xff]; \
82
+ n += 1; \
83
+ if (UNLIKELY((hash & mask) == 0)) { \
84
+ splits[*numSplits] = n; \
85
+ *numSplits += 1; \
86
+ if (*numSplits == LDM_BATCH_SIZE) \
87
+ goto done; \
88
+ } \
89
+ } while (0)
90
+
91
+ while (n + 3 < size) {
92
+ GEAR_ITER_ONCE();
93
+ GEAR_ITER_ONCE();
94
+ GEAR_ITER_ONCE();
95
+ GEAR_ITER_ONCE();
96
+ }
97
+ while (n < size) {
98
+ GEAR_ITER_ONCE();
99
+ }
100
+
101
+ #undef GEAR_ITER_ONCE
102
+
103
+ done:
104
+ state->rolling = hash;
105
+ return n;
106
+ }
21
107
 
22
108
  void ZSTD_ldm_adjustParameters(ldmParams_t* params,
23
109
  ZSTD_compressionParameters const* cParams)
@@ -27,13 +113,6 @@ void ZSTD_ldm_adjustParameters(ldmParams_t* params,
27
113
  DEBUGLOG(4, "ZSTD_ldm_adjustParameters");
28
114
  if (!params->bucketSizeLog) params->bucketSizeLog = LDM_BUCKET_SIZE_LOG;
29
115
  if (!params->minMatchLength) params->minMatchLength = LDM_MIN_MATCH_LENGTH;
30
- if (cParams->strategy >= ZSTD_btopt) {
31
- /* Get out of the way of the optimal parser */
32
- U32 const minMatch = MAX(cParams->targetLength, params->minMatchLength);
33
- assert(minMatch >= ZSTD_LDM_MINMATCH_MIN);
34
- assert(minMatch <= ZSTD_LDM_MINMATCH_MAX);
35
- params->minMatchLength = minMatch;
36
- }
37
116
  if (params->hashLog == 0) {
38
117
  params->hashLog = MAX(ZSTD_HASHLOG_MIN, params->windowLog - LDM_HASH_RLOG);
39
118
  assert(params->hashLog <= ZSTD_HASHLOG_MAX);
@@ -61,41 +140,6 @@ size_t ZSTD_ldm_getMaxNbSeq(ldmParams_t params, size_t maxChunkSize)
61
140
  return params.enableLdm ? (maxChunkSize / params.minMatchLength) : 0;
62
141
  }
63
142
 
64
- /** ZSTD_ldm_getSmallHash() :
65
- * numBits should be <= 32
66
- * If numBits==0, returns 0.
67
- * @return : the most significant numBits of value. */
68
- static U32 ZSTD_ldm_getSmallHash(U64 value, U32 numBits)
69
- {
70
- assert(numBits <= 32);
71
- return numBits == 0 ? 0 : (U32)(value >> (64 - numBits));
72
- }
73
-
74
- /** ZSTD_ldm_getChecksum() :
75
- * numBitsToDiscard should be <= 32
76
- * @return : the next most significant 32 bits after numBitsToDiscard */
77
- static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard)
78
- {
79
- assert(numBitsToDiscard <= 32);
80
- return (hash >> (64 - 32 - numBitsToDiscard)) & 0xFFFFFFFF;
81
- }
82
-
83
- /** ZSTD_ldm_getTag() ;
84
- * Given the hash, returns the most significant numTagBits bits
85
- * after (32 + hbits) bits.
86
- *
87
- * If there are not enough bits remaining, return the last
88
- * numTagBits bits. */
89
- static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits)
90
- {
91
- assert(numTagBits < 32 && hbits <= 32);
92
- if (32 - hbits < numTagBits) {
93
- return hash & (((U32)1 << numTagBits) - 1);
94
- } else {
95
- return (hash >> (32 - hbits - numTagBits)) & (((U32)1 << numTagBits) - 1);
96
- }
97
- }
98
-
99
143
  /** ZSTD_ldm_getBucket() :
100
144
  * Returns a pointer to the start of the bucket associated with hash. */
101
145
  static ldmEntry_t* ZSTD_ldm_getBucket(
@@ -110,38 +154,12 @@ static void ZSTD_ldm_insertEntry(ldmState_t* ldmState,
110
154
  size_t const hash, const ldmEntry_t entry,
111
155
  ldmParams_t const ldmParams)
112
156
  {
113
- BYTE* const bucketOffsets = ldmState->bucketOffsets;
114
- *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry;
115
- bucketOffsets[hash]++;
116
- bucketOffsets[hash] &= ((U32)1 << ldmParams.bucketSizeLog) - 1;
117
- }
157
+ BYTE* const pOffset = ldmState->bucketOffsets + hash;
158
+ unsigned const offset = *pOffset;
159
+
160
+ *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + offset) = entry;
161
+ *pOffset = (BYTE)((offset + 1) & ((1u << ldmParams.bucketSizeLog) - 1));
118
162
 
119
- /** ZSTD_ldm_makeEntryAndInsertByTag() :
120
- *
121
- * Gets the small hash, checksum, and tag from the rollingHash.
122
- *
123
- * If the tag matches (1 << ldmParams.hashRateLog)-1, then
124
- * creates an ldmEntry from the offset, and inserts it into the hash table.
125
- *
126
- * hBits is the length of the small hash, which is the most significant hBits
127
- * of rollingHash. The checksum is the next 32 most significant bits, followed
128
- * by ldmParams.hashRateLog bits that make up the tag. */
129
- static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState,
130
- U64 const rollingHash,
131
- U32 const hBits,
132
- U32 const offset,
133
- ldmParams_t const ldmParams)
134
- {
135
- U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashRateLog);
136
- U32 const tagMask = ((U32)1 << ldmParams.hashRateLog) - 1;
137
- if (tag == tagMask) {
138
- U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits);
139
- U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
140
- ldmEntry_t entry;
141
- entry.offset = offset;
142
- entry.checksum = checksum;
143
- ZSTD_ldm_insertEntry(ldmState, hash, entry, ldmParams);
144
- }
145
163
  }
146
164
 
147
165
  /** ZSTD_ldm_countBackwardsMatch() :
@@ -150,10 +168,10 @@ static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState,
150
168
  * We count only bytes where pMatch >= pBase and pIn >= pAnchor. */
151
169
  static size_t ZSTD_ldm_countBackwardsMatch(
152
170
  const BYTE* pIn, const BYTE* pAnchor,
153
- const BYTE* pMatch, const BYTE* pBase)
171
+ const BYTE* pMatch, const BYTE* pMatchBase)
154
172
  {
155
173
  size_t matchLength = 0;
156
- while (pIn > pAnchor && pMatch > pBase && pIn[-1] == pMatch[-1]) {
174
+ while (pIn > pAnchor && pMatch > pMatchBase && pIn[-1] == pMatch[-1]) {
157
175
  pIn--;
158
176
  pMatch--;
159
177
  matchLength++;
@@ -161,6 +179,27 @@ static size_t ZSTD_ldm_countBackwardsMatch(
161
179
  return matchLength;
162
180
  }
163
181
 
182
+ /** ZSTD_ldm_countBackwardsMatch_2segments() :
183
+ * Returns the number of bytes that match backwards from pMatch,
184
+ * even with the backwards match spanning 2 different segments.
185
+ *
186
+ * On reaching `pMatchBase`, start counting from mEnd */
187
+ static size_t ZSTD_ldm_countBackwardsMatch_2segments(
188
+ const BYTE* pIn, const BYTE* pAnchor,
189
+ const BYTE* pMatch, const BYTE* pMatchBase,
190
+ const BYTE* pExtDictStart, const BYTE* pExtDictEnd)
191
+ {
192
+ size_t matchLength = ZSTD_ldm_countBackwardsMatch(pIn, pAnchor, pMatch, pMatchBase);
193
+ if (pMatch - matchLength != pMatchBase || pMatchBase == pExtDictStart) {
194
+ /* If backwards match is entirely in the extDict or prefix, immediately return */
195
+ return matchLength;
196
+ }
197
+ DEBUGLOG(7, "ZSTD_ldm_countBackwardsMatch_2segments: found 2-parts backwards match (length in prefix==%zu)", matchLength);
198
+ matchLength += ZSTD_ldm_countBackwardsMatch(pIn - matchLength, pAnchor, pExtDictEnd, pExtDictStart);
199
+ DEBUGLOG(7, "final backwards match length = %zu", matchLength);
200
+ return matchLength;
201
+ }
202
+
164
203
  /** ZSTD_ldm_fillFastTables() :
165
204
  *
166
205
  * Fills the relevant tables for the ZSTD_fast and ZSTD_dfast strategies.
@@ -198,43 +237,42 @@ static size_t ZSTD_ldm_fillFastTables(ZSTD_matchState_t* ms,
198
237
  return 0;
199
238
  }
200
239
 
201
- /** ZSTD_ldm_fillLdmHashTable() :
202
- *
203
- * Fills hashTable from (lastHashed + 1) to iend (non-inclusive).
204
- * lastHash is the rolling hash that corresponds to lastHashed.
205
- *
206
- * Returns the rolling hash corresponding to position iend-1. */
207
- static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state,
208
- U64 lastHash, const BYTE* lastHashed,
209
- const BYTE* iend, const BYTE* base,
210
- U32 hBits, ldmParams_t const ldmParams)
211
- {
212
- U64 rollingHash = lastHash;
213
- const BYTE* cur = lastHashed + 1;
214
-
215
- while (cur < iend) {
216
- rollingHash = ZSTD_rollingHash_rotate(rollingHash, cur[-1],
217
- cur[ldmParams.minMatchLength-1],
218
- state->hashPower);
219
- ZSTD_ldm_makeEntryAndInsertByTag(state,
220
- rollingHash, hBits,
221
- (U32)(cur - base), ldmParams);
222
- ++cur;
223
- }
224
- return rollingHash;
225
- }
226
-
227
240
  void ZSTD_ldm_fillHashTable(
228
- ldmState_t* state, const BYTE* ip,
241
+ ldmState_t* ldmState, const BYTE* ip,
229
242
  const BYTE* iend, ldmParams_t const* params)
230
243
  {
244
+ U32 const minMatchLength = params->minMatchLength;
245
+ U32 const hBits = params->hashLog - params->bucketSizeLog;
246
+ BYTE const* const base = ldmState->window.base;
247
+ BYTE const* const istart = ip;
248
+ ldmRollingHashState_t hashState;
249
+ size_t* const splits = ldmState->splitIndices;
250
+ unsigned numSplits;
251
+
231
252
  DEBUGLOG(5, "ZSTD_ldm_fillHashTable");
232
- if ((size_t)(iend - ip) >= params->minMatchLength) {
233
- U64 startingHash = ZSTD_rollingHash_compute(ip, params->minMatchLength);
234
- ZSTD_ldm_fillLdmHashTable(
235
- state, startingHash, ip, iend - params->minMatchLength, state->window.base,
236
- params->hashLog - params->bucketSizeLog,
237
- *params);
253
+
254
+ ZSTD_ldm_gear_init(&hashState, params);
255
+ while (ip < iend) {
256
+ size_t hashed;
257
+ unsigned n;
258
+
259
+ numSplits = 0;
260
+ hashed = ZSTD_ldm_gear_feed(&hashState, ip, iend - ip, splits, &numSplits);
261
+
262
+ for (n = 0; n < numSplits; n++) {
263
+ if (ip + splits[n] >= istart + minMatchLength) {
264
+ BYTE const* const split = ip + splits[n] - minMatchLength;
265
+ U64 const xxhash = XXH64(split, minMatchLength, 0);
266
+ U32 const hash = (U32)(xxhash & (((U32)1 << hBits) - 1));
267
+ ldmEntry_t entry;
268
+
269
+ entry.offset = (U32)(split - base);
270
+ entry.checksum = (U32)(xxhash >> 32);
271
+ ZSTD_ldm_insertEntry(ldmState, hash, entry, *params);
272
+ }
273
+ }
274
+
275
+ ip += hashed;
238
276
  }
239
277
  }
240
278
 
@@ -246,10 +284,10 @@ void ZSTD_ldm_fillHashTable(
246
284
  * (after a long match, only update tables a limited amount). */
247
285
  static void ZSTD_ldm_limitTableUpdate(ZSTD_matchState_t* ms, const BYTE* anchor)
248
286
  {
249
- U32 const current = (U32)(anchor - ms->window.base);
250
- if (current > ms->nextToUpdate + 1024) {
287
+ U32 const curr = (U32)(anchor - ms->window.base);
288
+ if (curr > ms->nextToUpdate + 1024) {
251
289
  ms->nextToUpdate =
252
- current - MIN(512, current - ms->nextToUpdate - 1024);
290
+ curr - MIN(512, curr - ms->nextToUpdate - 1024);
253
291
  }
254
292
  }
255
293
 
@@ -260,11 +298,8 @@ static size_t ZSTD_ldm_generateSequences_internal(
260
298
  /* LDM parameters */
261
299
  int const extDict = ZSTD_window_hasExtDict(ldmState->window);
262
300
  U32 const minMatchLength = params->minMatchLength;
263
- U64 const hashPower = ldmState->hashPower;
301
+ U32 const entsPerBucket = 1U << params->bucketSizeLog;
264
302
  U32 const hBits = params->hashLog - params->bucketSizeLog;
265
- U32 const ldmBucketSize = 1U << params->bucketSizeLog;
266
- U32 const hashRateLog = params->hashRateLog;
267
- U32 const ldmTagMask = (1U << params->hashRateLog) - 1;
268
303
  /* Prefix and extDict parameters */
269
304
  U32 const dictLimit = ldmState->window.dictLimit;
270
305
  U32 const lowestIndex = extDict ? ldmState->window.lowLimit : dictLimit;
@@ -276,45 +311,76 @@ static size_t ZSTD_ldm_generateSequences_internal(
276
311
  /* Input bounds */
277
312
  BYTE const* const istart = (BYTE const*)src;
278
313
  BYTE const* const iend = istart + srcSize;
279
- BYTE const* const ilimit = iend - MAX(minMatchLength, HASH_READ_SIZE);
314
+ BYTE const* const ilimit = iend - HASH_READ_SIZE;
280
315
  /* Input positions */
281
316
  BYTE const* anchor = istart;
282
317
  BYTE const* ip = istart;
283
- /* Rolling hash */
284
- BYTE const* lastHashed = NULL;
285
- U64 rollingHash = 0;
286
-
287
- while (ip <= ilimit) {
288
- size_t mLength;
289
- U32 const current = (U32)(ip - base);
290
- size_t forwardMatchLength = 0, backwardMatchLength = 0;
291
- ldmEntry_t* bestEntry = NULL;
292
- if (ip != istart) {
293
- rollingHash = ZSTD_rollingHash_rotate(rollingHash, lastHashed[0],
294
- lastHashed[minMatchLength],
295
- hashPower);
296
- } else {
297
- rollingHash = ZSTD_rollingHash_compute(ip, minMatchLength);
318
+ /* Rolling hash state */
319
+ ldmRollingHashState_t hashState;
320
+ /* Arrays for staged-processing */
321
+ size_t* const splits = ldmState->splitIndices;
322
+ ldmMatchCandidate_t* const candidates = ldmState->matchCandidates;
323
+ unsigned numSplits;
324
+
325
+ if (srcSize < minMatchLength)
326
+ return iend - anchor;
327
+
328
+ /* Initialize the rolling hash state with the first minMatchLength bytes */
329
+ ZSTD_ldm_gear_init(&hashState, params);
330
+ {
331
+ size_t n = 0;
332
+
333
+ while (n < minMatchLength) {
334
+ numSplits = 0;
335
+ n += ZSTD_ldm_gear_feed(&hashState, ip + n, minMatchLength - n,
336
+ splits, &numSplits);
298
337
  }
299
- lastHashed = ip;
338
+ ip += minMatchLength;
339
+ }
340
+
341
+ while (ip < ilimit) {
342
+ size_t hashed;
343
+ unsigned n;
300
344
 
301
- /* Do not insert and do not look for a match */
302
- if (ZSTD_ldm_getTag(rollingHash, hBits, hashRateLog) != ldmTagMask) {
303
- ip++;
304
- continue;
345
+ numSplits = 0;
346
+ hashed = ZSTD_ldm_gear_feed(&hashState, ip, ilimit - ip,
347
+ splits, &numSplits);
348
+
349
+ for (n = 0; n < numSplits; n++) {
350
+ BYTE const* const split = ip + splits[n] - minMatchLength;
351
+ U64 const xxhash = XXH64(split, minMatchLength, 0);
352
+ U32 const hash = (U32)(xxhash & (((U32)1 << hBits) - 1));
353
+
354
+ candidates[n].split = split;
355
+ candidates[n].hash = hash;
356
+ candidates[n].checksum = (U32)(xxhash >> 32);
357
+ candidates[n].bucket = ZSTD_ldm_getBucket(ldmState, hash, *params);
358
+ PREFETCH_L1(candidates[n].bucket);
305
359
  }
306
360
 
307
- /* Get the best entry and compute the match lengths */
308
- {
309
- ldmEntry_t* const bucket =
310
- ZSTD_ldm_getBucket(ldmState,
311
- ZSTD_ldm_getSmallHash(rollingHash, hBits),
312
- *params);
313
- ldmEntry_t* cur;
314
- size_t bestMatchLength = 0;
315
- U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits);
316
-
317
- for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) {
361
+ for (n = 0; n < numSplits; n++) {
362
+ size_t forwardMatchLength = 0, backwardMatchLength = 0,
363
+ bestMatchLength = 0, mLength;
364
+ BYTE const* const split = candidates[n].split;
365
+ U32 const checksum = candidates[n].checksum;
366
+ U32 const hash = candidates[n].hash;
367
+ ldmEntry_t* const bucket = candidates[n].bucket;
368
+ ldmEntry_t const* cur;
369
+ ldmEntry_t const* bestEntry = NULL;
370
+ ldmEntry_t newEntry;
371
+
372
+ newEntry.offset = (U32)(split - base);
373
+ newEntry.checksum = checksum;
374
+
375
+ /* If a split point would generate a sequence overlapping with
376
+ * the previous one, we merely register it in the hash table and
377
+ * move on */
378
+ if (split < anchor) {
379
+ ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
380
+ continue;
381
+ }
382
+
383
+ for (cur = bucket; cur < bucket + entsPerBucket; cur++) {
318
384
  size_t curForwardMatchLength, curBackwardMatchLength,
319
385
  curTotalMatchLength;
320
386
  if (cur->checksum != checksum || cur->offset <= lowestIndex) {
@@ -328,30 +394,23 @@ static size_t ZSTD_ldm_generateSequences_internal(
328
394
  cur->offset < dictLimit ? dictEnd : iend;
329
395
  BYTE const* const lowMatchPtr =
330
396
  cur->offset < dictLimit ? dictStart : lowPrefixPtr;
331
-
332
- curForwardMatchLength = ZSTD_count_2segments(
333
- ip, pMatch, iend,
334
- matchEnd, lowPrefixPtr);
397
+ curForwardMatchLength =
398
+ ZSTD_count_2segments(split, pMatch, iend, matchEnd, lowPrefixPtr);
335
399
  if (curForwardMatchLength < minMatchLength) {
336
400
  continue;
337
401
  }
338
- curBackwardMatchLength =
339
- ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch,
340
- lowMatchPtr);
341
- curTotalMatchLength = curForwardMatchLength +
342
- curBackwardMatchLength;
402
+ curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch_2segments(
403
+ split, anchor, pMatch, lowMatchPtr, dictStart, dictEnd);
343
404
  } else { /* !extDict */
344
405
  BYTE const* const pMatch = base + cur->offset;
345
- curForwardMatchLength = ZSTD_count(ip, pMatch, iend);
406
+ curForwardMatchLength = ZSTD_count(split, pMatch, iend);
346
407
  if (curForwardMatchLength < minMatchLength) {
347
408
  continue;
348
409
  }
349
410
  curBackwardMatchLength =
350
- ZSTD_ldm_countBackwardsMatch(ip, anchor, pMatch,
351
- lowPrefixPtr);
352
- curTotalMatchLength = curForwardMatchLength +
353
- curBackwardMatchLength;
411
+ ZSTD_ldm_countBackwardsMatch(split, anchor, pMatch, lowPrefixPtr);
354
412
  }
413
+ curTotalMatchLength = curForwardMatchLength + curBackwardMatchLength;
355
414
 
356
415
  if (curTotalMatchLength > bestMatchLength) {
357
416
  bestMatchLength = curTotalMatchLength;
@@ -360,57 +419,39 @@ static size_t ZSTD_ldm_generateSequences_internal(
360
419
  bestEntry = cur;
361
420
  }
362
421
  }
363
- }
364
-
365
- /* No match found -- continue searching */
366
- if (bestEntry == NULL) {
367
- ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash,
368
- hBits, current,
369
- *params);
370
- ip++;
371
- continue;
372
- }
373
-
374
- /* Match found */
375
- mLength = forwardMatchLength + backwardMatchLength;
376
- ip -= backwardMatchLength;
377
422
 
378
- {
379
- /* Store the sequence:
380
- * ip = current - backwardMatchLength
381
- * The match is at (bestEntry->offset - backwardMatchLength)
382
- */
383
- U32 const matchIndex = bestEntry->offset;
384
- U32 const offset = current - matchIndex;
385
- rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size;
386
-
387
- /* Out of sequence storage */
388
- if (rawSeqStore->size == rawSeqStore->capacity)
389
- return ERROR(dstSize_tooSmall);
390
- seq->litLength = (U32)(ip - anchor);
391
- seq->matchLength = (U32)mLength;
392
- seq->offset = offset;
393
- rawSeqStore->size++;
394
- }
423
+ /* No match found -- insert an entry into the hash table
424
+ * and process the next candidate match */
425
+ if (bestEntry == NULL) {
426
+ ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
427
+ continue;
428
+ }
395
429
 
396
- /* Insert the current entry into the hash table */
397
- ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits,
398
- (U32)(lastHashed - base),
399
- *params);
430
+ /* Match found */
431
+ mLength = forwardMatchLength + backwardMatchLength;
432
+ {
433
+ U32 const offset = (U32)(split - base) - bestEntry->offset;
434
+ rawSeq* const seq = rawSeqStore->seq + rawSeqStore->size;
435
+
436
+ /* Out of sequence storage */
437
+ if (rawSeqStore->size == rawSeqStore->capacity)
438
+ return ERROR(dstSize_tooSmall);
439
+ seq->litLength = (U32)(split - backwardMatchLength - anchor);
440
+ seq->matchLength = (U32)mLength;
441
+ seq->offset = offset;
442
+ rawSeqStore->size++;
443
+ }
400
444
 
401
- assert(ip + backwardMatchLength == lastHashed);
445
+ /* Insert the current entry into the hash table --- it must be
446
+ * done after the previous block to avoid clobbering bestEntry */
447
+ ZSTD_ldm_insertEntry(ldmState, hash, newEntry, *params);
402
448
 
403
- /* Fill the hash table from lastHashed+1 to ip+mLength*/
404
- /* Heuristic: don't need to fill the entire table at end of block */
405
- if (ip + mLength <= ilimit) {
406
- rollingHash = ZSTD_ldm_fillLdmHashTable(
407
- ldmState, rollingHash, lastHashed,
408
- ip + mLength, base, hBits, *params);
409
- lastHashed = ip + mLength - 1;
449
+ anchor = split + forwardMatchLength;
410
450
  }
411
- ip += mLength;
412
- anchor = ip;
451
+
452
+ ip += hashed;
413
453
  }
454
+
414
455
  return iend - anchor;
415
456
  }
416
457
 
@@ -562,6 +603,23 @@ static rawSeq maybeSplitSequence(rawSeqStore_t* rawSeqStore,
562
603
  return sequence;
563
604
  }
564
605
 
606
+ void ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore_t* rawSeqStore, size_t nbBytes) {
607
+ U32 currPos = (U32)(rawSeqStore->posInSequence + nbBytes);
608
+ while (currPos && rawSeqStore->pos < rawSeqStore->size) {
609
+ rawSeq currSeq = rawSeqStore->seq[rawSeqStore->pos];
610
+ if (currPos >= currSeq.litLength + currSeq.matchLength) {
611
+ currPos -= currSeq.litLength + currSeq.matchLength;
612
+ rawSeqStore->pos++;
613
+ } else {
614
+ rawSeqStore->posInSequence = currPos;
615
+ break;
616
+ }
617
+ }
618
+ if (currPos == 0 || rawSeqStore->pos == rawSeqStore->size) {
619
+ rawSeqStore->posInSequence = 0;
620
+ }
621
+ }
622
+
565
623
  size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
566
624
  ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM],
567
625
  void const* src, size_t srcSize)
@@ -577,9 +635,18 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
577
635
  BYTE const* ip = istart;
578
636
 
579
637
  DEBUGLOG(5, "ZSTD_ldm_blockCompress: srcSize=%zu", srcSize);
638
+ /* If using opt parser, use LDMs only as candidates rather than always accepting them */
639
+ if (cParams->strategy >= ZSTD_btopt) {
640
+ size_t lastLLSize;
641
+ ms->ldmSeqStore = rawSeqStore;
642
+ lastLLSize = blockCompressor(ms, seqStore, rep, src, srcSize);
643
+ ZSTD_ldm_skipRawSeqStoreBytes(rawSeqStore, srcSize);
644
+ return lastLLSize;
645
+ }
646
+
580
647
  assert(rawSeqStore->pos <= rawSeqStore->size);
581
648
  assert(rawSeqStore->size <= rawSeqStore->capacity);
582
- /* Loop through each sequence and apply the block compressor to the lits */
649
+ /* Loop through each sequence and apply the block compressor to the literals */
583
650
  while (rawSeqStore->pos < rawSeqStore->size && ip < iend) {
584
651
  /* maybeSplitSequence updates rawSeqStore->pos */
585
652
  rawSeq const sequence = maybeSplitSequence(rawSeqStore,