brotli 0.4.0 → 0.6.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 (94) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +6 -3
  3. data/.github/workflows/publish.yml +7 -17
  4. data/.gitmodules +1 -1
  5. data/README.md +2 -2
  6. data/ext/brotli/brotli.c +8 -0
  7. data/ext/brotli/extconf.rb +6 -0
  8. data/lib/brotli/version.rb +1 -1
  9. data/test/brotli_test.rb +14 -1
  10. data/test/test_helper.rb +1 -0
  11. data/vendor/brotli/c/common/constants.c +1 -1
  12. data/vendor/brotli/c/common/constants.h +2 -1
  13. data/vendor/brotli/c/common/context.c +1 -1
  14. data/vendor/brotli/c/common/dictionary.c +5 -3
  15. data/vendor/brotli/c/common/platform.c +2 -1
  16. data/vendor/brotli/c/common/platform.h +60 -113
  17. data/vendor/brotli/c/common/shared_dictionary.c +521 -0
  18. data/vendor/brotli/c/common/shared_dictionary_internal.h +75 -0
  19. data/vendor/brotli/c/common/transform.c +1 -1
  20. data/vendor/brotli/c/common/version.h +31 -6
  21. data/vendor/brotli/c/dec/bit_reader.c +10 -8
  22. data/vendor/brotli/c/dec/bit_reader.h +172 -100
  23. data/vendor/brotli/c/dec/decode.c +467 -200
  24. data/vendor/brotli/c/dec/huffman.c +7 -4
  25. data/vendor/brotli/c/dec/huffman.h +2 -1
  26. data/vendor/brotli/c/dec/prefix.h +2 -1
  27. data/vendor/brotli/c/dec/state.c +33 -9
  28. data/vendor/brotli/c/dec/state.h +70 -35
  29. data/vendor/brotli/c/enc/backward_references.c +81 -19
  30. data/vendor/brotli/c/enc/backward_references.h +5 -4
  31. data/vendor/brotli/c/enc/backward_references_hq.c +148 -52
  32. data/vendor/brotli/c/enc/backward_references_hq.h +6 -5
  33. data/vendor/brotli/c/enc/backward_references_inc.h +31 -5
  34. data/vendor/brotli/c/enc/bit_cost.c +8 -7
  35. data/vendor/brotli/c/enc/bit_cost.h +5 -4
  36. data/vendor/brotli/c/enc/block_splitter.c +37 -14
  37. data/vendor/brotli/c/enc/block_splitter.h +5 -4
  38. data/vendor/brotli/c/enc/block_splitter_inc.h +86 -45
  39. data/vendor/brotli/c/enc/brotli_bit_stream.c +132 -110
  40. data/vendor/brotli/c/enc/brotli_bit_stream.h +11 -6
  41. data/vendor/brotli/c/enc/cluster.c +10 -9
  42. data/vendor/brotli/c/enc/cluster.h +7 -6
  43. data/vendor/brotli/c/enc/cluster_inc.h +25 -20
  44. data/vendor/brotli/c/enc/command.c +1 -1
  45. data/vendor/brotli/c/enc/command.h +5 -4
  46. data/vendor/brotli/c/enc/compound_dictionary.c +207 -0
  47. data/vendor/brotli/c/enc/compound_dictionary.h +74 -0
  48. data/vendor/brotli/c/enc/compress_fragment.c +93 -83
  49. data/vendor/brotli/c/enc/compress_fragment.h +32 -7
  50. data/vendor/brotli/c/enc/compress_fragment_two_pass.c +99 -87
  51. data/vendor/brotli/c/enc/compress_fragment_two_pass.h +21 -3
  52. data/vendor/brotli/c/enc/dictionary_hash.c +3 -1
  53. data/vendor/brotli/c/enc/encode.c +473 -404
  54. data/vendor/brotli/c/enc/encoder_dict.c +611 -4
  55. data/vendor/brotli/c/enc/encoder_dict.h +117 -3
  56. data/vendor/brotli/c/enc/entropy_encode.c +3 -2
  57. data/vendor/brotli/c/enc/entropy_encode.h +2 -1
  58. data/vendor/brotli/c/enc/entropy_encode_static.h +5 -2
  59. data/vendor/brotli/c/enc/fast_log.c +1 -1
  60. data/vendor/brotli/c/enc/fast_log.h +2 -1
  61. data/vendor/brotli/c/enc/find_match_length.h +15 -22
  62. data/vendor/brotli/c/enc/hash.h +285 -45
  63. data/vendor/brotli/c/enc/hash_composite_inc.h +26 -11
  64. data/vendor/brotli/c/enc/hash_forgetful_chain_inc.h +20 -18
  65. data/vendor/brotli/c/enc/hash_longest_match64_inc.h +34 -39
  66. data/vendor/brotli/c/enc/hash_longest_match_inc.h +6 -10
  67. data/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h +4 -4
  68. data/vendor/brotli/c/enc/hash_rolling_inc.h +4 -4
  69. data/vendor/brotli/c/enc/hash_to_binary_tree_inc.h +6 -5
  70. data/vendor/brotli/c/enc/histogram.c +4 -4
  71. data/vendor/brotli/c/enc/histogram.h +7 -6
  72. data/vendor/brotli/c/enc/literal_cost.c +20 -15
  73. data/vendor/brotli/c/enc/literal_cost.h +4 -2
  74. data/vendor/brotli/c/enc/memory.c +29 -5
  75. data/vendor/brotli/c/enc/memory.h +19 -2
  76. data/vendor/brotli/c/enc/metablock.c +72 -58
  77. data/vendor/brotli/c/enc/metablock.h +9 -8
  78. data/vendor/brotli/c/enc/metablock_inc.h +8 -6
  79. data/vendor/brotli/c/enc/params.h +4 -3
  80. data/vendor/brotli/c/enc/prefix.h +3 -2
  81. data/vendor/brotli/c/enc/quality.h +40 -3
  82. data/vendor/brotli/c/enc/ringbuffer.h +4 -3
  83. data/vendor/brotli/c/enc/state.h +104 -0
  84. data/vendor/brotli/c/enc/static_dict.c +60 -4
  85. data/vendor/brotli/c/enc/static_dict.h +3 -2
  86. data/vendor/brotli/c/enc/static_dict_lut.h +2 -0
  87. data/vendor/brotli/c/enc/utf8_util.c +1 -1
  88. data/vendor/brotli/c/enc/utf8_util.h +2 -1
  89. data/vendor/brotli/c/enc/write_bits.h +2 -1
  90. data/vendor/brotli/c/include/brotli/decode.h +67 -2
  91. data/vendor/brotli/c/include/brotli/encode.h +55 -2
  92. data/vendor/brotli/c/include/brotli/port.h +28 -11
  93. data/vendor/brotli/c/include/brotli/shared_dictionary.h +100 -0
  94. metadata +9 -3
