zstd-ruby 1.4.5.0 → 1.4.9.0

Sign up to get free protection for your applications and to get access to all the features.
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,