brotli 0.4.0 → 0.5.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/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 +1 -0
  7. data/ext/brotli/extconf.rb +6 -0
  8. data/lib/brotli/version.rb +1 -1
  9. data/test/brotli_test.rb +4 -1
  10. data/vendor/brotli/c/common/constants.c +1 -1
  11. data/vendor/brotli/c/common/constants.h +2 -1
  12. data/vendor/brotli/c/common/context.c +1 -1
  13. data/vendor/brotli/c/common/dictionary.c +5 -3
  14. data/vendor/brotli/c/common/platform.c +2 -1
  15. data/vendor/brotli/c/common/platform.h +60 -113
  16. data/vendor/brotli/c/common/shared_dictionary.c +521 -0
  17. data/vendor/brotli/c/common/shared_dictionary_internal.h +75 -0
  18. data/vendor/brotli/c/common/transform.c +1 -1
  19. data/vendor/brotli/c/common/version.h +31 -6
  20. data/vendor/brotli/c/dec/bit_reader.c +10 -8
  21. data/vendor/brotli/c/dec/bit_reader.h +172 -100
  22. data/vendor/brotli/c/dec/decode.c +467 -200
  23. data/vendor/brotli/c/dec/huffman.c +7 -4
  24. data/vendor/brotli/c/dec/huffman.h +2 -1
  25. data/vendor/brotli/c/dec/prefix.h +2 -1
  26. data/vendor/brotli/c/dec/state.c +33 -9
  27. data/vendor/brotli/c/dec/state.h +70 -35
  28. data/vendor/brotli/c/enc/backward_references.c +81 -19
  29. data/vendor/brotli/c/enc/backward_references.h +5 -4
  30. data/vendor/brotli/c/enc/backward_references_hq.c +148 -52
  31. data/vendor/brotli/c/enc/backward_references_hq.h +6 -5
  32. data/vendor/brotli/c/enc/backward_references_inc.h +31 -5
  33. data/vendor/brotli/c/enc/bit_cost.c +8 -7
  34. data/vendor/brotli/c/enc/bit_cost.h +5 -4
  35. data/vendor/brotli/c/enc/block_splitter.c +37 -14
  36. data/vendor/brotli/c/enc/block_splitter.h +5 -4
  37. data/vendor/brotli/c/enc/block_splitter_inc.h +86 -45
  38. data/vendor/brotli/c/enc/brotli_bit_stream.c +132 -110
  39. data/vendor/brotli/c/enc/brotli_bit_stream.h +11 -6
  40. data/vendor/brotli/c/enc/cluster.c +10 -9
  41. data/vendor/brotli/c/enc/cluster.h +7 -6
  42. data/vendor/brotli/c/enc/cluster_inc.h +25 -20
  43. data/vendor/brotli/c/enc/command.c +1 -1
  44. data/vendor/brotli/c/enc/command.h +5 -4
  45. data/vendor/brotli/c/enc/compound_dictionary.c +207 -0
  46. data/vendor/brotli/c/enc/compound_dictionary.h +74 -0
  47. data/vendor/brotli/c/enc/compress_fragment.c +93 -83
  48. data/vendor/brotli/c/enc/compress_fragment.h +32 -7
  49. data/vendor/brotli/c/enc/compress_fragment_two_pass.c +99 -87
  50. data/vendor/brotli/c/enc/compress_fragment_two_pass.h +21 -3
  51. data/vendor/brotli/c/enc/dictionary_hash.c +3 -1
  52. data/vendor/brotli/c/enc/encode.c +473 -404
  53. data/vendor/brotli/c/enc/encoder_dict.c +611 -4
  54. data/vendor/brotli/c/enc/encoder_dict.h +117 -3
  55. data/vendor/brotli/c/enc/entropy_encode.c +3 -2
  56. data/vendor/brotli/c/enc/entropy_encode.h +2 -1
  57. data/vendor/brotli/c/enc/entropy_encode_static.h +5 -2
  58. data/vendor/brotli/c/enc/fast_log.c +1 -1
  59. data/vendor/brotli/c/enc/fast_log.h +2 -1
  60. data/vendor/brotli/c/enc/find_match_length.h +15 -22
  61. data/vendor/brotli/c/enc/hash.h +285 -45
  62. data/vendor/brotli/c/enc/hash_composite_inc.h +26 -11
  63. data/vendor/brotli/c/enc/hash_forgetful_chain_inc.h +20 -18
  64. data/vendor/brotli/c/enc/hash_longest_match64_inc.h +34 -39
  65. data/vendor/brotli/c/enc/hash_longest_match_inc.h +6 -10
  66. data/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h +4 -4
  67. data/vendor/brotli/c/enc/hash_rolling_inc.h +4 -4
  68. data/vendor/brotli/c/enc/hash_to_binary_tree_inc.h +6 -5
  69. data/vendor/brotli/c/enc/histogram.c +4 -4
  70. data/vendor/brotli/c/enc/histogram.h +7 -6
  71. data/vendor/brotli/c/enc/literal_cost.c +20 -15
  72. data/vendor/brotli/c/enc/literal_cost.h +4 -2
  73. data/vendor/brotli/c/enc/memory.c +29 -5
  74. data/vendor/brotli/c/enc/memory.h +19 -2
  75. data/vendor/brotli/c/enc/metablock.c +72 -58
  76. data/vendor/brotli/c/enc/metablock.h +9 -8
  77. data/vendor/brotli/c/enc/metablock_inc.h +8 -6
  78. data/vendor/brotli/c/enc/params.h +4 -3
  79. data/vendor/brotli/c/enc/prefix.h +3 -2
  80. data/vendor/brotli/c/enc/quality.h +40 -3
  81. data/vendor/brotli/c/enc/ringbuffer.h +4 -3
  82. data/vendor/brotli/c/enc/state.h +104 -0
  83. data/vendor/brotli/c/enc/static_dict.c +60 -4
  84. data/vendor/brotli/c/enc/static_dict.h +3 -2
  85. data/vendor/brotli/c/enc/static_dict_lut.h +2 -0
  86. data/vendor/brotli/c/enc/utf8_util.c +1 -1
  87. data/vendor/brotli/c/enc/utf8_util.h +2 -1
  88. data/vendor/brotli/c/enc/write_bits.h +2 -1
  89. data/vendor/brotli/c/include/brotli/decode.h +67 -2
  90. data/vendor/brotli/c/include/brotli/encode.h +55 -2
  91. data/vendor/brotli/c/include/brotli/port.h +28 -11
  92. data/vendor/brotli/c/include/brotli/shared_dictionary.h +100 -0
  93. 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