@@ -20,13 +20,12 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; }
20
20
  static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
21
21
 
22
22
  /* HashBytes is the function that chooses the bucket to place the address in. */
23
- static BROTLI_INLINE uint32_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data,
24
- const uint64_t mask,
25
- const int shift) {
26
- const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(data) & mask) * kHashMul64Long;
23
+ static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data,
24
+ uint64_t hash_mul) {
25
+ const uint64_t h = BROTLI_UNALIGNED_LOAD64LE(data) * hash_mul;
27
26
  /* The higher bits contain more mixture from the multiplication,
28
27
  so we take our results from there. */
29
- return (uint32_t)(h >> shift);
28
+ return (size_t)(h >> (64 - 15));
30
29
  }
31
30
 
32
31
  typedef struct HashLongestMatch {
@@ -35,10 +34,8 @@ typedef struct HashLongestMatch {
35
34
  /* Only block_size_ newest backward references are kept,
36
35
  and the older are forgotten. */
37
36
  size_t block_size_;
38
- /* Left-shift for computing hash bucket index from hash value. */
39
- int hash_shift_;
40
- /* Mask for selecting the next 4-8 bytes of input */
41
- uint64_t hash_mask_;
37
+ /* Hash multiplier tuned to match length. */
38
+ uint64_t hash_mul_;
42
39
  /* Mask for accessing entries in a block (in a ring-buffer manner). */
43
40
  uint32_t block_mask_;
44
41
 
@@ -63,16 +60,16 @@ static void FN(Initialize)(
63
60
  self->common_ = common;
64
61
 
65
62
  BROTLI_UNUSED(params);
66
- self->hash_shift_ = 64 - common->params.bucket_bits;
67
- self->hash_mask_ = (~((uint64_t)0U)) >> (64 - 8 * common->params.hash_len);
63
+ self->hash_mul_ = kHashMul64 << (64 - 5 * 8);
64
+ BROTLI_DCHECK(common->params.bucket_bits == 15);
68
65
  self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
69
66
  self->block_bits_ = common->params.block_bits;
70
67
  self->block_size_ = (size_t)1 << common->params.block_bits;
71
68
  self->block_mask_ = (uint32_t)(self->block_size_ - 1);
72
69
  self->num_last_distances_to_check_ =
73
70
  common->params.num_last_distances_to_check;
74
- self->num_ = (uint16_t*)common->extra;
75
- self->buckets_ = (uint32_t*)&self->num_[self->bucket_size_];
71
+ self->num_ = (uint16_t*)common->extra[0];
72
+ self->buckets_ = (uint32_t*)common->extra[1];
76
73
  }
77
74
 
78
75
  static void FN(Prepare)(
@@ -84,8 +81,7 @@ static void FN(Prepare)(
84
81
  if (one_shot && input_size <= partial_prepare_threshold) {
85
82
  size_t i;
86
83
  for (i = 0; i < input_size; ++i) {
87
- const uint32_t key = FN(HashBytes)(&data[i], self->hash_mask_,
88
- self->hash_shift_);
84
+ const size_t key = FN(HashBytes)(&data[i], self->hash_mul_);
89
85
  num[key] = 0;
90
86
  }
91
87
  } else {
@@ -93,15 +89,15 @@ static void FN(Prepare)(
93
89
  }
94
90
  }
95
91
 
96
- static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
92
+ static BROTLI_INLINE void FN(HashMemAllocInBytes)(
97
93
  const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
98
- size_t input_size) {
94
+ size_t input_size, size_t* alloc_size) {
99
95
  size_t bucket_size = (size_t)1 << params->hasher.bucket_bits;
100
96
  size_t block_size = (size_t)1 << params->hasher.block_bits;
101
97
  BROTLI_UNUSED(one_shot);
102
98
  BROTLI_UNUSED(input_size);
103
- return sizeof(uint16_t) * bucket_size +
104
- sizeof(uint32_t) * bucket_size * block_size;
99
+ alloc_size[0] = sizeof(uint16_t) * bucket_size;
100
+ alloc_size[1] = sizeof(uint32_t) * bucket_size * block_size;
105
101
  }
106
102
 
107
103
  /* Look at 4 bytes at &data[ix & mask].
@@ -111,8 +107,7 @@ static BROTLI_INLINE void FN(Store)(
111
107
  const size_t mask, const size_t ix) {
112
108
  uint16_t* BROTLI_RESTRICT num = self->num_;
113
109
  uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
114
- const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_mask_,
115
- self->hash_shift_);
110
+ const size_t key = FN(HashBytes)(&data[ix & mask], self->hash_mul_);
116
111
  const size_t minor_ix = num[key] & self->block_mask_;
117
112
  const size_t offset = minor_ix + (key << self->block_bits_);
118
113
  ++num[key];
@@ -217,14 +212,17 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
217
212
  }
218
213
  }
219
214
  {
220
- const uint32_t key = FN(HashBytes)(
221
- &data[cur_ix_masked], self->hash_mask_, self->hash_shift_);
215
+ const size_t key = FN(HashBytes)(&data[cur_ix_masked], self->hash_mul_);
222
216
  uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
223
217
  const size_t down =
224
218
  (num[key] > self->block_size_) ?
225
219
  (num[key] - self->block_size_) : 0u;
226
- for (i = num[key]; i > down;) {
220
+ const uint32_t first4 = BrotliUnalignedRead32(data + cur_ix_masked);
221
+ const size_t max_length_m4 = max_length - 4;
222
+ i = num[key];
223
+ for (; i > down;) {
227
224
  size_t prev_ix = bucket[--i & self->block_mask_];
225
+ uint32_t current4;
228
226
  const size_t backward = cur_ix - prev_ix;
229
227
  if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
230
228
  break;
@@ -235,22 +233,19 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
235
233
  data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
236
234
  continue;
237
235
  }
236
+ current4 = BrotliUnalignedRead32(data + prev_ix);
237
+ if (first4 != current4) continue;
238
238
  {
239
- const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
240
- &data[cur_ix_masked],
241
- max_length);
242
- if (len >= 4) {
243
- /* Comparing for >= 3 does not change the semantics, but just saves
244
- for a few unnecessary binary logarithms in backward reference
245
- score, since we are not interested in such short matches. */
246
- score_t score = BackwardReferenceScore(len, backward);
247
- if (best_score < score) {
248
- best_score = score;
249
- best_len = len;
250
- out->len = best_len;
251
- out->distance = backward;
252
- out->score = best_score;
253
- }
239
+ const size_t len = FindMatchLengthWithLimit(&data[prev_ix + 4],
240
+ &data[cur_ix_masked + 4],
241
+ max_length_m4) + 4;
242
+ const score_t score = BackwardReferenceScore(len, backward);
243
+ if (best_score < score) {
244
+ best_score = score;
245
+ best_len = len;
246
+ out->len = best_len;
247
+ out->distance = backward;
248
+ out->score = best_score;
254
249
  }
255
250
  }
256
251
  }
@@ -54,10 +54,6 @@ typedef struct HashLongestMatch {
54
54
  uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
55
55
  } HashLongestMatch;
56
56
 
57
- static BROTLI_INLINE uint16_t* FN(Num)(void* extra) {
58
- return (uint16_t*)extra;
59
- }
60
-
61
57
  static void FN(Initialize)(
62
58
  HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
63
59
  const BrotliEncoderParams* params) {
@@ -68,8 +64,8 @@ static void FN(Initialize)(
68
64
  self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
69
65
  self->block_size_ = (size_t)1 << common->params.block_bits;
70
66
  self->block_mask_ = (uint32_t)(self->block_size_ - 1);
71
- self->num_ = (uint16_t*)common->extra;
72
- self->buckets_ = (uint32_t*)(&self->num_[self->bucket_size_]);
67
+ self->num_ = (uint16_t*)common->extra[0];
68
+ self->buckets_ = (uint32_t*)common->extra[1];
73
69
  self->block_bits_ = common->params.block_bits;
74
70
  self->num_last_distances_to_check_ =
75
71
  common->params.num_last_distances_to_check;
@@ -92,15 +88,15 @@ static void FN(Prepare)(
92
88
  }
93
89
  }
94
90
 
95
- static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
91
+ static BROTLI_INLINE void FN(HashMemAllocInBytes)(
96
92
  const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
97
- size_t input_size) {
93
+ size_t input_size, size_t* alloc_size) {
98
94
  size_t bucket_size = (size_t)1 << params->hasher.bucket_bits;
99
95
  size_t block_size = (size_t)1 << params->hasher.block_bits;
100
96
  BROTLI_UNUSED(one_shot);
101
97
  BROTLI_UNUSED(input_size);
102
- return sizeof(uint16_t) * bucket_size +
103
- sizeof(uint32_t) * bucket_size * block_size;
98
+ alloc_size[0] = sizeof(uint16_t) * bucket_size;
99
+ alloc_size[1] = sizeof(uint32_t) * bucket_size * block_size;
104
100
  }
105
101
 
106
102
  /* Look at 4 bytes at &data[ix & mask].
@@ -49,7 +49,7 @@ static void FN(Initialize)(
49
49
  self->common = common;
50
50
 
51
51
  BROTLI_UNUSED(params);
52
- self->buckets_ = (uint32_t*)common->extra;
52
+ self->buckets_ = (uint32_t*)common->extra[0];
53
53
  }
54
54
 
55
55
  static void FN(Prepare)(
@@ -80,13 +80,13 @@ static void FN(Prepare)(
80
80
  }
81
81
  }
82
82
 
83
- static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
83
+ static BROTLI_INLINE void FN(HashMemAllocInBytes)(
84
84
  const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
85
- size_t input_size) {
85
+ size_t input_size, size_t* alloc_size) {
86
86
  BROTLI_UNUSED(params);
87
87
  BROTLI_UNUSED(one_shot);
88
88
  BROTLI_UNUSED(input_size);
89
- return sizeof(uint32_t) * BUCKET_SIZE;
89
+ alloc_size[0] = sizeof(uint32_t) * BUCKET_SIZE;
90
90
  }
91
91
 
92
92
  /* Look at 5 bytes at &data[ix & mask].
@@ -67,7 +67,7 @@ static void FN(Initialize)(
67
67
  self->factor_remove *= self->factor;
68
68
  }
69
69
 
70
- self->table = (uint32_t*)common->extra;
70
+ self->table = (uint32_t*)common->extra[0];
71
71
  for (i = 0; i < NUMBUCKETS; i++) {
72
72
  self->table[i] = FN(kInvalidPos);
73
73
  }
@@ -88,13 +88,13 @@ static void FN(Prepare)(HashRolling* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
88
88
  BROTLI_UNUSED(one_shot);
89
89
  }
90
90
 
91
- static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
91
+ static BROTLI_INLINE void FN(HashMemAllocInBytes)(
92
92
  const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
93
- size_t input_size) {
94
- return NUMBUCKETS * sizeof(uint32_t);
93
+ size_t input_size, size_t* alloc_size) {
95
94
  BROTLI_UNUSED(params);
96
95
  BROTLI_UNUSED(one_shot);
97
96
  BROTLI_UNUSED(input_size);
97
+ alloc_size[0] = NUMBUCKETS * sizeof(uint32_t);
98
98
  }
99
99
 
100
100
  static BROTLI_INLINE void FN(Store)(HashRolling* BROTLI_RESTRICT self,
@@ -57,8 +57,8 @@ typedef struct HashToBinaryTree {
57
57
  static void FN(Initialize)(
58
58
  HasherCommon* common, HashToBinaryTree* BROTLI_RESTRICT self,
59
59
  const BrotliEncoderParams* params) {
60
- self->buckets_ = (uint32_t*)common->extra;
61
- self->forest_ = &self->buckets_[BUCKET_SIZE];
60
+ self->buckets_ = (uint32_t*)common->extra[0];
61
+ self->forest_ = (uint32_t*)common->extra[1];
62
62
 
63
63
  self->window_mask_ = (1u << params->lgwin) - 1u;
64
64
  self->invalid_pos_ = (uint32_t)(0 - self->window_mask_);
@@ -78,14 +78,15 @@ static void FN(Prepare)
78
78
  }
79
79
  }
80
80
 
81
- static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
81
+ static BROTLI_INLINE void FN(HashMemAllocInBytes)(
82
82
  const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
83
- size_t input_size) {
83
+ size_t input_size, size_t* alloc_size) {
84
84
  size_t num_nodes = (size_t)1 << params->lgwin;
85
85
  if (one_shot && input_size < num_nodes) {
86
86
  num_nodes = input_size;
87
87
  }
88
- return sizeof(uint32_t) * BUCKET_SIZE + 2 * sizeof(uint32_t) * num_nodes;
88
+ alloc_size[0] = sizeof(uint32_t) * BUCKET_SIZE;
89
+ alloc_size[1] = 2 * sizeof(uint32_t) * num_nodes;
89
90
  }
90
91
 
91
92
  static BROTLI_INLINE size_t FN(LeftChildIndex)(
@@ -6,11 +6,11 @@
6
6
 
7
7
  /* Build per-context histograms of literals, commands and distance codes. */
8
8
 
9
- #include "./histogram.h"
9
+ #include "histogram.h"
10
10
 
11
11
  #include "../common/context.h"
12
- #include "./block_splitter.h"
13
- #include "./command.h"
12
+ #include "block_splitter.h"
13
+ #include "command.h"
14
14
 
15
15
  #if defined(__cplusplus) || defined(c_plusplus)
16
16
  extern "C" {
@@ -63,7 +63,7 @@ void BrotliBuildHistogramsWithContext(
63
63
  BlockSplitIteratorNext(&insert_and_copy_it);
64
64
  HistogramAddCommand(&insert_and_copy_histograms[insert_and_copy_it.type_],
65
65
  cmd->cmd_prefix_);
66
- /* TODO: unwrap iterator blocks. */
66
+ /* TODO(eustas): unwrap iterator blocks. */
67
67
  for (j = cmd->insert_len_; j != 0; --j) {
68
68
  size_t context;
69
69
  BlockSplitIteratorNext(&literal_it);
@@ -11,12 +11,13 @@
11
11
 
12
12
  #include <string.h> /* memset */
13
13
 
14
+ #include <brotli/types.h>
15
+
14
16
  #include "../common/constants.h"
15
17
  #include "../common/context.h"
16
18
  #include "../common/platform.h"
17
- #include <brotli/types.h>
18
- #include "./block_splitter.h"
19
- #include "./command.h"
19
+ #include "block_splitter.h"
20
+ #include "command.h"
20
21
 
21
22
  #if defined(__cplusplus) || defined(c_plusplus)
22
23
  extern "C" {
@@ -28,7 +29,7 @@ extern "C" {
28
29
  #define FN(X) X ## Literal
29
30
  #define DATA_SIZE BROTLI_NUM_LITERAL_SYMBOLS
30
31
  #define DataType uint8_t
31
- #include "./histogram_inc.h" /* NOLINT(build/include) */
32
+ #include "histogram_inc.h" /* NOLINT(build/include) */
32
33
  #undef DataType
33
34
  #undef DATA_SIZE
34
35
  #undef FN
@@ -36,13 +37,13 @@ extern "C" {
36
37
  #define FN(X) X ## Command
37
38
  #define DataType uint16_t
38
39
  #define DATA_SIZE BROTLI_NUM_COMMAND_SYMBOLS
39
- #include "./histogram_inc.h" /* NOLINT(build/include) */
40
+ #include "histogram_inc.h" /* NOLINT(build/include) */
40
41
  #undef DATA_SIZE
41
42
  #undef FN
42
43
 
43
44
  #define FN(X) X ## Distance
44
45
  #define DATA_SIZE BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS
45
- #include "./histogram_inc.h" /* NOLINT(build/include) */
46
+ #include "histogram_inc.h" /* NOLINT(build/include) */
46
47
  #undef DataType
47
48
  #undef DATA_SIZE
48
49
  #undef FN
@@ -7,12 +7,15 @@
7
7
  /* Literal cost model to allow backward reference replacement to be efficient.
8
8
  */
9
9
 
10
- #include "./literal_cost.h"
10
+ #include "literal_cost.h"
11
+
12
+ #include <string.h> /* memset */
11
13
 
12
- #include "../common/platform.h"
13
14
  #include <brotli/types.h>
14
- #include "./fast_log.h"
15
- #include "./utf8_util.h"
15
+
16
+ #include "../common/platform.h"
17
+ #include "fast_log.h"
18
+ #include "utf8_util.h"
16
19
 
17
20
  #if defined(__cplusplus) || defined(c_plusplus)
18
21
  extern "C" {
@@ -54,22 +57,23 @@ static size_t DecideMultiByteStatsLevel(size_t pos, size_t len, size_t mask,
54
57
  }
55
58
 
56
59
  static void EstimateBitCostsForLiteralsUTF8(size_t pos, size_t len, size_t mask,
57
- const uint8_t* data, float* cost) {
60
+ const uint8_t* data,
61
+ size_t* histogram, float* cost) {
58
62
  /* max_utf8 is 0 (normal ASCII single byte modeling),
59
63
  1 (for 2-byte UTF-8 modeling), or 2 (for 3-byte UTF-8 modeling). */
60
64
  const size_t max_utf8 = DecideMultiByteStatsLevel(pos, len, mask, data);
61
- size_t histogram[3][256] = { { 0 } };
62
65
  size_t window_half = 495;
63
66
  size_t in_window = BROTLI_MIN(size_t, window_half, len);
64
67
  size_t in_window_utf8[3] = { 0 };
65
-
66
68
  size_t i;
69
+ memset(histogram, 0, 3 * 256 * sizeof(histogram[0]));
70
+
67
71
  { /* Bootstrap histograms. */
68
72
  size_t last_c = 0;
69
73
  size_t utf8_pos = 0;
70
74
  for (i = 0; i < in_window; ++i) {
71
75
  size_t c = data[(pos + i) & mask];
72
- ++histogram[utf8_pos][c];
76
+ ++histogram[256 * utf8_pos + c];
73
77
  ++in_window_utf8[utf8_pos];
74
78
  utf8_pos = UTF8Position(last_c, c, max_utf8);
75
79
  last_c = c;
@@ -85,7 +89,7 @@ static void EstimateBitCostsForLiteralsUTF8(size_t pos, size_t len, size_t mask,
85
89
  size_t last_c =
86
90
  i < window_half + 2 ? 0 : data[(pos + i - window_half - 2) & mask];
87
91
  size_t utf8_pos2 = UTF8Position(last_c, c, max_utf8);
88
- --histogram[utf8_pos2][data[(pos + i - window_half) & mask]];
92
+ --histogram[256 * utf8_pos2 + data[(pos + i - window_half) & mask]];
89
93
  --in_window_utf8[utf8_pos2];
90
94
  }
91
95
  if (i + window_half < len) {
@@ -93,7 +97,7 @@ static void EstimateBitCostsForLiteralsUTF8(size_t pos, size_t len, size_t mask,
93
97
  size_t c = data[(pos + i + window_half - 1) & mask];
94
98
  size_t last_c = data[(pos + i + window_half - 2) & mask];
95
99
  size_t utf8_pos2 = UTF8Position(last_c, c, max_utf8);
96
- ++histogram[utf8_pos2][data[(pos + i + window_half) & mask]];
100
+ ++histogram[256 * utf8_pos2 + data[(pos + i + window_half) & mask]];
97
101
  ++in_window_utf8[utf8_pos2];
98
102
  }
99
103
  {
@@ -101,7 +105,7 @@ static void EstimateBitCostsForLiteralsUTF8(size_t pos, size_t len, size_t mask,
101
105
  size_t last_c = i < 2 ? 0 : data[(pos + i - 2) & mask];
102
106
  size_t utf8_pos = UTF8Position(last_c, c, max_utf8);
103
107
  size_t masked_pos = (pos + i) & mask;
104
- size_t histo = histogram[utf8_pos][data[masked_pos]];
108
+ size_t histo = histogram[256 * utf8_pos + data[masked_pos]];
105
109
  double lit_cost;
106
110
  if (histo == 0) {
107
111
  histo = 1;
@@ -125,17 +129,18 @@ static void EstimateBitCostsForLiteralsUTF8(size_t pos, size_t len, size_t mask,
125
129
  }
126
130
 
127
131
  void BrotliEstimateBitCostsForLiterals(size_t pos, size_t len, size_t mask,
128
- const uint8_t* data, float* cost) {
132
+ const uint8_t* data,
133
+ size_t* histogram, float* cost) {
129
134
  if (BrotliIsMostlyUTF8(data, pos, mask, len, kMinUTF8Ratio)) {
130
- EstimateBitCostsForLiteralsUTF8(pos, len, mask, data, cost);
135
+ EstimateBitCostsForLiteralsUTF8(pos, len, mask, data, histogram, cost);
131
136
  return;
132
137
  } else {
133
- size_t histogram[256] = { 0 };
134
138
  size_t window_half = 2000;
135
139
  size_t in_window = BROTLI_MIN(size_t, window_half, len);
140
+ size_t i;
141
+ memset(histogram, 0, 256 * sizeof(histogram[0]));
136
142
 
137
143
  /* Bootstrap histogram. */
138
- size_t i;
139
144
  for (i = 0; i < in_window; ++i) {
140
145
  ++histogram[data[(pos + i) & mask]];
141
146
  }
@@ -10,9 +10,10 @@
10
10
  #ifndef BROTLI_ENC_LITERAL_COST_H_
11
11
  #define BROTLI_ENC_LITERAL_COST_H_
12
12
 
13
- #include "../common/platform.h"
14
13
  #include <brotli/types.h>
15
14
 
15
+ #include "../common/platform.h"
16
+
16
17
  #if defined(__cplusplus) || defined(c_plusplus)
17
18
  extern "C" {
18
19
  #endif
@@ -21,7 +22,8 @@ extern "C" {
21
22
  ring-buffer (data, mask) will take entropy coded and writes these estimates
22
23
  to the cost[0..len) array. */
23
24
  BROTLI_INTERNAL void BrotliEstimateBitCostsForLiterals(
24
- size_t pos, size_t len, size_t mask, const uint8_t* data, float* cost);
25
+ size_t pos, size_t len, size_t mask, const uint8_t* data, size_t* histogram,
26
+ float* cost);
25
27
 
26
28
  #if defined(__cplusplus) || defined(c_plusplus)
27
29
  } /* extern "C" */
@@ -7,21 +7,22 @@
7
7
  /* Algorithms for distributing the literals and commands of a metablock between
8
8
  block types and contexts. */
9
9
 
10
- #include "./memory.h"
10
+ #include "memory.h"
11
11
 
12
12
  #include <stdlib.h> /* exit, free, malloc */
13
13
  #include <string.h> /* memcpy */
14
14
 
15
- #include "../common/platform.h"
16
15
  #include <brotli/types.h>
17
16
 
17
+ #include "../common/platform.h"
18
+
18
19
  #if defined(__cplusplus) || defined(c_plusplus)
19
20
  extern "C" {
20
21
  #endif
21
22
 
22
- #define MAX_PERM_ALLOCATED 128
23
- #define MAX_NEW_ALLOCATED 64
24
- #define MAX_NEW_FREED 64
23
+ #define MAX_NEW_ALLOCATED (BROTLI_ENCODER_MEMORY_MANAGER_SLOTS >> 2)
24
+ #define MAX_NEW_FREED (BROTLI_ENCODER_MEMORY_MANAGER_SLOTS >> 2)
25
+ #define MAX_PERM_ALLOCATED (BROTLI_ENCODER_MEMORY_MANAGER_SLOTS >> 1)
25
26
 
26
27
  #define PERM_ALLOCATED_OFFSET 0
27
28
  #define NEW_ALLOCATED_OFFSET MAX_PERM_ALLOCATED
@@ -67,6 +68,7 @@ void BrotliWipeOutMemoryManager(MemoryManager* m) {
67
68
 
68
69
  static void SortPointers(void** items, const size_t n) {
69
70
  /* Shell sort. */
71
+ /* TODO(eustas): fine-tune for "many slots" case */
70
72
  static const size_t gaps[] = {23, 10, 4, 1};
71
73
  int g = 0;
72
74
  for (; g < 4; ++g) {
@@ -165,6 +167,28 @@ void BrotliWipeOutMemoryManager(MemoryManager* m) {
165
167
 
166
168
  #endif /* BROTLI_ENCODER_EXIT_ON_OOM */
167
169
 
170
+ void* BrotliBootstrapAlloc(size_t size,
171
+ brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
172
+ if (!alloc_func && !free_func) {
173
+ return malloc(size);
174
+ } else if (alloc_func && free_func) {
175
+ return alloc_func(opaque, size);
176
+ }
177
+ return NULL;
178
+ }
179
+
180
+ void BrotliBootstrapFree(void* address, MemoryManager* m) {
181
+ if (!address) {
182
+ /* Should not happen! */
183
+ return;
184
+ } else {
185
+ /* Copy values, as those would be freed. */
186
+ brotli_free_func free_func = m->free_func;
187
+ void* opaque = m->opaque;
188
+ free_func(opaque, address);
189
+ }
190
+ }
191
+
168
192
  #if defined(__cplusplus) || defined(c_plusplus)
169
193
  } /* extern "C" */
170
194
  #endif
@@ -11,9 +11,10 @@
11
11
 
12
12
  #include <string.h> /* memcpy */
13
13
 
14
- #include "../common/platform.h"
15
14
  #include <brotli/types.h>
16
15
 
16
+ #include "../common/platform.h"
17
+
17
18
  #if defined(__cplusplus) || defined(c_plusplus)
18
19
  extern "C" {
19
20
  #endif
@@ -23,6 +24,16 @@ extern "C" {
23
24
  #define BROTLI_ENCODER_EXIT_ON_OOM
24
25
  #endif
25
26
 
27
+ #if !defined(BROTLI_ENCODER_EXIT_ON_OOM)
28
+ #if defined(BROTLI_EXPERIMENTAL)
29
+ #define BROTLI_ENCODER_MEMORY_MANAGER_SLOTS (48*1024)
30
+ #else /* BROTLI_EXPERIMENTAL */
31
+ #define BROTLI_ENCODER_MEMORY_MANAGER_SLOTS 256
32
+ #endif /* BROTLI_EXPERIMENTAL */
33
+ #else /* BROTLI_ENCODER_EXIT_ON_OOM */
34
+ #define BROTLI_ENCODER_MEMORY_MANAGER_SLOTS 0
35
+ #endif /* BROTLI_ENCODER_EXIT_ON_OOM */
36
+
26
37
  typedef struct MemoryManager {
27
38
  brotli_alloc_func alloc_func;
28
39
  brotli_free_func free_func;
@@ -32,7 +43,7 @@ typedef struct MemoryManager {
32
43
  size_t perm_allocated;
33
44
  size_t new_allocated;
34
45
  size_t new_freed;
35
- void* pointers[256];
46
+ void* pointers[BROTLI_ENCODER_MEMORY_MANAGER_SLOTS];
36
47
  #endif /* BROTLI_ENCODER_EXIT_ON_OOM */
37
48
  } MemoryManager;
38
49
 
@@ -107,6 +118,12 @@ V: value to append
107
118
  A[(S) - 1] = (V); \
108
119
  }
109
120
 
121
+ /* "Bootstrap" allocations are not tracked by memory manager; should be used
122
+ only to allocate MemoryManager itself (or structure containing it). */
123
+ BROTLI_INTERNAL void* BrotliBootstrapAlloc(size_t size,
124
+ brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque);
125
+ BROTLI_INTERNAL void BrotliBootstrapFree(void* address, MemoryManager* m);
126
+
110
127
  #if defined(__cplusplus) || defined(c_plusplus)
111
128
  } /* extern "C" */
112
129
  #endif