brotli 0.2.3 → 0.5.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 (124) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +37 -0
  3. data/.github/workflows/publish.yml +24 -0
  4. data/.gitmodules +1 -1
  5. data/Gemfile +6 -3
  6. data/README.md +2 -2
  7. data/Rakefile +16 -9
  8. data/brotli.gemspec +7 -13
  9. data/ext/brotli/brotli.c +210 -31
  10. data/ext/brotli/buffer.c +1 -7
  11. data/ext/brotli/buffer.h +1 -1
  12. data/ext/brotli/extconf.rb +25 -17
  13. data/lib/brotli/version.rb +1 -1
  14. data/test/brotli_test.rb +107 -0
  15. data/test/brotli_writer_test.rb +36 -0
  16. data/test/test_helper.rb +8 -0
  17. data/vendor/brotli/c/common/constants.c +15 -0
  18. data/vendor/brotli/c/common/constants.h +137 -0
  19. data/vendor/brotli/c/common/context.c +156 -0
  20. data/vendor/brotli/c/common/context.h +4 -152
  21. data/vendor/brotli/c/common/dictionary.bin.br +0 -0
  22. data/vendor/brotli/c/common/dictionary.c +14 -3
  23. data/vendor/brotli/c/common/platform.c +23 -0
  24. data/vendor/brotli/c/common/platform.h +95 -122
  25. data/vendor/brotli/c/common/shared_dictionary.c +521 -0
  26. data/vendor/brotli/c/common/shared_dictionary_internal.h +75 -0
  27. data/vendor/brotli/c/common/transform.c +60 -4
  28. data/vendor/brotli/c/common/transform.h +5 -0
  29. data/vendor/brotli/c/common/version.h +31 -6
  30. data/vendor/brotli/c/dec/bit_reader.c +34 -4
  31. data/vendor/brotli/c/dec/bit_reader.h +221 -107
  32. data/vendor/brotli/c/dec/decode.c +772 -403
  33. data/vendor/brotli/c/dec/huffman.c +7 -4
  34. data/vendor/brotli/c/dec/huffman.h +8 -13
  35. data/vendor/brotli/c/dec/prefix.h +1 -18
  36. data/vendor/brotli/c/dec/state.c +40 -21
  37. data/vendor/brotli/c/dec/state.h +201 -59
  38. data/vendor/brotli/c/enc/backward_references.c +88 -25
  39. data/vendor/brotli/c/enc/backward_references.h +10 -8
  40. data/vendor/brotli/c/enc/backward_references_hq.c +194 -80
  41. data/vendor/brotli/c/enc/backward_references_hq.h +17 -13
  42. data/vendor/brotli/c/enc/backward_references_inc.h +52 -16
  43. data/vendor/brotli/c/enc/bit_cost.c +8 -7
  44. data/vendor/brotli/c/enc/bit_cost.h +5 -4
  45. data/vendor/brotli/c/enc/block_splitter.c +40 -17
  46. data/vendor/brotli/c/enc/block_splitter.h +5 -4
  47. data/vendor/brotli/c/enc/block_splitter_inc.h +99 -49
  48. data/vendor/brotli/c/enc/brotli_bit_stream.c +142 -137
  49. data/vendor/brotli/c/enc/brotli_bit_stream.h +11 -6
  50. data/vendor/brotli/c/enc/cluster.c +10 -9
  51. data/vendor/brotli/c/enc/cluster.h +7 -6
  52. data/vendor/brotli/c/enc/cluster_inc.h +30 -22
  53. data/vendor/brotli/c/enc/command.c +28 -0
  54. data/vendor/brotli/c/enc/command.h +17 -16
  55. data/vendor/brotli/c/enc/compound_dictionary.c +207 -0
  56. data/vendor/brotli/c/enc/compound_dictionary.h +74 -0
  57. data/vendor/brotli/c/enc/compress_fragment.c +93 -83
  58. data/vendor/brotli/c/enc/compress_fragment.h +32 -7
  59. data/vendor/brotli/c/enc/compress_fragment_two_pass.c +100 -88
  60. data/vendor/brotli/c/enc/compress_fragment_two_pass.h +21 -3
  61. data/vendor/brotli/c/enc/dictionary_hash.c +1829 -1101
  62. data/vendor/brotli/c/enc/dictionary_hash.h +2 -1
  63. data/vendor/brotli/c/enc/encode.c +550 -416
  64. data/vendor/brotli/c/enc/encoder_dict.c +613 -5
  65. data/vendor/brotli/c/enc/encoder_dict.h +120 -4
  66. data/vendor/brotli/c/enc/entropy_encode.c +5 -2
  67. data/vendor/brotli/c/enc/entropy_encode.h +4 -3
  68. data/vendor/brotli/c/enc/entropy_encode_static.h +5 -2
  69. data/vendor/brotli/c/enc/fast_log.c +105 -0
  70. data/vendor/brotli/c/enc/fast_log.h +21 -101
  71. data/vendor/brotli/c/enc/find_match_length.h +17 -25
  72. data/vendor/brotli/c/enc/hash.h +350 -120
  73. data/vendor/brotli/c/enc/hash_composite_inc.h +71 -67
  74. data/vendor/brotli/c/enc/hash_forgetful_chain_inc.h +92 -51
  75. data/vendor/brotli/c/enc/hash_longest_match64_inc.h +79 -84
  76. data/vendor/brotli/c/enc/hash_longest_match_inc.h +53 -54
  77. data/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h +93 -62
  78. data/vendor/brotli/c/enc/hash_rolling_inc.h +25 -29
  79. data/vendor/brotli/c/enc/hash_to_binary_tree_inc.h +42 -40
  80. data/vendor/brotli/c/enc/histogram.c +4 -4
  81. data/vendor/brotli/c/enc/histogram.h +7 -6
  82. data/vendor/brotli/c/enc/literal_cost.c +20 -15
  83. data/vendor/brotli/c/enc/literal_cost.h +4 -2
  84. data/vendor/brotli/c/enc/memory.c +29 -5
  85. data/vendor/brotli/c/enc/memory.h +43 -14
  86. data/vendor/brotli/c/enc/metablock.c +95 -85
  87. data/vendor/brotli/c/enc/metablock.h +9 -8
  88. data/vendor/brotli/c/enc/metablock_inc.h +9 -7
  89. data/vendor/brotli/c/enc/params.h +7 -4
  90. data/vendor/brotli/c/enc/prefix.h +3 -2
  91. data/vendor/brotli/c/enc/quality.h +40 -3
  92. data/vendor/brotli/c/enc/ringbuffer.h +8 -4
  93. data/vendor/brotli/c/enc/state.h +104 -0
  94. data/vendor/brotli/c/enc/static_dict.c +60 -4
  95. data/vendor/brotli/c/enc/static_dict.h +3 -2
  96. data/vendor/brotli/c/enc/static_dict_lut.h +2 -0
  97. data/vendor/brotli/c/enc/utf8_util.c +2 -2
  98. data/vendor/brotli/c/enc/utf8_util.h +2 -1
  99. data/vendor/brotli/c/enc/write_bits.h +29 -26
  100. data/vendor/brotli/c/include/brotli/decode.h +67 -2
  101. data/vendor/brotli/c/include/brotli/encode.h +77 -3
  102. data/vendor/brotli/c/include/brotli/port.h +34 -3
  103. data/vendor/brotli/c/include/brotli/shared_dictionary.h +100 -0
  104. metadata +23 -97
  105. data/.travis.yml +0 -31
  106. data/docs/Brotli/Error.html +0 -124
  107. data/docs/Brotli.html +0 -485
  108. data/docs/_index.html +0 -122
  109. data/docs/class_list.html +0 -51
  110. data/docs/css/common.css +0 -1
  111. data/docs/css/full_list.css +0 -58
  112. data/docs/css/style.css +0 -496
  113. data/docs/file.README.html +0 -127
  114. data/docs/file_list.html +0 -56
  115. data/docs/frames.html +0 -17
  116. data/docs/index.html +0 -127
  117. data/docs/js/app.js +0 -292
  118. data/docs/js/full_list.js +0 -216
  119. data/docs/js/jquery.js +0 -4
  120. data/docs/method_list.html +0 -67
  121. data/docs/top-level-namespace.html +0 -110
  122. data/spec/brotli_spec.rb +0 -88
  123. data/spec/inflate_spec.rb +0 -75
  124. data/spec/spec_helper.rb +0 -4
