brotli 0.1.8 → 0.2.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +7 -3
- data/brotli.gemspec +1 -1
- data/ext/brotli/brotli.c +4 -4
- data/ext/brotli/brotli.h +2 -2
- data/ext/brotli/extconf.rb +9 -16
- data/lib/brotli/version.rb +1 -1
- data/vendor/brotli/{common → c/common}/constants.h +11 -1
- data/vendor/brotli/c/common/dictionary.bin +432 -0
- data/vendor/brotli/c/common/dictionary.c +5905 -0
- data/vendor/brotli/c/common/dictionary.h +64 -0
- data/vendor/brotli/c/common/version.h +19 -0
- data/vendor/brotli/{dec → c/dec}/bit_reader.c +2 -2
- data/vendor/brotli/{dec → c/dec}/bit_reader.h +11 -34
- data/vendor/brotli/{dec → c/dec}/context.h +1 -1
- data/vendor/brotli/{dec → c/dec}/decode.c +389 -356
- data/vendor/brotli/{dec → c/dec}/huffman.c +24 -23
- data/vendor/brotli/{dec → c/dec}/huffman.h +1 -1
- data/vendor/brotli/{dec → c/dec}/port.h +19 -10
- data/vendor/brotli/{dec → c/dec}/prefix.h +1 -1
- data/vendor/brotli/{dec → c/dec}/state.c +23 -19
- data/vendor/brotli/{dec → c/dec}/state.h +18 -17
- data/vendor/brotli/{dec → c/dec}/transform.h +2 -2
- data/vendor/brotli/c/enc/backward_references.c +134 -0
- data/vendor/brotli/c/enc/backward_references.h +39 -0
- data/vendor/brotli/{enc/backward_references.c → c/enc/backward_references_hq.c} +144 -232
- data/vendor/brotli/{enc/backward_references.h → c/enc/backward_references_hq.h} +28 -31
- data/vendor/brotli/{enc → c/enc}/backward_references_inc.h +37 -31
- data/vendor/brotli/{enc → c/enc}/bit_cost.c +1 -1
- data/vendor/brotli/{enc → c/enc}/bit_cost.h +1 -1
- data/vendor/brotli/{enc → c/enc}/bit_cost_inc.h +0 -0
- data/vendor/brotli/{enc → c/enc}/block_encoder_inc.h +0 -0
- data/vendor/brotli/{enc → c/enc}/block_splitter.c +2 -4
- data/vendor/brotli/{enc → c/enc}/block_splitter.h +1 -1
- data/vendor/brotli/{enc → c/enc}/block_splitter_inc.h +6 -7
- data/vendor/brotli/{enc → c/enc}/brotli_bit_stream.c +22 -26
- data/vendor/brotli/{enc → c/enc}/brotli_bit_stream.h +1 -5
- data/vendor/brotli/{enc → c/enc}/cluster.c +1 -1
- data/vendor/brotli/{enc → c/enc}/cluster.h +1 -1
- data/vendor/brotli/{enc → c/enc}/cluster_inc.h +2 -0
- data/vendor/brotli/{enc → c/enc}/command.h +34 -17
- data/vendor/brotli/{enc → c/enc}/compress_fragment.c +97 -53
- data/vendor/brotli/{enc → c/enc}/compress_fragment.h +5 -2
- data/vendor/brotli/{enc → c/enc}/compress_fragment_two_pass.c +106 -51
- data/vendor/brotli/{enc → c/enc}/compress_fragment_two_pass.h +5 -2
- data/vendor/brotli/{enc → c/enc}/context.h +3 -3
- data/vendor/brotli/c/enc/dictionary_hash.c +1120 -0
- data/vendor/brotli/c/enc/dictionary_hash.h +24 -0
- data/vendor/brotli/{enc → c/enc}/encode.c +442 -240
- data/vendor/brotli/{enc → c/enc}/entropy_encode.c +9 -9
- data/vendor/brotli/{enc → c/enc}/entropy_encode.h +4 -4
- data/vendor/brotli/{enc → c/enc}/entropy_encode_static.h +4 -4
- data/vendor/brotli/{enc → c/enc}/fast_log.h +3 -3
- data/vendor/brotli/{enc → c/enc}/find_match_length.h +8 -8
- data/vendor/brotli/c/enc/hash.h +446 -0
- data/vendor/brotli/{enc → c/enc}/hash_forgetful_chain_inc.h +72 -68
- data/vendor/brotli/c/enc/hash_longest_match64_inc.h +266 -0
- data/vendor/brotli/c/enc/hash_longest_match_inc.h +258 -0
- data/vendor/brotli/{enc → c/enc}/hash_longest_match_quickly_inc.h +81 -77
- data/vendor/brotli/c/enc/hash_to_binary_tree_inc.h +326 -0
- data/vendor/brotli/{enc → c/enc}/histogram.c +4 -2
- data/vendor/brotli/{enc → c/enc}/histogram.h +1 -1
- data/vendor/brotli/{enc → c/enc}/histogram_inc.h +0 -0
- data/vendor/brotli/{enc → c/enc}/literal_cost.c +4 -7
- data/vendor/brotli/{enc → c/enc}/literal_cost.h +2 -2
- data/vendor/brotli/{enc → c/enc}/memory.c +1 -1
- data/vendor/brotli/{enc → c/enc}/memory.h +3 -2
- data/vendor/brotli/{enc → c/enc}/metablock.c +136 -123
- data/vendor/brotli/{enc → c/enc}/metablock.h +2 -12
- data/vendor/brotli/{enc → c/enc}/metablock_inc.h +0 -0
- data/vendor/brotli/{enc → c/enc}/port.h +49 -33
- data/vendor/brotli/{enc → c/enc}/prefix.h +4 -2
- data/vendor/brotli/{enc → c/enc}/quality.h +47 -17
- data/vendor/brotli/{enc → c/enc}/ringbuffer.h +6 -6
- data/vendor/brotli/{enc → c/enc}/static_dict.c +26 -22
- data/vendor/brotli/{enc → c/enc}/static_dict.h +3 -1
- data/vendor/brotli/c/enc/static_dict_lut.h +5864 -0
- data/vendor/brotli/{enc → c/enc}/utf8_util.c +1 -1
- data/vendor/brotli/{enc → c/enc}/utf8_util.h +2 -2
- data/vendor/brotli/{enc → c/enc}/write_bits.h +3 -3
- data/vendor/brotli/c/include/brotli/decode.h +339 -0
- data/vendor/brotli/c/include/brotli/encode.h +402 -0
- data/vendor/brotli/c/include/brotli/port.h +146 -0
- data/vendor/brotli/c/include/brotli/types.h +90 -0
- metadata +80 -79
- data/vendor/brotli/common/dictionary.c +0 -9474
- data/vendor/brotli/common/dictionary.h +0 -29
- data/vendor/brotli/common/port.h +0 -107
- data/vendor/brotli/common/types.h +0 -58
- data/vendor/brotli/dec/decode.h +0 -188
- data/vendor/brotli/enc/compressor.cc +0 -139
- data/vendor/brotli/enc/compressor.h +0 -161
- data/vendor/brotli/enc/dictionary_hash.h +0 -4121
- data/vendor/brotli/enc/encode.h +0 -221
- data/vendor/brotli/enc/encode_parallel.cc +0 -289
- data/vendor/brotli/enc/encode_parallel.h +0 -27
- data/vendor/brotli/enc/hash.h +0 -717
- data/vendor/brotli/enc/hash_longest_match_inc.h +0 -241
- data/vendor/brotli/enc/static_dict_lut.h +0 -11241
- data/vendor/brotli/enc/streams.cc +0 -114
- data/vendor/brotli/enc/streams.h +0 -121
@@ -0,0 +1,326 @@
|
|
1
|
+
/* NOLINT(build/header_guard) */
|
2
|
+
/* Copyright 2016 Google Inc. All Rights Reserved.
|
3
|
+
|
4
|
+
Distributed under MIT license.
|
5
|
+
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
6
|
+
*/
|
7
|
+
|
8
|
+
/* template parameters: FN, BUCKET_BITS, MAX_TREE_COMP_LENGTH,
|
9
|
+
MAX_TREE_SEARCH_DEPTH */
|
10
|
+
|
11
|
+
/* A (forgetful) hash table where each hash bucket contains a binary tree of
|
12
|
+
sequences whose first 4 bytes share the same hash code.
|
13
|
+
Each sequence is MAX_TREE_COMP_LENGTH long and is identified by its starting
|
14
|
+
position in the input data. The binary tree is sorted by the lexicographic
|
15
|
+
order of the sequences, and it is also a max-heap with respect to the
|
16
|
+
starting positions. */
|
17
|
+
|
18
|
+
#define HashToBinaryTree HASHER()
|
19
|
+
|
20
|
+
#define BUCKET_SIZE (1 << BUCKET_BITS)
|
21
|
+
|
22
|
+
static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
|
23
|
+
static BROTLI_INLINE size_t FN(StoreLookahead)(void) {
|
24
|
+
return MAX_TREE_COMP_LENGTH;
|
25
|
+
}
|
26
|
+
|
27
|
+
static uint32_t FN(HashBytes)(const uint8_t *data) {
|
28
|
+
uint32_t h = BROTLI_UNALIGNED_LOAD32(data) * kHashMul32;
|
29
|
+
/* The higher bits contain more mixture from the multiplication,
|
30
|
+
so we take our results from there. */
|
31
|
+
return h >> (32 - BUCKET_BITS);
|
32
|
+
}
|
33
|
+
|
34
|
+
typedef struct HashToBinaryTree {
|
35
|
+
/* The window size minus 1 */
|
36
|
+
size_t window_mask_;
|
37
|
+
|
38
|
+
/* Hash table that maps the 4-byte hashes of the sequence to the last
|
39
|
+
position where this hash was found, which is the root of the binary
|
40
|
+
tree of sequences that share this hash bucket. */
|
41
|
+
uint32_t buckets_[BUCKET_SIZE];
|
42
|
+
|
43
|
+
/* A position used to mark a non-existent sequence, i.e. a tree is empty if
|
44
|
+
its root is at invalid_pos_ and a node is a leaf if both its children
|
45
|
+
are at invalid_pos_. */
|
46
|
+
uint32_t invalid_pos_;
|
47
|
+
|
48
|
+
/* --- Dynamic size members --- */
|
49
|
+
|
50
|
+
/* The union of the binary trees of each hash bucket. The root of the tree
|
51
|
+
corresponding to a hash is a sequence starting at buckets_[hash] and
|
52
|
+
the left and right children of a sequence starting at pos are
|
53
|
+
forest_[2 * pos] and forest_[2 * pos + 1]. */
|
54
|
+
/* uint32_t forest[2 * num_nodes] */
|
55
|
+
} HashToBinaryTree;
|
56
|
+
|
57
|
+
static BROTLI_INLINE HashToBinaryTree* FN(Self)(HasherHandle handle) {
|
58
|
+
return (HashToBinaryTree*)&(GetHasherCommon(handle)[1]);
|
59
|
+
}
|
60
|
+
|
61
|
+
static BROTLI_INLINE uint32_t* FN(Forest)(HashToBinaryTree* self) {
|
62
|
+
return (uint32_t*)(&self[1]);
|
63
|
+
}
|
64
|
+
|
65
|
+
static void FN(Initialize)(
|
66
|
+
HasherHandle handle, const BrotliEncoderParams* params) {
|
67
|
+
HashToBinaryTree* self = FN(Self)(handle);
|
68
|
+
self->window_mask_ = (1u << params->lgwin) - 1u;
|
69
|
+
self->invalid_pos_ = (uint32_t)(0 - self->window_mask_);
|
70
|
+
}
|
71
|
+
|
72
|
+
static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
73
|
+
size_t input_size, const uint8_t* data) {
|
74
|
+
HashToBinaryTree* self = FN(Self)(handle);
|
75
|
+
uint32_t invalid_pos = self->invalid_pos_;
|
76
|
+
uint32_t i;
|
77
|
+
BROTLI_UNUSED(data);
|
78
|
+
BROTLI_UNUSED(one_shot);
|
79
|
+
BROTLI_UNUSED(input_size);
|
80
|
+
for (i = 0; i < BUCKET_SIZE; i++) {
|
81
|
+
self->buckets_[i] = invalid_pos;
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
86
|
+
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
87
|
+
size_t input_size) {
|
88
|
+
size_t num_nodes = (size_t)1 << params->lgwin;
|
89
|
+
if (one_shot && input_size < num_nodes) {
|
90
|
+
num_nodes = input_size;
|
91
|
+
}
|
92
|
+
return sizeof(HashToBinaryTree) + 2 * sizeof(uint32_t) * num_nodes;
|
93
|
+
}
|
94
|
+
|
95
|
+
static BROTLI_INLINE size_t FN(LeftChildIndex)(HashToBinaryTree* self,
|
96
|
+
const size_t pos) {
|
97
|
+
return 2 * (pos & self->window_mask_);
|
98
|
+
}
|
99
|
+
|
100
|
+
static BROTLI_INLINE size_t FN(RightChildIndex)(HashToBinaryTree* self,
|
101
|
+
const size_t pos) {
|
102
|
+
return 2 * (pos & self->window_mask_) + 1;
|
103
|
+
}
|
104
|
+
|
105
|
+
/* Stores the hash of the next 4 bytes and in a single tree-traversal, the
|
106
|
+
hash bucket's binary tree is searched for matches and is re-rooted at the
|
107
|
+
current position.
|
108
|
+
|
109
|
+
If less than MAX_TREE_COMP_LENGTH data is available, the hash bucket of the
|
110
|
+
current position is searched for matches, but the state of the hash table
|
111
|
+
is not changed, since we can not know the final sorting order of the
|
112
|
+
current (incomplete) sequence.
|
113
|
+
|
114
|
+
This function must be called with increasing cur_ix positions. */
|
115
|
+
static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
|
116
|
+
HashToBinaryTree* self, const uint8_t* const BROTLI_RESTRICT data,
|
117
|
+
const size_t cur_ix, const size_t ring_buffer_mask, const size_t max_length,
|
118
|
+
const size_t max_backward, size_t* const BROTLI_RESTRICT best_len,
|
119
|
+
BackwardMatch* BROTLI_RESTRICT matches) {
|
120
|
+
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
121
|
+
const size_t max_comp_len =
|
122
|
+
BROTLI_MIN(size_t, max_length, MAX_TREE_COMP_LENGTH);
|
123
|
+
const BROTLI_BOOL should_reroot_tree =
|
124
|
+
TO_BROTLI_BOOL(max_length >= MAX_TREE_COMP_LENGTH);
|
125
|
+
const uint32_t key = FN(HashBytes)(&data[cur_ix_masked]);
|
126
|
+
uint32_t* forest = FN(Forest)(self);
|
127
|
+
size_t prev_ix = self->buckets_[key];
|
128
|
+
/* The forest index of the rightmost node of the left subtree of the new
|
129
|
+
root, updated as we traverse and re-root the tree of the hash bucket. */
|
130
|
+
size_t node_left = FN(LeftChildIndex)(self, cur_ix);
|
131
|
+
/* The forest index of the leftmost node of the right subtree of the new
|
132
|
+
root, updated as we traverse and re-root the tree of the hash bucket. */
|
133
|
+
size_t node_right = FN(RightChildIndex)(self, cur_ix);
|
134
|
+
/* The match length of the rightmost node of the left subtree of the new
|
135
|
+
root, updated as we traverse and re-root the tree of the hash bucket. */
|
136
|
+
size_t best_len_left = 0;
|
137
|
+
/* The match length of the leftmost node of the right subtree of the new
|
138
|
+
root, updated as we traverse and re-root the tree of the hash bucket. */
|
139
|
+
size_t best_len_right = 0;
|
140
|
+
size_t depth_remaining;
|
141
|
+
if (should_reroot_tree) {
|
142
|
+
self->buckets_[key] = (uint32_t)cur_ix;
|
143
|
+
}
|
144
|
+
for (depth_remaining = MAX_TREE_SEARCH_DEPTH; ; --depth_remaining) {
|
145
|
+
const size_t backward = cur_ix - prev_ix;
|
146
|
+
const size_t prev_ix_masked = prev_ix & ring_buffer_mask;
|
147
|
+
if (backward == 0 || backward > max_backward || depth_remaining == 0) {
|
148
|
+
if (should_reroot_tree) {
|
149
|
+
forest[node_left] = self->invalid_pos_;
|
150
|
+
forest[node_right] = self->invalid_pos_;
|
151
|
+
}
|
152
|
+
break;
|
153
|
+
}
|
154
|
+
{
|
155
|
+
const size_t cur_len = BROTLI_MIN(size_t, best_len_left, best_len_right);
|
156
|
+
size_t len;
|
157
|
+
assert(cur_len <= MAX_TREE_COMP_LENGTH);
|
158
|
+
len = cur_len +
|
159
|
+
FindMatchLengthWithLimit(&data[cur_ix_masked + cur_len],
|
160
|
+
&data[prev_ix_masked + cur_len],
|
161
|
+
max_length - cur_len);
|
162
|
+
assert(0 == memcmp(&data[cur_ix_masked], &data[prev_ix_masked], len));
|
163
|
+
if (matches && len > *best_len) {
|
164
|
+
*best_len = len;
|
165
|
+
InitBackwardMatch(matches++, backward, len);
|
166
|
+
}
|
167
|
+
if (len >= max_comp_len) {
|
168
|
+
if (should_reroot_tree) {
|
169
|
+
forest[node_left] = forest[FN(LeftChildIndex)(self, prev_ix)];
|
170
|
+
forest[node_right] = forest[FN(RightChildIndex)(self, prev_ix)];
|
171
|
+
}
|
172
|
+
break;
|
173
|
+
}
|
174
|
+
if (data[cur_ix_masked + len] > data[prev_ix_masked + len]) {
|
175
|
+
best_len_left = len;
|
176
|
+
if (should_reroot_tree) {
|
177
|
+
forest[node_left] = (uint32_t)prev_ix;
|
178
|
+
}
|
179
|
+
node_left = FN(RightChildIndex)(self, prev_ix);
|
180
|
+
prev_ix = forest[node_left];
|
181
|
+
} else {
|
182
|
+
best_len_right = len;
|
183
|
+
if (should_reroot_tree) {
|
184
|
+
forest[node_right] = (uint32_t)prev_ix;
|
185
|
+
}
|
186
|
+
node_right = FN(LeftChildIndex)(self, prev_ix);
|
187
|
+
prev_ix = forest[node_right];
|
188
|
+
}
|
189
|
+
}
|
190
|
+
}
|
191
|
+
return matches;
|
192
|
+
}
|
193
|
+
|
194
|
+
/* Finds all backward matches of &data[cur_ix & ring_buffer_mask] up to the
|
195
|
+
length of max_length and stores the position cur_ix in the hash table.
|
196
|
+
|
197
|
+
Sets *num_matches to the number of matches found, and stores the found
|
198
|
+
matches in matches[0] to matches[*num_matches - 1]. The matches will be
|
199
|
+
sorted by strictly increasing length and (non-strictly) increasing
|
200
|
+
distance. */
|
201
|
+
static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle,
|
202
|
+
const BrotliDictionary* dictionary, const uint8_t* data,
|
203
|
+
const size_t ring_buffer_mask, const size_t cur_ix,
|
204
|
+
const size_t max_length, const size_t max_backward, const size_t gap,
|
205
|
+
const BrotliEncoderParams* params, BackwardMatch* matches) {
|
206
|
+
BackwardMatch* const orig_matches = matches;
|
207
|
+
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
208
|
+
size_t best_len = 1;
|
209
|
+
const size_t short_match_max_backward =
|
210
|
+
params->quality != HQ_ZOPFLIFICATION_QUALITY ? 16 : 64;
|
211
|
+
size_t stop = cur_ix - short_match_max_backward;
|
212
|
+
uint32_t dict_matches[BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN + 1];
|
213
|
+
size_t i;
|
214
|
+
if (cur_ix < short_match_max_backward) { stop = 0; }
|
215
|
+
for (i = cur_ix - 1; i > stop && best_len <= 2; --i) {
|
216
|
+
size_t prev_ix = i;
|
217
|
+
const size_t backward = cur_ix - prev_ix;
|
218
|
+
if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
|
219
|
+
break;
|
220
|
+
}
|
221
|
+
prev_ix &= ring_buffer_mask;
|
222
|
+
if (data[cur_ix_masked] != data[prev_ix] ||
|
223
|
+
data[cur_ix_masked + 1] != data[prev_ix + 1]) {
|
224
|
+
continue;
|
225
|
+
}
|
226
|
+
{
|
227
|
+
const size_t len =
|
228
|
+
FindMatchLengthWithLimit(&data[prev_ix], &data[cur_ix_masked],
|
229
|
+
max_length);
|
230
|
+
if (len > best_len) {
|
231
|
+
best_len = len;
|
232
|
+
InitBackwardMatch(matches++, backward, len);
|
233
|
+
}
|
234
|
+
}
|
235
|
+
}
|
236
|
+
if (best_len < max_length) {
|
237
|
+
matches = FN(StoreAndFindMatches)(FN(Self)(handle), data, cur_ix,
|
238
|
+
ring_buffer_mask, max_length, max_backward, &best_len, matches);
|
239
|
+
}
|
240
|
+
for (i = 0; i <= BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN; ++i) {
|
241
|
+
dict_matches[i] = kInvalidMatch;
|
242
|
+
}
|
243
|
+
{
|
244
|
+
size_t minlen = BROTLI_MAX(size_t, 4, best_len + 1);
|
245
|
+
if (BrotliFindAllStaticDictionaryMatches(dictionary,
|
246
|
+
&data[cur_ix_masked], minlen, max_length, &dict_matches[0])) {
|
247
|
+
size_t maxlen = BROTLI_MIN(
|
248
|
+
size_t, BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN, max_length);
|
249
|
+
size_t l;
|
250
|
+
for (l = minlen; l <= maxlen; ++l) {
|
251
|
+
uint32_t dict_id = dict_matches[l];
|
252
|
+
if (dict_id < kInvalidMatch) {
|
253
|
+
size_t distance = max_backward + gap + (dict_id >> 5) + 1;
|
254
|
+
if (distance < BROTLI_MAX_DISTANCE) {
|
255
|
+
InitDictionaryBackwardMatch(matches++, distance, l, dict_id & 31);
|
256
|
+
}
|
257
|
+
}
|
258
|
+
}
|
259
|
+
}
|
260
|
+
}
|
261
|
+
return (size_t)(matches - orig_matches);
|
262
|
+
}
|
263
|
+
|
264
|
+
/* Stores the hash of the next 4 bytes and re-roots the binary tree at the
|
265
|
+
current sequence, without returning any matches.
|
266
|
+
REQUIRES: ix + MAX_TREE_COMP_LENGTH <= end-of-current-block */
|
267
|
+
static BROTLI_INLINE void FN(Store)(HasherHandle handle, const uint8_t *data,
|
268
|
+
const size_t mask, const size_t ix) {
|
269
|
+
HashToBinaryTree* self = FN(Self)(handle);
|
270
|
+
/* Maximum distance is window size - 16, see section 9.1. of the spec. */
|
271
|
+
const size_t max_backward = self->window_mask_ - BROTLI_WINDOW_GAP + 1;
|
272
|
+
FN(StoreAndFindMatches)(self, data, ix, mask, MAX_TREE_COMP_LENGTH,
|
273
|
+
max_backward, NULL, NULL);
|
274
|
+
}
|
275
|
+
|
276
|
+
static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
|
277
|
+
const uint8_t *data, const size_t mask, const size_t ix_start,
|
278
|
+
const size_t ix_end) {
|
279
|
+
size_t i = ix_start;
|
280
|
+
size_t j = ix_start;
|
281
|
+
if (ix_start + 63 <= ix_end) {
|
282
|
+
i = ix_end - 63;
|
283
|
+
}
|
284
|
+
if (ix_start + 512 <= i) {
|
285
|
+
for (; j < i; j += 8) {
|
286
|
+
FN(Store)(handle, data, mask, j);
|
287
|
+
}
|
288
|
+
}
|
289
|
+
for (; i < ix_end; ++i) {
|
290
|
+
FN(Store)(handle, data, mask, i);
|
291
|
+
}
|
292
|
+
}
|
293
|
+
|
294
|
+
static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
|
295
|
+
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
296
|
+
size_t ringbuffer_mask) {
|
297
|
+
HashToBinaryTree* self = FN(Self)(handle);
|
298
|
+
if (num_bytes >= FN(HashTypeLength)() - 1 &&
|
299
|
+
position >= MAX_TREE_COMP_LENGTH) {
|
300
|
+
/* Store the last `MAX_TREE_COMP_LENGTH - 1` positions in the hasher.
|
301
|
+
These could not be calculated before, since they require knowledge
|
302
|
+
of both the previous and the current block. */
|
303
|
+
const size_t i_start = position - MAX_TREE_COMP_LENGTH + 1;
|
304
|
+
const size_t i_end = BROTLI_MIN(size_t, position, i_start + num_bytes);
|
305
|
+
size_t i;
|
306
|
+
for (i = i_start; i < i_end; ++i) {
|
307
|
+
/* Maximum distance is window size - 16, see section 9.1. of the spec.
|
308
|
+
Furthermore, we have to make sure that we don't look further back
|
309
|
+
from the start of the next block than the window size, otherwise we
|
310
|
+
could access already overwritten areas of the ring-buffer. */
|
311
|
+
const size_t max_backward =
|
312
|
+
self->window_mask_ - BROTLI_MAX(size_t,
|
313
|
+
BROTLI_WINDOW_GAP - 1,
|
314
|
+
position - i);
|
315
|
+
/* We know that i + MAX_TREE_COMP_LENGTH <= position + num_bytes, i.e. the
|
316
|
+
end of the current block and that we have at least
|
317
|
+
MAX_TREE_COMP_LENGTH tail in the ring-buffer. */
|
318
|
+
FN(StoreAndFindMatches)(self, ringbuffer, i, ringbuffer_mask,
|
319
|
+
MAX_TREE_COMP_LENGTH, max_backward, NULL, NULL);
|
320
|
+
}
|
321
|
+
}
|
322
|
+
}
|
323
|
+
|
324
|
+
#undef BUCKET_SIZE
|
325
|
+
|
326
|
+
#undef HashToBinaryTree
|
@@ -66,8 +66,10 @@ void BrotliBuildHistogramsWithContext(
|
|
66
66
|
for (j = cmd->insert_len_; j != 0; --j) {
|
67
67
|
size_t context;
|
68
68
|
BlockSplitIteratorNext(&literal_it);
|
69
|
-
context =
|
70
|
-
|
69
|
+
context = context_modes ?
|
70
|
+
((literal_it.type_ << BROTLI_LITERAL_CONTEXT_BITS) +
|
71
|
+
Context(prev_byte, prev_byte2, context_modes[literal_it.type_])) :
|
72
|
+
literal_it.type_;
|
71
73
|
HistogramAddLiteral(&literal_histograms[context],
|
72
74
|
ringbuffer[pos & mask]);
|
73
75
|
prev_byte2 = prev_byte;
|
File without changes
|
@@ -9,7 +9,7 @@
|
|
9
9
|
|
10
10
|
#include "./literal_cost.h"
|
11
11
|
|
12
|
-
#include
|
12
|
+
#include <brotli/types.h>
|
13
13
|
#include "./fast_log.h"
|
14
14
|
#include "./port.h"
|
15
15
|
#include "./utf8_util.h"
|
@@ -38,12 +38,10 @@ static size_t DecideMultiByteStatsLevel(size_t pos, size_t len, size_t mask,
|
|
38
38
|
size_t counts[3] = { 0 };
|
39
39
|
size_t max_utf8 = 1; /* should be 2, but 1 compresses better. */
|
40
40
|
size_t last_c = 0;
|
41
|
-
size_t utf8_pos = 0;
|
42
41
|
size_t i;
|
43
42
|
for (i = 0; i < len; ++i) {
|
44
43
|
size_t c = data[(pos + i) & mask];
|
45
|
-
|
46
|
-
++counts[utf8_pos];
|
44
|
+
++counts[UTF8Position(last_c, c, 2)];
|
47
45
|
last_c = c;
|
48
46
|
}
|
49
47
|
if (counts[2] < 500) {
|
@@ -57,15 +55,14 @@ static size_t DecideMultiByteStatsLevel(size_t pos, size_t len, size_t mask,
|
|
57
55
|
|
58
56
|
static void EstimateBitCostsForLiteralsUTF8(size_t pos, size_t len, size_t mask,
|
59
57
|
const uint8_t *data, float *cost) {
|
60
|
-
/* max_utf8 is 0 (normal
|
61
|
-
1 (for 2-byte
|
58
|
+
/* max_utf8 is 0 (normal ASCII single byte modeling),
|
59
|
+
1 (for 2-byte UTF-8 modeling), or 2 (for 3-byte UTF-8 modeling). */
|
62
60
|
const size_t max_utf8 = DecideMultiByteStatsLevel(pos, len, mask, data);
|
63
61
|
size_t histogram[3][256] = { { 0 } };
|
64
62
|
size_t window_half = 495;
|
65
63
|
size_t in_window = BROTLI_MIN(size_t, window_half, len);
|
66
64
|
size_t in_window_utf8[3] = { 0 };
|
67
65
|
|
68
|
-
|
69
66
|
size_t i;
|
70
67
|
{ /* Bootstrap histograms. */
|
71
68
|
size_t last_c = 0;
|
@@ -10,7 +10,7 @@
|
|
10
10
|
#ifndef BROTLI_ENC_LITERAL_COST_H_
|
11
11
|
#define BROTLI_ENC_LITERAL_COST_H_
|
12
12
|
|
13
|
-
#include
|
13
|
+
#include <brotli/types.h>
|
14
14
|
#include "./port.h"
|
15
15
|
|
16
16
|
#if defined(__cplusplus) || defined(c_plusplus)
|
@@ -18,7 +18,7 @@ extern "C" {
|
|
18
18
|
#endif
|
19
19
|
|
20
20
|
/* Estimates how many bits the literals in the interval [pos, pos + len) in the
|
21
|
-
|
21
|
+
ring-buffer (data, mask) will take entropy coded and writes these estimates
|
22
22
|
to the cost[0..len) array. */
|
23
23
|
BROTLI_INTERNAL void BrotliEstimateBitCostsForLiterals(
|
24
24
|
size_t pos, size_t len, size_t mask, const uint8_t *data, float *cost);
|
@@ -9,7 +9,7 @@
|
|
9
9
|
#ifndef BROTLI_ENC_MEMORY_H_
|
10
10
|
#define BROTLI_ENC_MEMORY_H_
|
11
11
|
|
12
|
-
#include
|
12
|
+
#include <brotli/types.h>
|
13
13
|
#include "./port.h"
|
14
14
|
|
15
15
|
#if defined(__cplusplus) || defined(c_plusplus)
|
@@ -39,7 +39,8 @@ BROTLI_INTERNAL void BrotliInitMemoryManager(
|
|
39
39
|
void* opaque);
|
40
40
|
|
41
41
|
BROTLI_INTERNAL void* BrotliAllocate(MemoryManager* m, size_t n);
|
42
|
-
#define BROTLI_ALLOC(M, T, N)
|
42
|
+
#define BROTLI_ALLOC(M, T, N) \
|
43
|
+
((N) > 0 ? ((T*)BrotliAllocate((M), (N) * sizeof(T))) : NULL)
|
43
44
|
|
44
45
|
BROTLI_INTERNAL void BrotliFree(MemoryManager* m, void* p);
|
45
46
|
#define BROTLI_FREE(M, P) { \
|
@@ -10,7 +10,7 @@
|
|
10
10
|
#include "./metablock.h"
|
11
11
|
|
12
12
|
#include "../common/constants.h"
|
13
|
-
#include
|
13
|
+
#include <brotli/types.h>
|
14
14
|
#include "./bit_cost.h"
|
15
15
|
#include "./block_splitter.h"
|
16
16
|
#include "./cluster.h"
|
@@ -40,10 +40,11 @@ void BrotliBuildMetaBlock(MemoryManager* m,
|
|
40
40
|
static const size_t kMaxNumberOfHistograms = 256;
|
41
41
|
HistogramDistance* distance_histograms;
|
42
42
|
HistogramLiteral* literal_histograms;
|
43
|
-
ContextType* literal_context_modes;
|
44
|
-
size_t
|
45
|
-
size_t
|
43
|
+
ContextType* literal_context_modes = NULL;
|
44
|
+
size_t literal_histograms_size;
|
45
|
+
size_t distance_histograms_size;
|
46
46
|
size_t i;
|
47
|
+
size_t literal_context_multiplier = 1;
|
47
48
|
|
48
49
|
BrotliSplitBlock(m, cmds, num_commands,
|
49
50
|
ringbuffer, pos, mask, params,
|
@@ -52,20 +53,29 @@ void BrotliBuildMetaBlock(MemoryManager* m,
|
|
52
53
|
&mb->distance_split);
|
53
54
|
if (BROTLI_IS_OOM(m)) return;
|
54
55
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
56
|
+
if (!params->disable_literal_context_modeling) {
|
57
|
+
literal_context_multiplier = 1 << BROTLI_LITERAL_CONTEXT_BITS;
|
58
|
+
literal_context_modes =
|
59
|
+
BROTLI_ALLOC(m, ContextType, mb->literal_split.num_types);
|
60
|
+
if (BROTLI_IS_OOM(m)) return;
|
61
|
+
for (i = 0; i < mb->literal_split.num_types; ++i) {
|
62
|
+
literal_context_modes[i] = literal_context_mode;
|
63
|
+
}
|
60
64
|
}
|
61
65
|
|
62
|
-
|
63
|
-
mb->literal_split.num_types
|
64
|
-
|
66
|
+
literal_histograms_size =
|
67
|
+
mb->literal_split.num_types * literal_context_multiplier;
|
68
|
+
literal_histograms =
|
69
|
+
BROTLI_ALLOC(m, HistogramLiteral, literal_histograms_size);
|
70
|
+
if (BROTLI_IS_OOM(m)) return;
|
71
|
+
ClearHistogramsLiteral(literal_histograms, literal_histograms_size);
|
72
|
+
|
73
|
+
distance_histograms_size =
|
65
74
|
mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
|
66
|
-
|
75
|
+
distance_histograms =
|
76
|
+
BROTLI_ALLOC(m, HistogramDistance, distance_histograms_size);
|
67
77
|
if (BROTLI_IS_OOM(m)) return;
|
68
|
-
|
78
|
+
ClearHistogramsDistance(distance_histograms, distance_histograms_size);
|
69
79
|
|
70
80
|
assert(mb->command_histograms == 0);
|
71
81
|
mb->command_histograms_size = mb->command_split.num_types;
|
@@ -73,10 +83,7 @@ void BrotliBuildMetaBlock(MemoryManager* m,
|
|
73
83
|
BROTLI_ALLOC(m, HistogramCommand, mb->command_histograms_size);
|
74
84
|
if (BROTLI_IS_OOM(m)) return;
|
75
85
|
ClearHistogramsCommand(mb->command_histograms, mb->command_histograms_size);
|
76
|
-
|
77
|
-
BROTLI_ALLOC(m, HistogramDistance, num_distance_contexts);
|
78
|
-
if (BROTLI_IS_OOM(m)) return;
|
79
|
-
ClearHistogramsDistance(distance_histograms, num_distance_contexts);
|
86
|
+
|
80
87
|
BrotliBuildHistogramsWithContext(cmds, num_commands,
|
81
88
|
&mb->literal_split, &mb->command_split, &mb->distance_split,
|
82
89
|
ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_modes,
|
@@ -89,31 +96,44 @@ void BrotliBuildMetaBlock(MemoryManager* m,
|
|
89
96
|
mb->literal_context_map =
|
90
97
|
BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
|
91
98
|
if (BROTLI_IS_OOM(m)) return;
|
99
|
+
|
92
100
|
assert(mb->literal_histograms == 0);
|
93
101
|
mb->literal_histograms_size = mb->literal_context_map_size;
|
94
102
|
mb->literal_histograms =
|
95
103
|
BROTLI_ALLOC(m, HistogramLiteral, mb->literal_histograms_size);
|
96
104
|
if (BROTLI_IS_OOM(m)) return;
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
&mb->literal_histograms_size,
|
102
|
-
mb->literal_context_map);
|
105
|
+
|
106
|
+
BrotliClusterHistogramsLiteral(m, literal_histograms, literal_histograms_size,
|
107
|
+
kMaxNumberOfHistograms, mb->literal_histograms,
|
108
|
+
&mb->literal_histograms_size, mb->literal_context_map);
|
103
109
|
if (BROTLI_IS_OOM(m)) return;
|
104
110
|
BROTLI_FREE(m, literal_histograms);
|
105
111
|
|
112
|
+
if (params->disable_literal_context_modeling) {
|
113
|
+
/* Distribute assignment to all contexts. */
|
114
|
+
for (i = mb->literal_split.num_types; i != 0;) {
|
115
|
+
size_t j = 0;
|
116
|
+
i--;
|
117
|
+
for (; j < (1 << BROTLI_LITERAL_CONTEXT_BITS); j++) {
|
118
|
+
mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] =
|
119
|
+
mb->literal_context_map[i];
|
120
|
+
}
|
121
|
+
}
|
122
|
+
}
|
123
|
+
|
106
124
|
assert(mb->distance_context_map == 0);
|
107
125
|
mb->distance_context_map_size =
|
108
126
|
mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
|
109
127
|
mb->distance_context_map =
|
110
128
|
BROTLI_ALLOC(m, uint32_t, mb->distance_context_map_size);
|
111
129
|
if (BROTLI_IS_OOM(m)) return;
|
130
|
+
|
112
131
|
assert(mb->distance_histograms == 0);
|
113
132
|
mb->distance_histograms_size = mb->distance_context_map_size;
|
114
133
|
mb->distance_histograms =
|
115
134
|
BROTLI_ALLOC(m, HistogramDistance, mb->distance_histograms_size);
|
116
135
|
if (BROTLI_IS_OOM(m)) return;
|
136
|
+
|
117
137
|
BrotliClusterHistogramsDistance(m, distance_histograms,
|
118
138
|
mb->distance_context_map_size,
|
119
139
|
kMaxNumberOfHistograms,
|
@@ -136,53 +156,7 @@ void BrotliBuildMetaBlock(MemoryManager* m,
|
|
136
156
|
#include "./metablock_inc.h" /* NOLINT(build/include) */
|
137
157
|
#undef FN
|
138
158
|
|
139
|
-
|
140
|
-
const uint8_t* ringbuffer,
|
141
|
-
size_t pos,
|
142
|
-
size_t mask,
|
143
|
-
const Command *commands,
|
144
|
-
size_t n_commands,
|
145
|
-
MetaBlockSplit* mb) {
|
146
|
-
BlockSplitterLiteral lit_blocks;
|
147
|
-
BlockSplitterCommand cmd_blocks;
|
148
|
-
BlockSplitterDistance dist_blocks;
|
149
|
-
size_t num_literals = 0;
|
150
|
-
size_t i;
|
151
|
-
for (i = 0; i < n_commands; ++i) {
|
152
|
-
num_literals += commands[i].insert_len_;
|
153
|
-
}
|
154
|
-
|
155
|
-
InitBlockSplitterLiteral(m, &lit_blocks, 256, 512, 400.0, num_literals,
|
156
|
-
&mb->literal_split, &mb->literal_histograms,
|
157
|
-
&mb->literal_histograms_size);
|
158
|
-
if (BROTLI_IS_OOM(m)) return;
|
159
|
-
InitBlockSplitterCommand(m, &cmd_blocks, BROTLI_NUM_COMMAND_SYMBOLS, 1024,
|
160
|
-
500.0, n_commands, &mb->command_split, &mb->command_histograms,
|
161
|
-
&mb->command_histograms_size);
|
162
|
-
if (BROTLI_IS_OOM(m)) return;
|
163
|
-
InitBlockSplitterDistance(m, &dist_blocks, 64, 512, 100.0, n_commands,
|
164
|
-
&mb->distance_split, &mb->distance_histograms,
|
165
|
-
&mb->distance_histograms_size);
|
166
|
-
if (BROTLI_IS_OOM(m)) return;
|
167
|
-
|
168
|
-
for (i = 0; i < n_commands; ++i) {
|
169
|
-
const Command cmd = commands[i];
|
170
|
-
size_t j;
|
171
|
-
BlockSplitterAddSymbolCommand(&cmd_blocks, cmd.cmd_prefix_);
|
172
|
-
for (j = cmd.insert_len_; j != 0; --j) {
|
173
|
-
BlockSplitterAddSymbolLiteral(&lit_blocks, ringbuffer[pos & mask]);
|
174
|
-
++pos;
|
175
|
-
}
|
176
|
-
pos += CommandCopyLen(&cmd);
|
177
|
-
if (CommandCopyLen(&cmd) && cmd.cmd_prefix_ >= 128) {
|
178
|
-
BlockSplitterAddSymbolDistance(&dist_blocks, cmd.dist_prefix_);
|
179
|
-
}
|
180
|
-
}
|
181
|
-
|
182
|
-
BlockSplitterFinishBlockLiteral(&lit_blocks, /* is_final = */ BROTLI_TRUE);
|
183
|
-
BlockSplitterFinishBlockCommand(&cmd_blocks, /* is_final = */ BROTLI_TRUE);
|
184
|
-
BlockSplitterFinishBlockDistance(&dist_blocks, /* is_final = */ BROTLI_TRUE);
|
185
|
-
}
|
159
|
+
#define BROTLI_MAX_STATIC_CONTEXTS 13
|
186
160
|
|
187
161
|
/* Greedy block splitter for one block category (literal, command or distance).
|
188
162
|
Gathers histograms for all context buckets. */
|
@@ -214,7 +188,7 @@ typedef struct ContextBlockSplitter {
|
|
214
188
|
/* Offset of the histograms of the previous two block types. */
|
215
189
|
size_t last_histogram_ix_[2];
|
216
190
|
/* Entropy of the previous two block types. */
|
217
|
-
double*
|
191
|
+
double last_entropy_[2 * BROTLI_MAX_STATIC_CONTEXTS];
|
218
192
|
/* The number of times we merged the current block with the last one. */
|
219
193
|
size_t merge_last_count_;
|
220
194
|
} ContextBlockSplitter;
|
@@ -226,6 +200,7 @@ static void InitContextBlockSplitter(
|
|
226
200
|
size_t* histograms_size) {
|
227
201
|
size_t max_num_blocks = num_symbols / min_block_size + 1;
|
228
202
|
size_t max_num_types;
|
203
|
+
assert(num_contexts <= BROTLI_MAX_STATIC_CONTEXTS);
|
229
204
|
|
230
205
|
self->alphabet_size_ = alphabet_size;
|
231
206
|
self->num_contexts_ = num_contexts;
|
@@ -250,29 +225,23 @@ static void InitContextBlockSplitter(
|
|
250
225
|
split->lengths, split->lengths_alloc_size, max_num_blocks);
|
251
226
|
if (BROTLI_IS_OOM(m)) return;
|
252
227
|
split->num_blocks = max_num_blocks;
|
253
|
-
self->last_entropy_ = BROTLI_ALLOC(m, double, 2 * num_contexts);
|
254
228
|
if (BROTLI_IS_OOM(m)) return;
|
255
229
|
assert(*histograms == 0);
|
256
230
|
*histograms_size = max_num_types * num_contexts;
|
257
231
|
*histograms = BROTLI_ALLOC(m, HistogramLiteral, *histograms_size);
|
258
232
|
self->histograms_ = *histograms;
|
259
233
|
if (BROTLI_IS_OOM(m)) return;
|
260
|
-
/* Clear only current
|
234
|
+
/* Clear only current histogram. */
|
261
235
|
ClearHistogramsLiteral(&self->histograms_[0], num_contexts);
|
262
236
|
self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
|
263
237
|
}
|
264
238
|
|
265
|
-
static void CleanupContextBlockSplitter(
|
266
|
-
MemoryManager* m, ContextBlockSplitter* self) {
|
267
|
-
BROTLI_FREE(m, self->last_entropy_);
|
268
|
-
}
|
269
|
-
|
270
239
|
/* Does either of three things:
|
271
240
|
(1) emits the current block with a new block type;
|
272
241
|
(2) emits the current block with the type of the second last block;
|
273
242
|
(3) merges the current block with the last block. */
|
274
243
|
static void ContextBlockSplitterFinishBlock(
|
275
|
-
|
244
|
+
ContextBlockSplitter* self, MemoryManager* m, BROTLI_BOOL is_final) {
|
276
245
|
BlockSplit* split = self->split_;
|
277
246
|
const size_t num_contexts = self->num_contexts_;
|
278
247
|
double* last_entropy = self->last_entropy_;
|
@@ -305,10 +274,10 @@ static void ContextBlockSplitterFinishBlock(
|
|
305
274
|
respective set of histograms for the last and second last block types.
|
306
275
|
Decide over the split based on the total reduction of entropy across
|
307
276
|
all contexts. */
|
308
|
-
double
|
277
|
+
double entropy[BROTLI_MAX_STATIC_CONTEXTS];
|
309
278
|
HistogramLiteral* combined_histo =
|
310
279
|
BROTLI_ALLOC(m, HistogramLiteral, 2 * num_contexts);
|
311
|
-
double
|
280
|
+
double combined_entropy[2 * BROTLI_MAX_STATIC_CONTEXTS];
|
312
281
|
double diff[2] = { 0.0 };
|
313
282
|
size_t i;
|
314
283
|
if (BROTLI_IS_OOM(m)) return;
|
@@ -383,9 +352,7 @@ static void ContextBlockSplitterFinishBlock(
|
|
383
352
|
self->target_block_size_ += self->min_block_size_;
|
384
353
|
}
|
385
354
|
}
|
386
|
-
BROTLI_FREE(m, combined_entropy);
|
387
355
|
BROTLI_FREE(m, combined_histo);
|
388
|
-
BROTLI_FREE(m, entropy);
|
389
356
|
}
|
390
357
|
if (is_final) {
|
391
358
|
*self->histograms_size_ = split->num_types * num_contexts;
|
@@ -395,30 +362,49 @@ static void ContextBlockSplitterFinishBlock(
|
|
395
362
|
|
396
363
|
/* Adds the next symbol to the current block type and context. When the
|
397
364
|
current block reaches the target size, decides on merging the block. */
|
398
|
-
static void ContextBlockSplitterAddSymbol(
|
399
|
-
ContextBlockSplitter* self,
|
365
|
+
static void ContextBlockSplitterAddSymbol(
|
366
|
+
ContextBlockSplitter* self, MemoryManager* m,
|
367
|
+
size_t symbol, size_t context) {
|
400
368
|
HistogramAddLiteral(&self->histograms_[self->curr_histogram_ix_ + context],
|
401
369
|
symbol);
|
402
370
|
++self->block_size_;
|
403
371
|
if (self->block_size_ == self->target_block_size_) {
|
404
|
-
ContextBlockSplitterFinishBlock(
|
372
|
+
ContextBlockSplitterFinishBlock(self, m, /* is_final = */ BROTLI_FALSE);
|
405
373
|
if (BROTLI_IS_OOM(m)) return;
|
406
374
|
}
|
407
375
|
}
|
408
376
|
|
409
|
-
void
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
377
|
+
static void MapStaticContexts(MemoryManager* m,
|
378
|
+
size_t num_contexts,
|
379
|
+
const uint32_t* static_context_map,
|
380
|
+
MetaBlockSplit* mb) {
|
381
|
+
size_t i;
|
382
|
+
assert(mb->literal_context_map == 0);
|
383
|
+
mb->literal_context_map_size =
|
384
|
+
mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
|
385
|
+
mb->literal_context_map =
|
386
|
+
BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
|
387
|
+
if (BROTLI_IS_OOM(m)) return;
|
388
|
+
|
389
|
+
for (i = 0; i < mb->literal_split.num_types; ++i) {
|
390
|
+
uint32_t offset = (uint32_t)(i * num_contexts);
|
391
|
+
size_t j;
|
392
|
+
for (j = 0; j < (1u << BROTLI_LITERAL_CONTEXT_BITS); ++j) {
|
393
|
+
mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] =
|
394
|
+
offset + static_context_map[j];
|
395
|
+
}
|
396
|
+
}
|
397
|
+
}
|
398
|
+
|
399
|
+
static BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal(
|
400
|
+
MemoryManager* m, const uint8_t* ringbuffer, size_t pos, size_t mask,
|
401
|
+
uint8_t prev_byte, uint8_t prev_byte2, ContextType literal_context_mode,
|
402
|
+
const size_t num_contexts, const uint32_t* static_context_map,
|
403
|
+
const Command *commands, size_t n_commands, MetaBlockSplit* mb) {
|
404
|
+
union {
|
405
|
+
BlockSplitterLiteral plain;
|
406
|
+
ContextBlockSplitter ctx;
|
407
|
+
} lit_blocks;
|
422
408
|
BlockSplitterCommand cmd_blocks;
|
423
409
|
BlockSplitterDistance dist_blocks;
|
424
410
|
size_t num_literals = 0;
|
@@ -427,9 +413,15 @@ void BrotliBuildMetaBlockGreedyWithContexts(MemoryManager* m,
|
|
427
413
|
num_literals += commands[i].insert_len_;
|
428
414
|
}
|
429
415
|
|
430
|
-
|
431
|
-
|
432
|
-
|
416
|
+
if (num_contexts == 1) {
|
417
|
+
InitBlockSplitterLiteral(m, &lit_blocks.plain, 256, 512, 400.0,
|
418
|
+
num_literals, &mb->literal_split, &mb->literal_histograms,
|
419
|
+
&mb->literal_histograms_size);
|
420
|
+
} else {
|
421
|
+
InitContextBlockSplitter(m, &lit_blocks.ctx, 256, num_contexts, 512, 400.0,
|
422
|
+
num_literals, &mb->literal_split, &mb->literal_histograms,
|
423
|
+
&mb->literal_histograms_size);
|
424
|
+
}
|
433
425
|
if (BROTLI_IS_OOM(m)) return;
|
434
426
|
InitBlockSplitterCommand(m, &cmd_blocks, BROTLI_NUM_COMMAND_SYMBOLS, 1024,
|
435
427
|
500.0, n_commands, &mb->command_split, &mb->command_histograms,
|
@@ -445,12 +437,16 @@ void BrotliBuildMetaBlockGreedyWithContexts(MemoryManager* m,
|
|
445
437
|
size_t j;
|
446
438
|
BlockSplitterAddSymbolCommand(&cmd_blocks, cmd.cmd_prefix_);
|
447
439
|
for (j = cmd.insert_len_; j != 0; --j) {
|
448
|
-
size_t context = Context(prev_byte, prev_byte2, literal_context_mode);
|
449
440
|
uint8_t literal = ringbuffer[pos & mask];
|
450
|
-
|
451
|
-
|
441
|
+
if (num_contexts == 1) {
|
442
|
+
BlockSplitterAddSymbolLiteral(&lit_blocks.plain, literal);
|
443
|
+
} else {
|
444
|
+
size_t context = Context(prev_byte, prev_byte2, literal_context_mode);
|
445
|
+
ContextBlockSplitterAddSymbol(&lit_blocks.ctx, m, literal,
|
446
|
+
static_context_map[context]);
|
447
|
+
if (BROTLI_IS_OOM(m)) return;
|
448
|
+
}
|
452
449
|
prev_byte2 = prev_byte;
|
453
|
-
if (BROTLI_IS_OOM(m)) return;
|
454
450
|
prev_byte = literal;
|
455
451
|
++pos;
|
456
452
|
}
|
@@ -464,25 +460,41 @@ void BrotliBuildMetaBlockGreedyWithContexts(MemoryManager* m,
|
|
464
460
|
}
|
465
461
|
}
|
466
462
|
|
467
|
-
|
468
|
-
|
469
|
-
|
463
|
+
if (num_contexts == 1) {
|
464
|
+
BlockSplitterFinishBlockLiteral(
|
465
|
+
&lit_blocks.plain, /* is_final = */ BROTLI_TRUE);
|
466
|
+
} else {
|
467
|
+
ContextBlockSplitterFinishBlock(
|
468
|
+
&lit_blocks.ctx, m, /* is_final = */ BROTLI_TRUE);
|
469
|
+
if (BROTLI_IS_OOM(m)) return;
|
470
|
+
}
|
470
471
|
BlockSplitterFinishBlockCommand(&cmd_blocks, /* is_final = */ BROTLI_TRUE);
|
471
472
|
BlockSplitterFinishBlockDistance(&dist_blocks, /* is_final = */ BROTLI_TRUE);
|
472
473
|
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
|
478
|
-
if (BROTLI_IS_OOM(m)) return;
|
474
|
+
if (num_contexts > 1) {
|
475
|
+
MapStaticContexts(m, num_contexts, static_context_map, mb);
|
476
|
+
}
|
477
|
+
}
|
479
478
|
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
479
|
+
void BrotliBuildMetaBlockGreedy(MemoryManager* m,
|
480
|
+
const uint8_t* ringbuffer,
|
481
|
+
size_t pos,
|
482
|
+
size_t mask,
|
483
|
+
uint8_t prev_byte,
|
484
|
+
uint8_t prev_byte2,
|
485
|
+
ContextType literal_context_mode,
|
486
|
+
size_t num_contexts,
|
487
|
+
const uint32_t* static_context_map,
|
488
|
+
const Command* commands,
|
489
|
+
size_t n_commands,
|
490
|
+
MetaBlockSplit* mb) {
|
491
|
+
if (num_contexts == 1) {
|
492
|
+
BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte,
|
493
|
+
prev_byte2, literal_context_mode, 1, NULL, commands, n_commands, mb);
|
494
|
+
} else {
|
495
|
+
BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte,
|
496
|
+
prev_byte2, literal_context_mode, num_contexts, static_context_map,
|
497
|
+
commands, n_commands, mb);
|
486
498
|
}
|
487
499
|
}
|
488
500
|
|
@@ -502,7 +514,8 @@ void BrotliOptimizeHistograms(size_t num_direct_distance_codes,
|
|
502
514
|
good_for_rle);
|
503
515
|
}
|
504
516
|
num_distance_codes = BROTLI_NUM_DISTANCE_SHORT_CODES +
|
505
|
-
num_direct_distance_codes +
|
517
|
+
num_direct_distance_codes +
|
518
|
+
((2 * BROTLI_MAX_DISTANCE_BITS) << distance_postfix_bits);
|
506
519
|
for (i = 0; i < mb->distance_histograms_size; ++i) {
|
507
520
|
BrotliOptimizeHuffmanCountsForRle(num_distance_codes,
|
508
521
|
mb->distance_histograms[i].data_,
|