@@ -10,50 +10,51 @@
10
10
  #ifndef BROTLI_ENC_HASH_H_
11
11
  #define BROTLI_ENC_HASH_H_
12
12
 
13
+ #include <stdlib.h> /* exit */
13
14
  #include <string.h> /* memcmp, memset */
14
15
 
16
+ #include <brotli/types.h>
17
+
15
18
  #include "../common/constants.h"
16
19
  #include "../common/dictionary.h"
17
20
  #include "../common/platform.h"
18
- #include <brotli/types.h>
19
- #include "./encoder_dict.h"
20
- #include "./fast_log.h"
21
- #include "./find_match_length.h"
22
- #include "./memory.h"
23
- #include "./quality.h"
24
- #include "./static_dict.h"
21
+ #include "compound_dictionary.h"
22
+ #include "encoder_dict.h"
23
+ #include "fast_log.h"
24
+ #include "find_match_length.h"
25
+ #include "memory.h"
26
+ #include "quality.h"
27
+ #include "static_dict.h"
25
28
 
26
29
  #if defined(__cplusplus) || defined(c_plusplus)
27
30
  extern "C" {
28
31
  #endif
29
32
 
30
- /* Pointer to hasher data.
31
- *
32
- * Excluding initialization and destruction, hasher can be passed as
33
- * HasherHandle by value.
34
- *
35
- * Typically hasher data consists of 3 sections:
36
- * * HasherCommon structure
37
- * * private structured hasher data, depending on hasher type
38
- * * private dynamic hasher data, depending on hasher type and parameters
39
- *
40
- * Using "define" instead of "typedef", because on MSVC __restrict does not work
41
- * on typedef pointer types. */
42
- #define HasherHandle uint8_t*
43
-
44
33
  typedef struct {
45
- BrotliHasherParams params;
46
-
47
- /* False if hasher needs to be "prepared" before use. */
48
- BROTLI_BOOL is_prepared_;
34
+ /**
35
+ * Dynamically allocated areas; regular hasher uses one or two allocations;
36
+ * "composite" hasher uses up to 4 allocations.
37
+ */
38
+ void* extra[4];
39
+
40
+ /**
41
+ * False before the fisrt invocation of HasherSetup (where "extra" memory)
42
+ * is allocated.
43
+ */
44
+ BROTLI_BOOL is_setup_;
49
45
 
50
46
  size_t dict_num_lookups;
51
47
  size_t dict_num_matches;
52
- } HasherCommon;
53
48
 
54
- static BROTLI_INLINE HasherCommon* GetHasherCommon(HasherHandle handle) {
55
- return (HasherCommon*)handle;
56
- }
49
+ BrotliHasherParams params;
50
+
51
+ /**
52
+ * False if hasher needs to be "prepared" before use (before the first
53
+ * invocation of HasherSetup or after HasherReset). "preparation" is hasher
54
+ * data initialization (using input ringbuffer).
55
+ */
56
+ BROTLI_BOOL is_prepared_;
57
+ } HasherCommon;
57
58
 
58
59
  #define score_t size_t
59
60
 
@@ -77,8 +78,7 @@ typedef struct HasherSearchResult {
77
78
  for this use.
78
79
  * The number has been tuned heuristically against compression benchmarks. */
79
80
  static const uint32_t kHashMul32 = 0x1E35A7BD;
80
- static const uint64_t kHashMul64 = BROTLI_MAKE_UINT64_T(0x1E35A7BD, 0x1E35A7BD);
81
- static const uint64_t kHashMul64Long =
81
+ static const uint64_t kHashMul64 =
82
82
  BROTLI_MAKE_UINT64_T(0x1FE35A7Bu, 0xD3579BD3u);
83
83
 
84
84
  static BROTLI_INLINE uint32_t Hash14(const uint8_t* data) {
@@ -149,17 +149,13 @@ static BROTLI_INLINE score_t BackwardReferencePenaltyUsingLastDistance(
149
149
  }
150
150
 
151
151
  static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(
152
- const BrotliEncoderDictionary* dictionary, size_t item,
152
+ const BrotliEncoderDictionary* dictionary, size_t len, size_t word_idx,
153
153
  const uint8_t* data, size_t max_length, size_t max_backward,
154
154
  size_t max_distance, HasherSearchResult* out) {
155
- size_t len;
156
- size_t word_idx;
157
155
  size_t offset;
158
156
  size_t matchlen;
159
157
  size_t backward;
160
158
  score_t score;
161
- len = item & 0x1F;
162
- word_idx = item >> 5;
163
159
  offset = dictionary->words->offsets_by_length[len] + len * word_idx;
164
160
  if (len > max_length) {
165
161
  return BROTLI_FALSE;
@@ -193,25 +189,24 @@ static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(
193
189
 
194
190
  static BROTLI_INLINE void SearchInStaticDictionary(
195
191
  const BrotliEncoderDictionary* dictionary,
196
- HasherHandle handle, const uint8_t* data, size_t max_length,
192
+ HasherCommon* common, const uint8_t* data, size_t max_length,
197
193
  size_t max_backward, size_t max_distance,
198
194
  HasherSearchResult* out, BROTLI_BOOL shallow) {
199
195
  size_t key;
200
196
  size_t i;
201
- HasherCommon* self = GetHasherCommon(handle);
202
- if (self->dict_num_matches < (self->dict_num_lookups >> 7)) {
197
+ if (common->dict_num_matches < (common->dict_num_lookups >> 7)) {
203
198
  return;
204
199
  }
205
200
  key = Hash14(data) << 1;
206
201
  for (i = 0; i < (shallow ? 1u : 2u); ++i, ++key) {
207
- size_t item = dictionary->hash_table[key];
208
- self->dict_num_lookups++;
209
- if (item != 0) {
202
+ common->dict_num_lookups++;
203
+ if (dictionary->hash_table_lengths[key] != 0) {
210
204
  BROTLI_BOOL item_matches = TestStaticDictionaryItem(
211
- dictionary, item, data,
205
+ dictionary, dictionary->hash_table_lengths[key],
206
+ dictionary->hash_table_words[key], data,
212
207
  max_length, max_backward, max_distance, out);
213
208
  if (item_matches) {
214
- self->dict_num_matches++;
209
+ common->dict_num_matches++;
215
210
  }
216
211
  }
217
212
  }
@@ -252,7 +247,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
252
247
  #define BUCKET_BITS 17
253
248
  #define MAX_TREE_SEARCH_DEPTH 64
254
249
  #define MAX_TREE_COMP_LENGTH 128
255
- #include "./hash_to_binary_tree_inc.h" /* NOLINT(build/include) */
250
+ #include "hash_to_binary_tree_inc.h" /* NOLINT(build/include) */
256
251
  #undef MAX_TREE_SEARCH_DEPTH
257
252
  #undef MAX_TREE_COMP_LENGTH
258
253
  #undef BUCKET_BITS
@@ -260,46 +255,46 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
260
255
  /* MAX_NUM_MATCHES == 64 + MAX_TREE_SEARCH_DEPTH */
261
256
  #define MAX_NUM_MATCHES_H10 128
262
257
 
263
- /* For BUCKET_SWEEP == 1, enabling the dictionary lookup makes compression
258
+ /* For BUCKET_SWEEP_BITS == 0, enabling the dictionary lookup makes compression
264
259
  a little faster (0.5% - 1%) and it compresses 0.15% better on small text
265
260
  and HTML inputs. */
266
261
 
267
262
  #define HASHER() H2
268
263
  #define BUCKET_BITS 16
269
- #define BUCKET_SWEEP 1
264
+ #define BUCKET_SWEEP_BITS 0
270
265
  #define HASH_LEN 5
271
266
  #define USE_DICTIONARY 1
272
- #include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
273
- #undef BUCKET_SWEEP
267
+ #include "hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
268
+ #undef BUCKET_SWEEP_BITS
274
269
  #undef USE_DICTIONARY
275
270
  #undef HASHER
276
271
 
277
272
  #define HASHER() H3
278
- #define BUCKET_SWEEP 2
273
+ #define BUCKET_SWEEP_BITS 1
279
274
  #define USE_DICTIONARY 0
280
- #include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
275
+ #include "hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
281
276
  #undef USE_DICTIONARY
282
- #undef BUCKET_SWEEP
277
+ #undef BUCKET_SWEEP_BITS
283
278
  #undef BUCKET_BITS
284
279
  #undef HASHER
285
280
 
286
281
  #define HASHER() H4
287
282
  #define BUCKET_BITS 17
288
- #define BUCKET_SWEEP 4
283
+ #define BUCKET_SWEEP_BITS 2
289
284
  #define USE_DICTIONARY 1
290
- #include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
285
+ #include "hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
291
286
  #undef USE_DICTIONARY
292
287
  #undef HASH_LEN
293
- #undef BUCKET_SWEEP
288
+ #undef BUCKET_SWEEP_BITS
294
289
  #undef BUCKET_BITS
295
290
  #undef HASHER
296
291
 
297
292
  #define HASHER() H5
298
- #include "./hash_longest_match_inc.h" /* NOLINT(build/include) */
293
+ #include "hash_longest_match_inc.h" /* NOLINT(build/include) */
299
294
  #undef HASHER
300
295
 
301
296
  #define HASHER() H6
302
- #include "./hash_longest_match64_inc.h" /* NOLINT(build/include) */
297
+ #include "hash_longest_match64_inc.h" /* NOLINT(build/include) */
303
298
  #undef HASHER
304
299
 
305
300
  #define BUCKET_BITS 15
@@ -308,13 +303,13 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
308
303
  #define NUM_BANKS 1
309
304
  #define BANK_BITS 16
310
305
  #define HASHER() H40
311
- #include "./hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
306
+ #include "hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
312
307
  #undef HASHER
313
308
  #undef NUM_LAST_DISTANCES_TO_CHECK
314
309
 
315
310
  #define NUM_LAST_DISTANCES_TO_CHECK 10
316
311
  #define HASHER() H41
317
- #include "./hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
312
+ #include "hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
318
313
  #undef HASHER
319
314
  #undef NUM_LAST_DISTANCES_TO_CHECK
320
315
  #undef NUM_BANKS
@@ -324,7 +319,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
324
319
  #define NUM_BANKS 512
325
320
  #define BANK_BITS 9
326
321
  #define HASHER() H42
327
- #include "./hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
322
+ #include "hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
328
323
  #undef HASHER
329
324
  #undef NUM_LAST_DISTANCES_TO_CHECK
330
325
  #undef NUM_BANKS
@@ -334,13 +329,13 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
334
329
 
335
330
  #define HASHER() H54
336
331
  #define BUCKET_BITS 20
337
- #define BUCKET_SWEEP 4
332
+ #define BUCKET_SWEEP_BITS 2
338
333
  #define HASH_LEN 7
339
334
  #define USE_DICTIONARY 0
340
- #include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
335
+ #include "hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
341
336
  #undef USE_DICTIONARY
342
337
  #undef HASH_LEN
343
- #undef BUCKET_SWEEP
338
+ #undef BUCKET_SWEEP_BITS
344
339
  #undef BUCKET_BITS
345
340
  #undef HASHER
346
341
 
@@ -351,14 +346,14 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
351
346
  #define JUMP 4
352
347
  #define NUMBUCKETS 16777216
353
348
  #define MASK ((NUMBUCKETS * 64) - 1)
354
- #include "./hash_rolling_inc.h" /* NOLINT(build/include) */
349
+ #include "hash_rolling_inc.h" /* NOLINT(build/include) */
355
350
  #undef JUMP
356
351
  #undef HASHER
357
352
 
358
353
 
359
354
  #define HASHER() HROLLING
360
355
  #define JUMP 1
361
- #include "./hash_rolling_inc.h" /* NOLINT(build/include) */
356
+ #include "hash_rolling_inc.h" /* NOLINT(build/include) */
362
357
  #undef MASK
363
358
  #undef NUMBUCKETS
364
359
  #undef JUMP
@@ -368,7 +363,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
368
363
  #define HASHER() H35
369
364
  #define HASHER_A H3
370
365
  #define HASHER_B HROLLING_FAST
371
- #include "./hash_composite_inc.h" /* NOLINT(build/include) */
366
+ #include "hash_composite_inc.h" /* NOLINT(build/include) */
372
367
  #undef HASHER_A
373
368
  #undef HASHER_B
374
369
  #undef HASHER
@@ -376,7 +371,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
376
371
  #define HASHER() H55
377
372
  #define HASHER_A H54
378
373
  #define HASHER_B HROLLING_FAST
379
- #include "./hash_composite_inc.h" /* NOLINT(build/include) */
374
+ #include "hash_composite_inc.h" /* NOLINT(build/include) */
380
375
  #undef HASHER_A
381
376
  #undef HASHER_B
382
377
  #undef HASHER
@@ -384,7 +379,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
384
379
  #define HASHER() H65
385
380
  #define HASHER_A H6
386
381
  #define HASHER_B HROLLING
387
- #include "./hash_composite_inc.h" /* NOLINT(build/include) */
382
+ #include "hash_composite_inc.h" /* NOLINT(build/include) */
388
383
  #undef HASHER_A
389
384
  #undef HASHER_B
390
385
  #undef HASHER
@@ -393,97 +388,116 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
393
388
  #undef CAT
394
389
  #undef EXPAND_CAT
395
390
 
396
- #define FOR_GENERIC_HASHERS(H) H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54)\
397
- H(35) H(55) H(65)
391
+ #define FOR_SIMPLE_HASHERS(H) H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54)
392
+ #define FOR_COMPOSITE_HASHERS(H) H(35) H(55) H(65)
393
+ #define FOR_GENERIC_HASHERS(H) FOR_SIMPLE_HASHERS(H) FOR_COMPOSITE_HASHERS(H)
398
394
  #define FOR_ALL_HASHERS(H) FOR_GENERIC_HASHERS(H) H(10)
399
395
 
400
- static BROTLI_INLINE void DestroyHasher(
401
- MemoryManager* m, HasherHandle* handle) {
402
- if (*handle == NULL) return;
403
- BROTLI_FREE(m, *handle);
396
+ typedef struct {
397
+ HasherCommon common;
398
+
399
+ union {
400
+ #define MEMBER_(N) \
401
+ H ## N _H ## N;
402
+ FOR_ALL_HASHERS(MEMBER_)
403
+ #undef MEMBER_
404
+ } privat;
405
+ } Hasher;
406
+
407
+ /* MUST be invoked before any other method. */
408
+ static BROTLI_INLINE void HasherInit(Hasher* hasher) {
409
+ hasher->common.is_setup_ = BROTLI_FALSE;
410
+ hasher->common.extra[0] = NULL;
411
+ hasher->common.extra[1] = NULL;
412
+ hasher->common.extra[2] = NULL;
413
+ hasher->common.extra[3] = NULL;
414
+ }
415
+
416
+ static BROTLI_INLINE void DestroyHasher(MemoryManager* m, Hasher* hasher) {
417
+ if (hasher->common.extra[0] != NULL) BROTLI_FREE(m, hasher->common.extra[0]);
418
+ if (hasher->common.extra[1] != NULL) BROTLI_FREE(m, hasher->common.extra[1]);
419
+ if (hasher->common.extra[2] != NULL) BROTLI_FREE(m, hasher->common.extra[2]);
420
+ if (hasher->common.extra[3] != NULL) BROTLI_FREE(m, hasher->common.extra[3]);
404
421
  }
405
422
 
406
- static BROTLI_INLINE void HasherReset(HasherHandle handle) {
407
- if (handle == NULL) return;
408
- GetHasherCommon(handle)->is_prepared_ = BROTLI_FALSE;
423
+ static BROTLI_INLINE void HasherReset(Hasher* hasher) {
424
+ hasher->common.is_prepared_ = BROTLI_FALSE;
409
425
  }
410
426
 
411
- static BROTLI_INLINE size_t HasherSize(const BrotliEncoderParams* params,
412
- BROTLI_BOOL one_shot, const size_t input_size) {
413
- size_t result = sizeof(HasherCommon);
427
+ static BROTLI_INLINE void HasherSize(const BrotliEncoderParams* params,
428
+ BROTLI_BOOL one_shot, const size_t input_size, size_t* alloc_size) {
414
429
  switch (params->hasher.type) {
415
- #define SIZE_(N) \
416
- case N: \
417
- result += HashMemAllocInBytesH ## N(params, one_shot, input_size); \
430
+ #define SIZE_(N) \
431
+ case N: \
432
+ HashMemAllocInBytesH ## N(params, one_shot, input_size, alloc_size); \
418
433
  break;
419
434
  FOR_ALL_HASHERS(SIZE_)
420
435
  #undef SIZE_
421
436
  default:
422
437
  break;
423
438
  }
424
- return result;
425
439
  }
426
440
 
427
- static BROTLI_INLINE void HasherSetup(MemoryManager* m, HasherHandle* handle,
441
+ static BROTLI_INLINE void HasherSetup(MemoryManager* m, Hasher* hasher,
428
442
  BrotliEncoderParams* params, const uint8_t* data, size_t position,
429
443
  size_t input_size, BROTLI_BOOL is_last) {
430
- HasherHandle self = NULL;
431
- HasherCommon* common = NULL;
432
444
  BROTLI_BOOL one_shot = (position == 0 && is_last);
433
- if (*handle == NULL) {
434
- size_t alloc_size;
445
+ if (!hasher->common.is_setup_) {
446
+ size_t alloc_size[4] = {0};
447
+ size_t i;
435
448
  ChooseHasher(params, &params->hasher);
436
- alloc_size = HasherSize(params, one_shot, input_size);
437
- self = BROTLI_ALLOC(m, uint8_t, alloc_size);
438
- if (BROTLI_IS_OOM(m)) return;
439
- *handle = self;
440
- common = GetHasherCommon(self);
441
- common->params = params->hasher;
442
- switch (common->params.type) {
443
- #define INITIALIZE_(N) \
444
- case N: \
445
- InitializeH ## N(*handle, params); \
449
+ hasher->common.params = params->hasher;
450
+ hasher->common.dict_num_lookups = 0;
451
+ hasher->common.dict_num_matches = 0;
452
+ HasherSize(params, one_shot, input_size, alloc_size);
453
+ for (i = 0; i < 4; ++i) {
454
+ if (alloc_size[i] == 0) continue;
455
+ hasher->common.extra[i] = BROTLI_ALLOC(m, uint8_t, alloc_size[i]);
456
+ if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(hasher->common.extra[i])) return;
457
+ }
458
+ switch (hasher->common.params.type) {
459
+ #define INITIALIZE_(N) \
460
+ case N: \
461
+ InitializeH ## N(&hasher->common, \
462
+ &hasher->privat._H ## N, params); \
446
463
  break;
447
464
  FOR_ALL_HASHERS(INITIALIZE_);
448
465
  #undef INITIALIZE_
449
466
  default:
450
467
  break;
451
468
  }
452
- HasherReset(*handle);
469
+ HasherReset(hasher);
470
+ hasher->common.is_setup_ = BROTLI_TRUE;
453
471
  }
454
472
 
455
- self = *handle;
456
- common = GetHasherCommon(self);
457
- if (!common->is_prepared_) {
458
- switch (common->params.type) {
459
- #define PREPARE_(N) \
460
- case N: \
461
- PrepareH ## N(self, one_shot, input_size, data); \
473
+ if (!hasher->common.is_prepared_) {
474
+ switch (hasher->common.params.type) {
475
+ #define PREPARE_(N) \
476
+ case N: \
477
+ PrepareH ## N( \
478
+ &hasher->privat._H ## N, \
479
+ one_shot, input_size, data); \
462
480
  break;
463
481
  FOR_ALL_HASHERS(PREPARE_)
464
482
  #undef PREPARE_
465
483
  default: break;
466
484
  }
467
- if (position == 0) {
468
- common->dict_num_lookups = 0;
469
- common->dict_num_matches = 0;
470
- }
471
- common->is_prepared_ = BROTLI_TRUE;
485
+ hasher->common.is_prepared_ = BROTLI_TRUE;
472
486
  }
473
487
  }
474
488
 
475
489
  static BROTLI_INLINE void InitOrStitchToPreviousBlock(
476
- MemoryManager* m, HasherHandle* handle, const uint8_t* data, size_t mask,
490
+ MemoryManager* m, Hasher* hasher, const uint8_t* data, size_t mask,
477
491
  BrotliEncoderParams* params, size_t position, size_t input_size,
478
492
  BROTLI_BOOL is_last) {
479
- HasherHandle self;
480
- HasherSetup(m, handle, params, data, position, input_size, is_last);
493
+ HasherSetup(m, hasher, params, data, position, input_size, is_last);
481
494
  if (BROTLI_IS_OOM(m)) return;
482
- self = *handle;
483
- switch (GetHasherCommon(self)->params.type) {
484
- #define INIT_(N) \
485
- case N: \
486
- StitchToPreviousBlockH ## N(self, input_size, position, data, mask); \
495
+ switch (hasher->common.params.type) {
496
+ #define INIT_(N) \
497
+ case N: \
498
+ StitchToPreviousBlockH ## N( \
499
+ &hasher->privat._H ## N, \
500
+ input_size, position, data, mask); \
487
501
  break;
488
502
  FOR_ALL_HASHERS(INIT_)
489
503
  #undef INIT_
@@ -491,6 +505,222 @@ static BROTLI_INLINE void InitOrStitchToPreviousBlock(
491
505
  }
492
506
  }
493
507
 
508
+ /* NB: when seamless dictionary-ring-buffer copies are implemented, don't forget
509
+ to add proper guards for non-zero-BROTLI_PARAM_STREAM_OFFSET. */
510
+ static BROTLI_INLINE void FindCompoundDictionaryMatch(
511
+ const PreparedDictionary* self, const uint8_t* BROTLI_RESTRICT data,
512
+ const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache,
513
+ const size_t cur_ix, const size_t max_length, const size_t distance_offset,
514
+ const size_t max_distance, HasherSearchResult* BROTLI_RESTRICT out) {
515
+ const uint32_t source_size = self->source_size;
516
+ const size_t boundary = distance_offset - source_size;
517
+ const uint32_t hash_bits = self->hash_bits;
518
+ const uint32_t bucket_bits = self->bucket_bits;
519
+ const uint32_t slot_bits = self->slot_bits;
520
+
521
+ const uint32_t hash_shift = 64u - bucket_bits;
522
+ const uint32_t slot_mask = (~((uint32_t)0U)) >> (32 - slot_bits);
523
+ const uint64_t hash_mask = (~((uint64_t)0U)) >> (64 - hash_bits);
524
+
525
+ const uint32_t* slot_offsets = (uint32_t*)(&self[1]);
526
+ const uint16_t* heads = (uint16_t*)(&slot_offsets[1u << slot_bits]);
527
+ const uint32_t* items = (uint32_t*)(&heads[1u << bucket_bits]);
528
+ const uint8_t* source = NULL;
529
+
530
+ const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
531
+ score_t best_score = out->score;
532
+ size_t best_len = out->len;
533
+ size_t i;
534
+ const uint64_t h =
535
+ (BROTLI_UNALIGNED_LOAD64LE(&data[cur_ix_masked]) & hash_mask) *
536
+ kPreparedDictionaryHashMul64Long;
537
+ const uint32_t key = (uint32_t)(h >> hash_shift);
538
+ const uint32_t slot = key & slot_mask;
539
+ const uint32_t head = heads[key];
540
+ const uint32_t* BROTLI_RESTRICT chain = &items[slot_offsets[slot] + head];
541
+ uint32_t item = (head == 0xFFFF) ? 1 : 0;
542
+
543
+ const void* tail = (void*)&items[self->num_items];
544
+ if (self->magic == kPreparedDictionaryMagic) {
545
+ source = (const uint8_t*)tail;
546
+ } else {
547
+ /* kLeanPreparedDictionaryMagic */
548
+ source = (const uint8_t*)BROTLI_UNALIGNED_LOAD_PTR((const uint8_t**)tail);
549
+ }
550
+
551
+ for (i = 0; i < 4; ++i) {
552
+ const size_t distance = (size_t)distance_cache[i];
553
+ size_t offset;
554
+ size_t limit;
555
+ size_t len;
556
+ if (distance <= boundary || distance > distance_offset) continue;
557
+ offset = distance_offset - distance;
558
+ limit = source_size - offset;
559
+ limit = limit > max_length ? max_length : limit;
560
+ len = FindMatchLengthWithLimit(&source[offset], &data[cur_ix_masked],
561
+ limit);
562
+ if (len >= 2) {
563
+ score_t score = BackwardReferenceScoreUsingLastDistance(len);
564
+ if (best_score < score) {
565
+ if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i);
566
+ if (best_score < score) {
567
+ best_score = score;
568
+ if (len > best_len) best_len = len;
569
+ out->len = len;
570
+ out->len_code_delta = 0;
571
+ out->distance = distance;
572
+ out->score = best_score;
573
+ }
574
+ }
575
+ }
576
+ }
577
+ while (item == 0) {
578
+ size_t offset;
579
+ size_t distance;
580
+ size_t limit;
581
+ item = *chain;
582
+ chain++;
583
+ offset = item & 0x7FFFFFFF;
584
+ item &= 0x80000000;
585
+ distance = distance_offset - offset;
586
+ limit = source_size - offset;
587
+ limit = (limit > max_length) ? max_length : limit;
588
+ if (distance > max_distance) continue;
589
+ if (cur_ix_masked + best_len > ring_buffer_mask ||
590
+ best_len >= limit ||
591
+ data[cur_ix_masked + best_len] != source[offset + best_len]) {
592
+ continue;
593
+ }
594
+ {
595
+ const size_t len = FindMatchLengthWithLimit(&source[offset],
596
+ &data[cur_ix_masked],
597
+ limit);
598
+ if (len >= 4) {
599
+ score_t score = BackwardReferenceScore(len, distance);
600
+ if (best_score < score) {
601
+ best_score = score;
602
+ best_len = len;
603
+ out->len = best_len;
604
+ out->len_code_delta = 0;
605
+ out->distance = distance;
606
+ out->score = best_score;
607
+ }
608
+ }
609
+ }
610
+ }
611
+ }
612
+
613
+ /* NB: when seamless dictionary-ring-buffer copies are implemented, don't forget
614
+ to add proper guards for non-zero-BROTLI_PARAM_STREAM_OFFSET. */
615
+ static BROTLI_INLINE size_t FindAllCompoundDictionaryMatches(
616
+ const PreparedDictionary* self, const uint8_t* BROTLI_RESTRICT data,
617
+ const size_t ring_buffer_mask, const size_t cur_ix, const size_t min_length,
618
+ const size_t max_length, const size_t distance_offset,
619
+ const size_t max_distance, BackwardMatch* matches, size_t match_limit) {
620
+ const uint32_t source_size = self->source_size;
621
+ const uint32_t hash_bits = self->hash_bits;
622
+ const uint32_t bucket_bits = self->bucket_bits;
623
+ const uint32_t slot_bits = self->slot_bits;
624
+
625
+ const uint32_t hash_shift = 64u - bucket_bits;
626
+ const uint32_t slot_mask = (~((uint32_t)0U)) >> (32 - slot_bits);
627
+ const uint64_t hash_mask = (~((uint64_t)0U)) >> (64 - hash_bits);
628
+
629
+ const uint32_t* slot_offsets = (uint32_t*)(&self[1]);
630
+ const uint16_t* heads = (uint16_t*)(&slot_offsets[1u << slot_bits]);
631
+ const uint32_t* items = (uint32_t*)(&heads[1u << bucket_bits]);
632
+ const uint8_t* source = NULL;
633
+
634
+ const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
635
+ size_t best_len = min_length;
636
+ const uint64_t h =
637
+ (BROTLI_UNALIGNED_LOAD64LE(&data[cur_ix_masked]) & hash_mask) *
638
+ kPreparedDictionaryHashMul64Long;
639
+ const uint32_t key = (uint32_t)(h >> hash_shift);
640
+ const uint32_t slot = key & slot_mask;
641
+ const uint32_t head = heads[key];
642
+ const uint32_t* BROTLI_RESTRICT chain = &items[slot_offsets[slot] + head];
643
+ uint32_t item = (head == 0xFFFF) ? 1 : 0;
644
+ size_t found = 0;
645
+
646
+ const void* tail = (void*)&items[self->num_items];
647
+ if (self->magic == kPreparedDictionaryMagic) {
648
+ source = (const uint8_t*)tail;
649
+ } else {
650
+ /* kLeanPreparedDictionaryMagic */
651
+ source = (const uint8_t*)BROTLI_UNALIGNED_LOAD_PTR((const uint8_t**)tail);
652
+ }
653
+
654
+ while (item == 0) {
655
+ size_t offset;
656
+ size_t distance;
657
+ size_t limit;
658
+ size_t len;
659
+ item = *chain;
660
+ chain++;
661
+ offset = item & 0x7FFFFFFF;
662
+ item &= 0x80000000;
663
+ distance = distance_offset - offset;
664
+ limit = source_size - offset;
665
+ limit = (limit > max_length) ? max_length : limit;
666
+ if (distance > max_distance) continue;
667
+ if (cur_ix_masked + best_len > ring_buffer_mask ||
668
+ best_len >= limit ||
669
+ data[cur_ix_masked + best_len] != source[offset + best_len]) {
670
+ continue;
671
+ }
672
+ len = FindMatchLengthWithLimit(
673
+ &source[offset], &data[cur_ix_masked], limit);
674
+ if (len > best_len) {
675
+ best_len = len;
676
+ InitBackwardMatch(matches++, distance, len);
677
+ found++;
678
+ if (found == match_limit) break;
679
+ }
680
+ }
681
+ return found;
682
+ }
683
+
684
+ static BROTLI_INLINE void LookupCompoundDictionaryMatch(
685
+ const CompoundDictionary* addon, const uint8_t* BROTLI_RESTRICT data,
686
+ const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache,
687
+ const size_t cur_ix, const size_t max_length,
688
+ const size_t max_ring_buffer_distance, const size_t max_distance,
689
+ HasherSearchResult* sr) {
690
+ size_t base_offset = max_ring_buffer_distance + 1 + addon->total_size - 1;
691
+ size_t d;
692
+ for (d = 0; d < addon->num_chunks; ++d) {
693
+ /* Only one prepared dictionary type is currently supported. */
694
+ FindCompoundDictionaryMatch(
695
+ (const PreparedDictionary*)addon->chunks[d], data, ring_buffer_mask,
696
+ distance_cache, cur_ix, max_length,
697
+ base_offset - addon->chunk_offsets[d], max_distance, sr);
698
+ }
699
+ }
700
+
701
+ static BROTLI_INLINE size_t LookupAllCompoundDictionaryMatches(
702
+ const CompoundDictionary* addon, const uint8_t* BROTLI_RESTRICT data,
703
+ const size_t ring_buffer_mask, const size_t cur_ix, size_t min_length,
704
+ const size_t max_length, const size_t max_ring_buffer_distance,
705
+ const size_t max_distance, BackwardMatch* matches,
706
+ size_t match_limit) {
707
+ size_t base_offset = max_ring_buffer_distance + 1 + addon->total_size - 1;
708
+ size_t d;
709
+ size_t total_found = 0;
710
+ for (d = 0; d < addon->num_chunks; ++d) {
711
+ /* Only one prepared dictionary type is currently supported. */
712
+ total_found += FindAllCompoundDictionaryMatches(
713
+ (const PreparedDictionary*)addon->chunks[d], data, ring_buffer_mask,
714
+ cur_ix, min_length, max_length, base_offset - addon->chunk_offsets[d],
715
+ max_distance, matches + total_found, match_limit - total_found);
716
+ if (total_found == match_limit) break;
717
+ if (total_found > 0) {
718
+ min_length = BackwardMatchLength(&matches[total_found - 1]);
719
+ }
720
+ }
721
+ return total_found;
722
+ }
723
+
494
724
  #if defined(__cplusplus) || defined(c_plusplus)
495
725
  } /* extern "C" */
496
726
  #endif