brotli 0.1.1 → 0.1.2
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/ext/brotli/brotli.cc +114 -24
- data/ext/brotli/brotli.h +0 -1
- data/ext/brotli/extconf.rb +30 -23
- data/lib/brotli/version.rb +1 -1
- data/vendor/brotli/LICENSE +1 -1
- data/vendor/brotli/dec/Makefile +1 -1
- data/vendor/brotli/dec/bit_reader.c +3 -3
- data/vendor/brotli/dec/bit_reader.h +25 -27
- data/vendor/brotli/dec/context.h +4 -4
- data/vendor/brotli/dec/decode.c +410 -486
- data/vendor/brotli/dec/decode.h +101 -105
- data/vendor/brotli/dec/dictionary.c +1 -1
- data/vendor/brotli/dec/dictionary.h +7 -8
- data/vendor/brotli/dec/huffman.c +103 -105
- data/vendor/brotli/dec/huffman.h +18 -18
- data/vendor/brotli/dec/port.h +52 -40
- data/vendor/brotli/dec/prefix.h +2 -0
- data/vendor/brotli/dec/state.c +13 -19
- data/vendor/brotli/dec/state.h +25 -39
- data/vendor/brotli/dec/transform.h +38 -44
- data/vendor/brotli/dec/types.h +2 -2
- data/vendor/brotli/enc/Makefile +1 -1
- data/vendor/brotli/enc/backward_references.cc +455 -359
- data/vendor/brotli/enc/backward_references.h +79 -3
- data/vendor/brotli/enc/bit_cost.h +54 -32
- data/vendor/brotli/enc/block_splitter.cc +285 -193
- data/vendor/brotli/enc/block_splitter.h +4 -12
- data/vendor/brotli/enc/brotli_bit_stream.cc +623 -324
- data/vendor/brotli/enc/brotli_bit_stream.h +76 -37
- data/vendor/brotli/enc/cluster.h +161 -120
- data/vendor/brotli/enc/command.h +60 -37
- data/vendor/brotli/enc/compress_fragment.cc +701 -0
- data/vendor/brotli/enc/compress_fragment.h +47 -0
- data/vendor/brotli/enc/compress_fragment_two_pass.cc +524 -0
- data/vendor/brotli/enc/compress_fragment_two_pass.h +40 -0
- data/vendor/brotli/enc/compressor.h +15 -0
- data/vendor/brotli/enc/context.h +1 -1
- data/vendor/brotli/enc/dictionary.h +2 -2
- data/vendor/brotli/enc/encode.cc +819 -286
- data/vendor/brotli/enc/encode.h +38 -15
- data/vendor/brotli/enc/encode_parallel.cc +40 -42
- data/vendor/brotli/enc/entropy_encode.cc +144 -147
- data/vendor/brotli/enc/entropy_encode.h +32 -8
- data/vendor/brotli/enc/entropy_encode_static.h +572 -0
- data/vendor/brotli/enc/fast_log.h +7 -40
- data/vendor/brotli/enc/find_match_length.h +9 -9
- data/vendor/brotli/enc/hash.h +462 -154
- data/vendor/brotli/enc/histogram.cc +6 -6
- data/vendor/brotli/enc/histogram.h +13 -13
- data/vendor/brotli/enc/literal_cost.cc +45 -45
- data/vendor/brotli/enc/metablock.cc +92 -89
- data/vendor/brotli/enc/metablock.h +12 -12
- data/vendor/brotli/enc/port.h +7 -16
- data/vendor/brotli/enc/prefix.h +23 -22
- data/vendor/brotli/enc/ringbuffer.h +75 -29
- data/vendor/brotli/enc/static_dict.cc +56 -48
- data/vendor/brotli/enc/static_dict.h +5 -5
- data/vendor/brotli/enc/streams.cc +1 -1
- data/vendor/brotli/enc/streams.h +5 -5
- data/vendor/brotli/enc/transform.h +40 -35
- data/vendor/brotli/enc/types.h +2 -0
- data/vendor/brotli/enc/utf8_util.cc +3 -2
- data/vendor/brotli/enc/write_bits.h +6 -6
- metadata +9 -5
- data/vendor/brotli/dec/streams.c +0 -102
- data/vendor/brotli/dec/streams.h +0 -95
@@ -11,70 +11,86 @@
|
|
11
11
|
#include "./brotli_bit_stream.h"
|
12
12
|
|
13
13
|
#include <algorithm>
|
14
|
+
#include <cstdlib> /* free, malloc */
|
15
|
+
#include <cstring>
|
14
16
|
#include <limits>
|
15
17
|
#include <vector>
|
16
18
|
|
17
19
|
#include "./bit_cost.h"
|
18
20
|
#include "./context.h"
|
19
21
|
#include "./entropy_encode.h"
|
22
|
+
#include "./entropy_encode_static.h"
|
20
23
|
#include "./fast_log.h"
|
21
24
|
#include "./prefix.h"
|
22
25
|
#include "./write_bits.h"
|
26
|
+
|
23
27
|
namespace brotli {
|
24
28
|
|
25
|
-
|
29
|
+
namespace {
|
30
|
+
|
31
|
+
static const size_t kMaxHuffmanTreeSize = 2 * kNumCommandPrefixes + 1;
|
32
|
+
// Context map alphabet has 256 context id symbols plus max 16 rle symbols.
|
33
|
+
static const size_t kContextMapAlphabetSize = 256 + 16;
|
34
|
+
// Block type alphabet has 256 block id symbols plus 2 special symbols.
|
35
|
+
static const size_t kBlockTypeAlphabetSize = 256 + 2;
|
36
|
+
|
26
37
|
// nibblesbits represents the 2 bits to encode MNIBBLES (0-3)
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
38
|
+
// REQUIRES: length > 0
|
39
|
+
// REQUIRES: length <= (1 << 24)
|
40
|
+
void EncodeMlen(size_t length, uint64_t* bits,
|
41
|
+
size_t* numbits, uint64_t* nibblesbits) {
|
42
|
+
assert(length > 0);
|
43
|
+
assert(length <= (1 << 24));
|
31
44
|
length--; // MLEN - 1 is encoded
|
32
|
-
|
45
|
+
size_t lg = length == 0 ? 1 : Log2FloorNonZero(
|
46
|
+
static_cast<uint32_t>(length)) + 1;
|
33
47
|
assert(lg <= 24);
|
34
|
-
|
48
|
+
size_t mnibbles = (lg < 16 ? 16 : (lg + 3)) / 4;
|
35
49
|
*nibblesbits = mnibbles - 4;
|
36
50
|
*numbits = mnibbles * 4;
|
37
|
-
*bits =
|
38
|
-
return true;
|
51
|
+
*bits = length;
|
39
52
|
}
|
40
53
|
|
41
|
-
void
|
54
|
+
static inline void StoreCommandExtra(
|
55
|
+
const Command& cmd, size_t* storage_ix, uint8_t* storage) {
|
56
|
+
uint32_t copylen_code = cmd.copy_len_code();
|
57
|
+
uint16_t inscode = GetInsertLengthCode(cmd.insert_len_);
|
58
|
+
uint16_t copycode = GetCopyLengthCode(copylen_code);
|
59
|
+
uint32_t insnumextra = GetInsertExtra(inscode);
|
60
|
+
uint64_t insextraval = cmd.insert_len_ - GetInsertBase(inscode);
|
61
|
+
uint64_t copyextraval = copylen_code - GetCopyBase(copycode);
|
62
|
+
uint64_t bits = (copyextraval << insnumextra) | insextraval;
|
63
|
+
WriteBits(insnumextra + GetCopyExtra(copycode), bits, storage_ix, storage);
|
64
|
+
}
|
65
|
+
|
66
|
+
} // namespace
|
67
|
+
|
68
|
+
void StoreVarLenUint8(size_t n, size_t* storage_ix, uint8_t* storage) {
|
42
69
|
if (n == 0) {
|
43
70
|
WriteBits(1, 0, storage_ix, storage);
|
44
71
|
} else {
|
45
72
|
WriteBits(1, 1, storage_ix, storage);
|
46
|
-
|
73
|
+
size_t nbits = Log2FloorNonZero(n);
|
47
74
|
WriteBits(3, nbits, storage_ix, storage);
|
48
75
|
WriteBits(nbits, n - (1 << nbits), storage_ix, storage);
|
49
76
|
}
|
50
77
|
}
|
51
78
|
|
52
|
-
|
79
|
+
void StoreCompressedMetaBlockHeader(bool final_block,
|
53
80
|
size_t length,
|
54
|
-
|
81
|
+
size_t* storage_ix,
|
55
82
|
uint8_t* storage) {
|
56
83
|
// Write ISLAST bit.
|
57
84
|
WriteBits(1, final_block, storage_ix, storage);
|
58
85
|
// Write ISEMPTY bit.
|
59
86
|
if (final_block) {
|
60
|
-
WriteBits(1,
|
61
|
-
if (length == 0) {
|
62
|
-
return true;
|
63
|
-
}
|
64
|
-
}
|
65
|
-
|
66
|
-
if (length == 0) {
|
67
|
-
// Only the last meta-block can be empty.
|
68
|
-
return false;
|
69
|
-
}
|
70
|
-
|
71
|
-
int lenbits;
|
72
|
-
int nlenbits;
|
73
|
-
int nibblesbits;
|
74
|
-
if (!EncodeMlen(length, &lenbits, &nlenbits, &nibblesbits)) {
|
75
|
-
return false;
|
87
|
+
WriteBits(1, 0, storage_ix, storage);
|
76
88
|
}
|
77
89
|
|
90
|
+
uint64_t lenbits;
|
91
|
+
size_t nlenbits;
|
92
|
+
uint64_t nibblesbits;
|
93
|
+
EncodeMlen(length, &lenbits, &nlenbits, &nibblesbits);
|
78
94
|
WriteBits(2, nibblesbits, storage_ix, storage);
|
79
95
|
WriteBits(nlenbits, lenbits, storage_ix, storage);
|
80
96
|
|
@@ -82,31 +98,27 @@ bool StoreCompressedMetaBlockHeader(bool final_block,
|
|
82
98
|
// Write ISUNCOMPRESSED bit.
|
83
99
|
WriteBits(1, 0, storage_ix, storage);
|
84
100
|
}
|
85
|
-
return true;
|
86
101
|
}
|
87
102
|
|
88
|
-
|
89
|
-
|
103
|
+
void StoreUncompressedMetaBlockHeader(size_t length,
|
104
|
+
size_t* storage_ix,
|
90
105
|
uint8_t* storage) {
|
91
106
|
// Write ISLAST bit. Uncompressed block cannot be the last one, so set to 0.
|
92
107
|
WriteBits(1, 0, storage_ix, storage);
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
return false;
|
98
|
-
}
|
108
|
+
uint64_t lenbits;
|
109
|
+
size_t nlenbits;
|
110
|
+
uint64_t nibblesbits;
|
111
|
+
EncodeMlen(length, &lenbits, &nlenbits, &nibblesbits);
|
99
112
|
WriteBits(2, nibblesbits, storage_ix, storage);
|
100
113
|
WriteBits(nlenbits, lenbits, storage_ix, storage);
|
101
114
|
// Write ISUNCOMPRESSED bit.
|
102
115
|
WriteBits(1, 1, storage_ix, storage);
|
103
|
-
return true;
|
104
116
|
}
|
105
117
|
|
106
118
|
void StoreHuffmanTreeOfHuffmanTreeToBitMask(
|
107
119
|
const int num_codes,
|
108
120
|
const uint8_t *code_length_bitdepth,
|
109
|
-
|
121
|
+
size_t *storage_ix,
|
110
122
|
uint8_t *storage) {
|
111
123
|
static const uint8_t kStorageOrder[kCodeLengthCodes] = {
|
112
124
|
1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
@@ -129,7 +141,7 @@ void StoreHuffmanTreeOfHuffmanTreeToBitMask(
|
|
129
141
|
};
|
130
142
|
|
131
143
|
// Throw away trailing zeros:
|
132
|
-
|
144
|
+
size_t codes_to_store = kCodeLengthCodes;
|
133
145
|
if (num_codes > 1) {
|
134
146
|
for (; codes_to_store > 0; --codes_to_store) {
|
135
147
|
if (code_length_bitdepth[kStorageOrder[codes_to_store - 1]] != 0) {
|
@@ -137,7 +149,7 @@ void StoreHuffmanTreeOfHuffmanTreeToBitMask(
|
|
137
149
|
}
|
138
150
|
}
|
139
151
|
}
|
140
|
-
|
152
|
+
size_t skip_some = 0; // skips none.
|
141
153
|
if (code_length_bitdepth[kStorageOrder[0]] == 0 &&
|
142
154
|
code_length_bitdepth[kStorageOrder[1]] == 0) {
|
143
155
|
skip_some = 2; // skips two.
|
@@ -146,22 +158,23 @@ void StoreHuffmanTreeOfHuffmanTreeToBitMask(
|
|
146
158
|
}
|
147
159
|
}
|
148
160
|
WriteBits(2, skip_some, storage_ix, storage);
|
149
|
-
for (
|
150
|
-
|
161
|
+
for (size_t i = skip_some; i < codes_to_store; ++i) {
|
162
|
+
size_t l = code_length_bitdepth[kStorageOrder[i]];
|
151
163
|
WriteBits(kHuffmanBitLengthHuffmanCodeBitLengths[l],
|
152
164
|
kHuffmanBitLengthHuffmanCodeSymbols[l], storage_ix, storage);
|
153
165
|
}
|
154
166
|
}
|
155
167
|
|
156
|
-
void StoreHuffmanTreeToBitMask(
|
157
|
-
const
|
158
|
-
const
|
159
|
-
const uint8_t
|
160
|
-
const
|
161
|
-
|
168
|
+
static void StoreHuffmanTreeToBitMask(
|
169
|
+
const size_t huffman_tree_size,
|
170
|
+
const uint8_t* huffman_tree,
|
171
|
+
const uint8_t* huffman_tree_extra_bits,
|
172
|
+
const uint8_t* code_length_bitdepth,
|
173
|
+
const uint16_t* code_length_bitdepth_symbols,
|
174
|
+
size_t * __restrict storage_ix,
|
162
175
|
uint8_t * __restrict storage) {
|
163
|
-
for (size_t i = 0; i <
|
164
|
-
|
176
|
+
for (size_t i = 0; i < huffman_tree_size; ++i) {
|
177
|
+
size_t ix = huffman_tree[i];
|
165
178
|
WriteBits(code_length_bitdepth[ix], code_length_bitdepth_symbols[ix],
|
166
179
|
storage_ix, storage);
|
167
180
|
// Extra bits
|
@@ -176,18 +189,18 @@ void StoreHuffmanTreeToBitMask(
|
|
176
189
|
}
|
177
190
|
}
|
178
191
|
|
179
|
-
void StoreSimpleHuffmanTree(const uint8_t* depths,
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
192
|
+
static void StoreSimpleHuffmanTree(const uint8_t* depths,
|
193
|
+
size_t symbols[4],
|
194
|
+
size_t num_symbols,
|
195
|
+
size_t max_bits,
|
196
|
+
size_t *storage_ix, uint8_t *storage) {
|
184
197
|
// value of 1 indicates a simple Huffman code
|
185
198
|
WriteBits(2, 1, storage_ix, storage);
|
186
199
|
WriteBits(2, num_symbols - 1, storage_ix, storage); // NSYM - 1
|
187
200
|
|
188
201
|
// Sort
|
189
|
-
for (
|
190
|
-
for (
|
202
|
+
for (size_t i = 0; i < num_symbols; i++) {
|
203
|
+
for (size_t j = i + 1; j < num_symbols; j++) {
|
191
204
|
if (depths[symbols[j]] < depths[symbols[i]]) {
|
192
205
|
std::swap(symbols[j], symbols[i]);
|
193
206
|
}
|
@@ -213,19 +226,22 @@ void StoreSimpleHuffmanTree(const uint8_t* depths,
|
|
213
226
|
|
214
227
|
// num = alphabet size
|
215
228
|
// depths = symbol depths
|
216
|
-
void StoreHuffmanTree(const uint8_t* depths,
|
217
|
-
|
229
|
+
void StoreHuffmanTree(const uint8_t* depths, size_t num,
|
230
|
+
HuffmanTree* tree,
|
231
|
+
size_t *storage_ix, uint8_t *storage) {
|
218
232
|
// Write the Huffman tree into the brotli-representation.
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
huffman_tree
|
223
|
-
huffman_tree_extra_bits
|
224
|
-
|
233
|
+
// The command alphabet is the largest, so this allocation will fit all
|
234
|
+
// alphabets.
|
235
|
+
assert(num <= kNumCommandPrefixes);
|
236
|
+
uint8_t huffman_tree[kNumCommandPrefixes];
|
237
|
+
uint8_t huffman_tree_extra_bits[kNumCommandPrefixes];
|
238
|
+
size_t huffman_tree_size = 0;
|
239
|
+
WriteHuffmanTree(depths, num, &huffman_tree_size, huffman_tree,
|
240
|
+
huffman_tree_extra_bits);
|
225
241
|
|
226
242
|
// Calculate the statistics of the Huffman tree in brotli-representation.
|
227
|
-
|
228
|
-
for (size_t i = 0; i <
|
243
|
+
uint32_t huffman_tree_histogram[kCodeLengthCodes] = { 0 };
|
244
|
+
for (size_t i = 0; i < huffman_tree_size; ++i) {
|
229
245
|
++huffman_tree_histogram[huffman_tree[i]];
|
230
246
|
}
|
231
247
|
|
@@ -245,11 +261,10 @@ void StoreHuffmanTree(const uint8_t* depths, int num,
|
|
245
261
|
|
246
262
|
// Calculate another Huffman tree to use for compressing both the
|
247
263
|
// earlier Huffman tree with.
|
248
|
-
// TODO: Consider allocating these from stack.
|
249
264
|
uint8_t code_length_bitdepth[kCodeLengthCodes] = { 0 };
|
250
|
-
|
265
|
+
uint16_t code_length_bitdepth_symbols[kCodeLengthCodes] = { 0 };
|
251
266
|
CreateHuffmanTree(&huffman_tree_histogram[0], kCodeLengthCodes,
|
252
|
-
5, &code_length_bitdepth[0]);
|
267
|
+
5, tree, &code_length_bitdepth[0]);
|
253
268
|
ConvertBitDepthsToSymbols(code_length_bitdepth, kCodeLengthCodes,
|
254
269
|
&code_length_bitdepth_symbols[0]);
|
255
270
|
|
@@ -262,23 +277,24 @@ void StoreHuffmanTree(const uint8_t* depths, int num,
|
|
262
277
|
}
|
263
278
|
|
264
279
|
// Store the real huffman tree now.
|
265
|
-
StoreHuffmanTreeToBitMask(
|
280
|
+
StoreHuffmanTreeToBitMask(huffman_tree_size,
|
281
|
+
huffman_tree,
|
266
282
|
huffman_tree_extra_bits,
|
267
283
|
&code_length_bitdepth[0],
|
268
284
|
code_length_bitdepth_symbols,
|
269
285
|
storage_ix, storage);
|
270
286
|
}
|
271
287
|
|
272
|
-
|
273
|
-
|
274
|
-
|
288
|
+
void BuildAndStoreHuffmanTree(const uint32_t *histogram,
|
289
|
+
const size_t length,
|
290
|
+
HuffmanTree* tree,
|
275
291
|
uint8_t* depth,
|
276
292
|
uint16_t* bits,
|
277
|
-
|
293
|
+
size_t* storage_ix,
|
278
294
|
uint8_t* storage) {
|
279
|
-
|
280
|
-
|
281
|
-
for (
|
295
|
+
size_t count = 0;
|
296
|
+
size_t s4[4] = { 0 };
|
297
|
+
for (size_t i = 0; i < length; i++) {
|
282
298
|
if (histogram[i]) {
|
283
299
|
if (count < 4) {
|
284
300
|
s4[count] = i;
|
@@ -289,8 +305,8 @@ void BuildAndStoreHuffmanTree(const int *histogram,
|
|
289
305
|
}
|
290
306
|
}
|
291
307
|
|
292
|
-
|
293
|
-
|
308
|
+
size_t max_bits_counter = length - 1;
|
309
|
+
size_t max_bits = 0;
|
294
310
|
while (max_bits_counter) {
|
295
311
|
max_bits_counter >>= 1;
|
296
312
|
++max_bits;
|
@@ -302,179 +318,365 @@ void BuildAndStoreHuffmanTree(const int *histogram,
|
|
302
318
|
return;
|
303
319
|
}
|
304
320
|
|
305
|
-
CreateHuffmanTree(histogram, length, 15, depth);
|
321
|
+
CreateHuffmanTree(histogram, length, 15, tree, depth);
|
306
322
|
ConvertBitDepthsToSymbols(depth, length, bits);
|
307
323
|
|
308
324
|
if (count <= 4) {
|
309
325
|
StoreSimpleHuffmanTree(depth, s4, count, max_bits, storage_ix, storage);
|
310
326
|
} else {
|
311
|
-
StoreHuffmanTree(depth, length, storage_ix, storage);
|
327
|
+
StoreHuffmanTree(depth, length, tree, storage_ix, storage);
|
328
|
+
}
|
329
|
+
}
|
330
|
+
|
331
|
+
static inline bool SortHuffmanTree(const HuffmanTree& v0,
|
332
|
+
const HuffmanTree& v1) {
|
333
|
+
return v0.total_count_ < v1.total_count_;
|
334
|
+
}
|
335
|
+
|
336
|
+
void BuildAndStoreHuffmanTreeFast(const uint32_t *histogram,
|
337
|
+
const size_t histogram_total,
|
338
|
+
const size_t max_bits,
|
339
|
+
uint8_t* depth,
|
340
|
+
uint16_t* bits,
|
341
|
+
size_t* storage_ix,
|
342
|
+
uint8_t* storage) {
|
343
|
+
size_t count = 0;
|
344
|
+
size_t symbols[4] = { 0 };
|
345
|
+
size_t length = 0;
|
346
|
+
size_t total = histogram_total;
|
347
|
+
while (total != 0) {
|
348
|
+
if (histogram[length]) {
|
349
|
+
if (count < 4) {
|
350
|
+
symbols[count] = length;
|
351
|
+
}
|
352
|
+
++count;
|
353
|
+
total -= histogram[length];
|
354
|
+
}
|
355
|
+
++length;
|
356
|
+
}
|
357
|
+
|
358
|
+
if (count <= 1) {
|
359
|
+
WriteBits(4, 1, storage_ix, storage);
|
360
|
+
WriteBits(max_bits, symbols[0], storage_ix, storage);
|
361
|
+
return;
|
362
|
+
}
|
363
|
+
|
364
|
+
const size_t max_tree_size = 2 * length + 1;
|
365
|
+
HuffmanTree* const tree =
|
366
|
+
static_cast<HuffmanTree*>(malloc(max_tree_size * sizeof(HuffmanTree)));
|
367
|
+
for (uint32_t count_limit = 1; ; count_limit *= 2) {
|
368
|
+
HuffmanTree* node = tree;
|
369
|
+
for (size_t i = length; i != 0;) {
|
370
|
+
--i;
|
371
|
+
if (histogram[i]) {
|
372
|
+
if (PREDICT_TRUE(histogram[i] >= count_limit)) {
|
373
|
+
*node = HuffmanTree(histogram[i], -1, static_cast<int16_t>(i));
|
374
|
+
} else {
|
375
|
+
*node = HuffmanTree(count_limit, -1, static_cast<int16_t>(i));
|
376
|
+
}
|
377
|
+
++node;
|
378
|
+
}
|
379
|
+
}
|
380
|
+
const int n = static_cast<int>(node - tree);
|
381
|
+
std::sort(tree, node, SortHuffmanTree);
|
382
|
+
// The nodes are:
|
383
|
+
// [0, n): the sorted leaf nodes that we start with.
|
384
|
+
// [n]: we add a sentinel here.
|
385
|
+
// [n + 1, 2n): new parent nodes are added here, starting from
|
386
|
+
// (n+1). These are naturally in ascending order.
|
387
|
+
// [2n]: we add a sentinel at the end as well.
|
388
|
+
// There will be (2n+1) elements at the end.
|
389
|
+
const HuffmanTree sentinel(std::numeric_limits<int>::max(), -1, -1);
|
390
|
+
*node++ = sentinel;
|
391
|
+
*node++ = sentinel;
|
392
|
+
|
393
|
+
int i = 0; // Points to the next leaf node.
|
394
|
+
int j = n + 1; // Points to the next non-leaf node.
|
395
|
+
for (int k = n - 1; k > 0; --k) {
|
396
|
+
int left, right;
|
397
|
+
if (tree[i].total_count_ <= tree[j].total_count_) {
|
398
|
+
left = i;
|
399
|
+
++i;
|
400
|
+
} else {
|
401
|
+
left = j;
|
402
|
+
++j;
|
403
|
+
}
|
404
|
+
if (tree[i].total_count_ <= tree[j].total_count_) {
|
405
|
+
right = i;
|
406
|
+
++i;
|
407
|
+
} else {
|
408
|
+
right = j;
|
409
|
+
++j;
|
410
|
+
}
|
411
|
+
// The sentinel node becomes the parent node.
|
412
|
+
node[-1].total_count_ =
|
413
|
+
tree[left].total_count_ + tree[right].total_count_;
|
414
|
+
node[-1].index_left_ = static_cast<int16_t>(left);
|
415
|
+
node[-1].index_right_or_value_ = static_cast<int16_t>(right);
|
416
|
+
// Add back the last sentinel node.
|
417
|
+
*node++ = sentinel;
|
418
|
+
}
|
419
|
+
SetDepth(tree[2 * n - 1], &tree[0], depth, 0);
|
420
|
+
// We need to pack the Huffman tree in 14 bits.
|
421
|
+
// If this was not successful, add fake entities to the lowest values
|
422
|
+
// and retry.
|
423
|
+
if (PREDICT_TRUE(*std::max_element(&depth[0], &depth[length]) <= 14)) {
|
424
|
+
break;
|
425
|
+
}
|
426
|
+
}
|
427
|
+
free(tree);
|
428
|
+
ConvertBitDepthsToSymbols(depth, length, bits);
|
429
|
+
if (count <= 4) {
|
430
|
+
// value of 1 indicates a simple Huffman code
|
431
|
+
WriteBits(2, 1, storage_ix, storage);
|
432
|
+
WriteBits(2, count - 1, storage_ix, storage); // NSYM - 1
|
433
|
+
|
434
|
+
// Sort
|
435
|
+
for (size_t i = 0; i < count; i++) {
|
436
|
+
for (size_t j = i + 1; j < count; j++) {
|
437
|
+
if (depth[symbols[j]] < depth[symbols[i]]) {
|
438
|
+
std::swap(symbols[j], symbols[i]);
|
439
|
+
}
|
440
|
+
}
|
441
|
+
}
|
442
|
+
|
443
|
+
if (count == 2) {
|
444
|
+
WriteBits(max_bits, symbols[0], storage_ix, storage);
|
445
|
+
WriteBits(max_bits, symbols[1], storage_ix, storage);
|
446
|
+
} else if (count == 3) {
|
447
|
+
WriteBits(max_bits, symbols[0], storage_ix, storage);
|
448
|
+
WriteBits(max_bits, symbols[1], storage_ix, storage);
|
449
|
+
WriteBits(max_bits, symbols[2], storage_ix, storage);
|
450
|
+
} else {
|
451
|
+
WriteBits(max_bits, symbols[0], storage_ix, storage);
|
452
|
+
WriteBits(max_bits, symbols[1], storage_ix, storage);
|
453
|
+
WriteBits(max_bits, symbols[2], storage_ix, storage);
|
454
|
+
WriteBits(max_bits, symbols[3], storage_ix, storage);
|
455
|
+
// tree-select
|
456
|
+
WriteBits(1, depth[symbols[0]] == 1 ? 1 : 0, storage_ix, storage);
|
457
|
+
}
|
458
|
+
} else {
|
459
|
+
// Complex Huffman Tree
|
460
|
+
StoreStaticCodeLengthCode(storage_ix, storage);
|
461
|
+
|
462
|
+
// Actual rle coding.
|
463
|
+
uint8_t previous_value = 8;
|
464
|
+
for (size_t i = 0; i < length;) {
|
465
|
+
const uint8_t value = depth[i];
|
466
|
+
size_t reps = 1;
|
467
|
+
for (size_t k = i + 1; k < length && depth[k] == value; ++k) {
|
468
|
+
++reps;
|
469
|
+
}
|
470
|
+
i += reps;
|
471
|
+
if (value == 0) {
|
472
|
+
WriteBits(kZeroRepsDepth[reps], kZeroRepsBits[reps],
|
473
|
+
storage_ix, storage);
|
474
|
+
} else {
|
475
|
+
if (previous_value != value) {
|
476
|
+
WriteBits(kCodeLengthDepth[value], kCodeLengthBits[value],
|
477
|
+
storage_ix, storage);
|
478
|
+
--reps;
|
479
|
+
}
|
480
|
+
if (reps < 3) {
|
481
|
+
while (reps != 0) {
|
482
|
+
reps--;
|
483
|
+
WriteBits(kCodeLengthDepth[value], kCodeLengthBits[value],
|
484
|
+
storage_ix, storage);
|
485
|
+
}
|
486
|
+
} else {
|
487
|
+
reps -= 3;
|
488
|
+
WriteBits(kNonZeroRepsDepth[reps], kNonZeroRepsBits[reps],
|
489
|
+
storage_ix, storage);
|
490
|
+
}
|
491
|
+
previous_value = value;
|
492
|
+
}
|
493
|
+
}
|
312
494
|
}
|
313
495
|
}
|
314
496
|
|
315
|
-
|
316
|
-
|
497
|
+
static size_t IndexOf(const uint8_t* v, size_t v_size, uint8_t value) {
|
498
|
+
size_t i = 0;
|
499
|
+
for (; i < v_size; ++i) {
|
317
500
|
if (v[i] == value) return i;
|
318
501
|
}
|
319
|
-
return
|
502
|
+
return i;
|
320
503
|
}
|
321
504
|
|
322
|
-
void MoveToFront(
|
323
|
-
|
324
|
-
for (
|
325
|
-
|
505
|
+
static void MoveToFront(uint8_t* v, size_t index) {
|
506
|
+
uint8_t value = v[index];
|
507
|
+
for (size_t i = index; i != 0; --i) {
|
508
|
+
v[i] = v[i - 1];
|
326
509
|
}
|
327
|
-
|
510
|
+
v[0] = value;
|
328
511
|
}
|
329
512
|
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
513
|
+
static void MoveToFrontTransform(const uint32_t* __restrict v_in,
|
514
|
+
const size_t v_size,
|
515
|
+
uint32_t* v_out) {
|
516
|
+
if (v_size == 0) {
|
517
|
+
return;
|
518
|
+
}
|
519
|
+
uint32_t max_value = *std::max_element(v_in, v_in + v_size);
|
520
|
+
assert(max_value < 256u);
|
521
|
+
uint8_t mtf[256];
|
522
|
+
size_t mtf_size = max_value + 1;
|
523
|
+
for (uint32_t i = 0; i <= max_value; ++i) {
|
524
|
+
mtf[i] = static_cast<uint8_t>(i);
|
525
|
+
}
|
526
|
+
for (size_t i = 0; i < v_size; ++i) {
|
527
|
+
size_t index = IndexOf(mtf, mtf_size, static_cast<uint8_t>(v_in[i]));
|
528
|
+
assert(index < mtf_size);
|
529
|
+
v_out[i] = static_cast<uint32_t>(index);
|
530
|
+
MoveToFront(mtf, index);
|
531
|
+
}
|
342
532
|
}
|
343
533
|
|
344
|
-
// Finds runs of zeros in
|
345
|
-
// length plus extra bits
|
346
|
-
//
|
347
|
-
//
|
348
|
-
//
|
349
|
-
// code.
|
350
|
-
void RunLengthCodeZeros(const
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
for (size_t i = 0; i <
|
356
|
-
for (; i <
|
357
|
-
|
358
|
-
for (; i <
|
534
|
+
// Finds runs of zeros in v[0..in_size) and replaces them with a prefix code of
|
535
|
+
// the run length plus extra bits (lower 9 bits is the prefix code and the rest
|
536
|
+
// are the extra bits). Non-zero values in v[] are shifted by
|
537
|
+
// *max_length_prefix. Will not create prefix codes bigger than the initial
|
538
|
+
// value of *max_run_length_prefix. The prefix code of run length L is simply
|
539
|
+
// Log2Floor(L) and the number of extra bits is the same as the prefix code.
|
540
|
+
static void RunLengthCodeZeros(const size_t in_size,
|
541
|
+
uint32_t* __restrict v,
|
542
|
+
size_t* __restrict out_size,
|
543
|
+
uint32_t* __restrict max_run_length_prefix) {
|
544
|
+
uint32_t max_reps = 0;
|
545
|
+
for (size_t i = 0; i < in_size;) {
|
546
|
+
for (; i < in_size && v[i] != 0; ++i) ;
|
547
|
+
uint32_t reps = 0;
|
548
|
+
for (; i < in_size && v[i] == 0; ++i) {
|
359
549
|
++reps;
|
360
550
|
}
|
361
551
|
max_reps = std::max(reps, max_reps);
|
362
552
|
}
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
553
|
+
uint32_t max_prefix = max_reps > 0 ? Log2FloorNonZero(max_reps) : 0;
|
554
|
+
max_prefix = std::min(max_prefix, *max_run_length_prefix);
|
555
|
+
*max_run_length_prefix = max_prefix;
|
556
|
+
*out_size = 0;
|
557
|
+
for (size_t i = 0; i < in_size;) {
|
558
|
+
assert(*out_size <= i);
|
559
|
+
if (v[i] != 0) {
|
560
|
+
v[*out_size] = v[i] + *max_run_length_prefix;
|
369
561
|
++i;
|
562
|
+
++(*out_size);
|
370
563
|
} else {
|
371
|
-
|
372
|
-
for (size_t k = i + 1; k <
|
564
|
+
uint32_t reps = 1;
|
565
|
+
for (size_t k = i + 1; k < in_size && v[k] == 0; ++k) {
|
373
566
|
++reps;
|
374
567
|
}
|
375
568
|
i += reps;
|
376
|
-
while (reps) {
|
377
|
-
if (reps < (
|
378
|
-
|
379
|
-
|
380
|
-
|
569
|
+
while (reps != 0) {
|
570
|
+
if (reps < (2u << max_prefix)) {
|
571
|
+
uint32_t run_length_prefix = Log2FloorNonZero(reps);
|
572
|
+
const uint32_t extra_bits = reps - (1u << run_length_prefix);
|
573
|
+
v[*out_size] = run_length_prefix + (extra_bits << 9);
|
574
|
+
++(*out_size);
|
381
575
|
break;
|
382
576
|
} else {
|
383
|
-
|
384
|
-
extra_bits
|
385
|
-
reps -= (
|
577
|
+
const uint32_t extra_bits = (1u << max_prefix) - 1u;
|
578
|
+
v[*out_size] = max_prefix + (extra_bits << 9);
|
579
|
+
reps -= (2u << max_prefix) - 1u;
|
580
|
+
++(*out_size);
|
386
581
|
}
|
387
582
|
}
|
388
583
|
}
|
389
584
|
}
|
390
585
|
}
|
391
586
|
|
392
|
-
void EncodeContextMap(const std::vector<
|
393
|
-
|
394
|
-
|
587
|
+
void EncodeContextMap(const std::vector<uint32_t>& context_map,
|
588
|
+
size_t num_clusters,
|
589
|
+
HuffmanTree* tree,
|
590
|
+
size_t* storage_ix, uint8_t* storage) {
|
395
591
|
StoreVarLenUint8(num_clusters - 1, storage_ix, storage);
|
396
592
|
|
397
593
|
if (num_clusters == 1) {
|
398
594
|
return;
|
399
595
|
}
|
400
596
|
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
RunLengthCodeZeros(
|
406
|
-
&
|
407
|
-
|
408
|
-
|
409
|
-
|
597
|
+
uint32_t* rle_symbols = new uint32_t[context_map.size()];
|
598
|
+
MoveToFrontTransform(&context_map[0], context_map.size(), rle_symbols);
|
599
|
+
uint32_t max_run_length_prefix = 6;
|
600
|
+
size_t num_rle_symbols = 0;
|
601
|
+
RunLengthCodeZeros(context_map.size(), rle_symbols,
|
602
|
+
&num_rle_symbols, &max_run_length_prefix);
|
603
|
+
uint32_t histogram[kContextMapAlphabetSize];
|
604
|
+
memset(histogram, 0, sizeof(histogram));
|
605
|
+
static const int kSymbolBits = 9;
|
606
|
+
static const uint32_t kSymbolMask = (1u << kSymbolBits) - 1u;
|
607
|
+
for (size_t i = 0; i < num_rle_symbols; ++i) {
|
608
|
+
++histogram[rle_symbols[i] & kSymbolMask];
|
410
609
|
}
|
411
610
|
bool use_rle = max_run_length_prefix > 0;
|
412
611
|
WriteBits(1, use_rle, storage_ix, storage);
|
413
612
|
if (use_rle) {
|
414
613
|
WriteBits(4, max_run_length_prefix - 1, storage_ix, storage);
|
415
614
|
}
|
416
|
-
|
417
|
-
|
418
|
-
memset(
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
WriteBits(rle_symbols[i], extra_bits[i], storage_ix, storage);
|
615
|
+
uint8_t depths[kContextMapAlphabetSize];
|
616
|
+
uint16_t bits[kContextMapAlphabetSize];
|
617
|
+
memset(depths, 0, sizeof(depths));
|
618
|
+
memset(bits, 0, sizeof(bits));
|
619
|
+
BuildAndStoreHuffmanTree(histogram, num_clusters + max_run_length_prefix,
|
620
|
+
tree, depths, bits, storage_ix, storage);
|
621
|
+
for (size_t i = 0; i < num_rle_symbols; ++i) {
|
622
|
+
const uint32_t rle_symbol = rle_symbols[i] & kSymbolMask;
|
623
|
+
const uint32_t extra_bits_val = rle_symbols[i] >> kSymbolBits;
|
624
|
+
WriteBits(depths[rle_symbol], bits[rle_symbol], storage_ix, storage);
|
625
|
+
if (rle_symbol > 0 && rle_symbol <= max_run_length_prefix) {
|
626
|
+
WriteBits(rle_symbol, extra_bits_val, storage_ix, storage);
|
429
627
|
}
|
430
628
|
}
|
431
629
|
WriteBits(1, 1, storage_ix, storage); // use move-to-front
|
630
|
+
delete[] rle_symbols;
|
432
631
|
}
|
433
632
|
|
434
633
|
void StoreBlockSwitch(const BlockSplitCode& code,
|
435
|
-
const
|
436
|
-
|
634
|
+
const size_t block_ix,
|
635
|
+
size_t* storage_ix,
|
437
636
|
uint8_t* storage) {
|
438
637
|
if (block_ix > 0) {
|
439
|
-
|
638
|
+
size_t typecode = code.type_code[block_ix];
|
440
639
|
WriteBits(code.type_depths[typecode], code.type_bits[typecode],
|
441
640
|
storage_ix, storage);
|
442
641
|
}
|
443
|
-
|
642
|
+
size_t lencode = code.length_prefix[block_ix];
|
444
643
|
WriteBits(code.length_depths[lencode], code.length_bits[lencode],
|
445
644
|
storage_ix, storage);
|
446
645
|
WriteBits(code.length_nextra[block_ix], code.length_extra[block_ix],
|
447
646
|
storage_ix, storage);
|
448
647
|
}
|
449
648
|
|
450
|
-
void BuildAndStoreBlockSplitCode(const std::vector<
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
649
|
+
static void BuildAndStoreBlockSplitCode(const std::vector<uint8_t>& types,
|
650
|
+
const std::vector<uint32_t>& lengths,
|
651
|
+
const size_t num_types,
|
652
|
+
HuffmanTree* tree,
|
653
|
+
BlockSplitCode* code,
|
654
|
+
size_t* storage_ix,
|
655
|
+
uint8_t* storage) {
|
656
|
+
const size_t num_blocks = types.size();
|
657
|
+
uint32_t type_histo[kBlockTypeAlphabetSize];
|
658
|
+
uint32_t length_histo[kNumBlockLenPrefixes];
|
659
|
+
memset(type_histo, 0, (num_types + 2) * sizeof(type_histo[0]));
|
660
|
+
memset(length_histo, 0, sizeof(length_histo));
|
661
|
+
size_t last_type = 1;
|
662
|
+
size_t second_last_type = 0;
|
461
663
|
code->type_code.resize(num_blocks);
|
462
664
|
code->length_prefix.resize(num_blocks);
|
463
665
|
code->length_nextra.resize(num_blocks);
|
464
666
|
code->length_extra.resize(num_blocks);
|
465
667
|
code->type_depths.resize(num_types + 2);
|
466
668
|
code->type_bits.resize(num_types + 2);
|
467
|
-
code->length_depths
|
468
|
-
code->length_bits
|
469
|
-
for (
|
470
|
-
|
471
|
-
|
669
|
+
memset(code->length_depths, 0, sizeof(code->length_depths));
|
670
|
+
memset(code->length_bits, 0, sizeof(code->length_bits));
|
671
|
+
for (size_t i = 0; i < num_blocks; ++i) {
|
672
|
+
size_t type = types[i];
|
673
|
+
size_t type_code = (type == last_type + 1 ? 1 :
|
472
674
|
type == second_last_type ? 0 :
|
473
675
|
type + 2);
|
474
676
|
second_last_type = last_type;
|
475
677
|
last_type = type;
|
476
|
-
code->type_code[i] = type_code;
|
477
|
-
if (i
|
678
|
+
code->type_code[i] = static_cast<uint32_t>(type_code);
|
679
|
+
if (i != 0) ++type_histo[type_code];
|
478
680
|
GetBlockLengthPrefixCode(lengths[i],
|
479
681
|
&code->length_prefix[i],
|
480
682
|
&code->length_nextra[i],
|
@@ -483,41 +685,45 @@ void BuildAndStoreBlockSplitCode(const std::vector<int>& types,
|
|
483
685
|
}
|
484
686
|
StoreVarLenUint8(num_types - 1, storage_ix, storage);
|
485
687
|
if (num_types > 1) {
|
486
|
-
BuildAndStoreHuffmanTree(&type_histo[0], num_types + 2,
|
688
|
+
BuildAndStoreHuffmanTree(&type_histo[0], num_types + 2, tree,
|
487
689
|
&code->type_depths[0], &code->type_bits[0],
|
488
690
|
storage_ix, storage);
|
489
|
-
BuildAndStoreHuffmanTree(&length_histo[0],
|
691
|
+
BuildAndStoreHuffmanTree(&length_histo[0], kNumBlockLenPrefixes, tree,
|
490
692
|
&code->length_depths[0], &code->length_bits[0],
|
491
693
|
storage_ix, storage);
|
492
694
|
StoreBlockSwitch(*code, 0, storage_ix, storage);
|
493
695
|
}
|
494
696
|
}
|
495
697
|
|
496
|
-
void StoreTrivialContextMap(
|
497
|
-
|
498
|
-
|
698
|
+
void StoreTrivialContextMap(size_t num_types,
|
699
|
+
size_t context_bits,
|
700
|
+
HuffmanTree* tree,
|
701
|
+
size_t* storage_ix,
|
499
702
|
uint8_t* storage) {
|
500
703
|
StoreVarLenUint8(num_types - 1, storage_ix, storage);
|
501
704
|
if (num_types > 1) {
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
705
|
+
size_t repeat_code = context_bits - 1u;
|
706
|
+
size_t repeat_bits = (1u << repeat_code) - 1u;
|
707
|
+
size_t alphabet_size = num_types + repeat_code;
|
708
|
+
uint32_t histogram[kContextMapAlphabetSize];
|
709
|
+
uint8_t depths[kContextMapAlphabetSize];
|
710
|
+
uint16_t bits[kContextMapAlphabetSize];
|
711
|
+
memset(histogram, 0, alphabet_size * sizeof(histogram[0]));
|
712
|
+
memset(depths, 0, alphabet_size * sizeof(depths[0]));
|
713
|
+
memset(bits, 0, alphabet_size * sizeof(bits[0]));
|
508
714
|
// Write RLEMAX.
|
509
715
|
WriteBits(1, 1, storage_ix, storage);
|
510
716
|
WriteBits(4, repeat_code - 1, storage_ix, storage);
|
511
|
-
histogram[repeat_code] = num_types;
|
717
|
+
histogram[repeat_code] = static_cast<uint32_t>(num_types);
|
512
718
|
histogram[0] = 1;
|
513
|
-
for (
|
719
|
+
for (size_t i = context_bits; i < alphabet_size; ++i) {
|
514
720
|
histogram[i] = 1;
|
515
721
|
}
|
516
|
-
BuildAndStoreHuffmanTree(&histogram[0], alphabet_size,
|
722
|
+
BuildAndStoreHuffmanTree(&histogram[0], alphabet_size, tree,
|
517
723
|
&depths[0], &bits[0],
|
518
724
|
storage_ix, storage);
|
519
|
-
for (
|
520
|
-
|
725
|
+
for (size_t i = 0; i < num_types; ++i) {
|
726
|
+
size_t code = (i == 0 ? 0 : i + context_bits - 1);
|
521
727
|
WriteBits(depths[code], bits[code], storage_ix, storage);
|
522
728
|
WriteBits(depths[repeat_code], bits[repeat_code], storage_ix, storage);
|
523
729
|
WriteBits(repeat_code, repeat_bits, storage_ix, storage);
|
@@ -530,10 +736,10 @@ void StoreTrivialContextMap(int num_types,
|
|
530
736
|
// Manages the encoding of one block category (literal, command or distance).
|
531
737
|
class BlockEncoder {
|
532
738
|
public:
|
533
|
-
BlockEncoder(
|
534
|
-
|
535
|
-
const std::vector<
|
536
|
-
const std::vector<
|
739
|
+
BlockEncoder(size_t alphabet_size,
|
740
|
+
size_t num_block_types,
|
741
|
+
const std::vector<uint8_t>& block_types,
|
742
|
+
const std::vector<uint32_t>& block_lengths)
|
537
743
|
: alphabet_size_(alphabet_size),
|
538
744
|
num_block_types_(num_block_types),
|
539
745
|
block_types_(block_types),
|
@@ -544,10 +750,12 @@ class BlockEncoder {
|
|
544
750
|
|
545
751
|
// Creates entropy codes of block lengths and block types and stores them
|
546
752
|
// to the bit stream.
|
547
|
-
void BuildAndStoreBlockSwitchEntropyCodes(
|
753
|
+
void BuildAndStoreBlockSwitchEntropyCodes(HuffmanTree* tree,
|
754
|
+
size_t* storage_ix,
|
755
|
+
uint8_t* storage) {
|
548
756
|
BuildAndStoreBlockSplitCode(
|
549
757
|
block_types_, block_lengths_, num_block_types_,
|
550
|
-
&block_split_code_, storage_ix, storage);
|
758
|
+
tree, &block_split_code_, storage_ix, storage);
|
551
759
|
}
|
552
760
|
|
553
761
|
// Creates entropy codes for all block types and stores them to the bit
|
@@ -555,12 +763,14 @@ class BlockEncoder {
|
|
555
763
|
template<int kSize>
|
556
764
|
void BuildAndStoreEntropyCodes(
|
557
765
|
const std::vector<Histogram<kSize> >& histograms,
|
558
|
-
|
766
|
+
HuffmanTree* tree,
|
767
|
+
size_t* storage_ix, uint8_t* storage) {
|
559
768
|
depths_.resize(histograms.size() * alphabet_size_);
|
560
769
|
bits_.resize(histograms.size() * alphabet_size_);
|
561
770
|
for (size_t i = 0; i < histograms.size(); ++i) {
|
562
771
|
size_t ix = i * alphabet_size_;
|
563
772
|
BuildAndStoreHuffmanTree(&histograms[i].data_[0], alphabet_size_,
|
773
|
+
tree,
|
564
774
|
&depths_[ix], &bits_[ix],
|
565
775
|
storage_ix, storage);
|
566
776
|
}
|
@@ -568,7 +778,7 @@ class BlockEncoder {
|
|
568
778
|
|
569
779
|
// Stores the next symbol with the entropy code of the current block type.
|
570
780
|
// Updates the block type and block length at block boundaries.
|
571
|
-
void StoreSymbol(
|
781
|
+
void StoreSymbol(size_t symbol, size_t* storage_ix, uint8_t* storage) {
|
572
782
|
if (block_len_ == 0) {
|
573
783
|
++block_ix_;
|
574
784
|
block_len_ = block_lengths_[block_ix_];
|
@@ -576,7 +786,7 @@ class BlockEncoder {
|
|
576
786
|
StoreBlockSwitch(block_split_code_, block_ix_, storage_ix, storage);
|
577
787
|
}
|
578
788
|
--block_len_;
|
579
|
-
|
789
|
+
size_t ix = entropy_ix_ + symbol;
|
580
790
|
WriteBits(depths_[ix], bits_[ix], storage_ix, storage);
|
581
791
|
}
|
582
792
|
|
@@ -584,68 +794,63 @@ class BlockEncoder {
|
|
584
794
|
// context value.
|
585
795
|
// Updates the block type and block length at block boundaries.
|
586
796
|
template<int kContextBits>
|
587
|
-
void StoreSymbolWithContext(
|
588
|
-
const std::vector<
|
589
|
-
|
797
|
+
void StoreSymbolWithContext(size_t symbol, size_t context,
|
798
|
+
const std::vector<uint32_t>& context_map,
|
799
|
+
size_t* storage_ix, uint8_t* storage) {
|
590
800
|
if (block_len_ == 0) {
|
591
801
|
++block_ix_;
|
592
802
|
block_len_ = block_lengths_[block_ix_];
|
593
|
-
|
803
|
+
size_t block_type = block_types_[block_ix_];
|
804
|
+
entropy_ix_ = block_type << kContextBits;
|
594
805
|
StoreBlockSwitch(block_split_code_, block_ix_, storage_ix, storage);
|
595
806
|
}
|
596
807
|
--block_len_;
|
597
|
-
|
598
|
-
|
808
|
+
size_t histo_ix = context_map[entropy_ix_ + context];
|
809
|
+
size_t ix = histo_ix * alphabet_size_ + symbol;
|
599
810
|
WriteBits(depths_[ix], bits_[ix], storage_ix, storage);
|
600
811
|
}
|
601
812
|
|
602
813
|
private:
|
603
|
-
const
|
604
|
-
const
|
605
|
-
const std::vector<
|
606
|
-
const std::vector<
|
814
|
+
const size_t alphabet_size_;
|
815
|
+
const size_t num_block_types_;
|
816
|
+
const std::vector<uint8_t>& block_types_;
|
817
|
+
const std::vector<uint32_t>& block_lengths_;
|
607
818
|
BlockSplitCode block_split_code_;
|
608
|
-
|
609
|
-
|
610
|
-
|
819
|
+
size_t block_ix_;
|
820
|
+
size_t block_len_;
|
821
|
+
size_t entropy_ix_;
|
611
822
|
std::vector<uint8_t> depths_;
|
612
823
|
std::vector<uint16_t> bits_;
|
613
824
|
};
|
614
825
|
|
615
|
-
void JumpToByteBoundary(
|
616
|
-
*storage_ix = (*storage_ix +
|
826
|
+
static void JumpToByteBoundary(size_t* storage_ix, uint8_t* storage) {
|
827
|
+
*storage_ix = (*storage_ix + 7u) & ~7u;
|
617
828
|
storage[*storage_ix >> 3] = 0;
|
618
829
|
}
|
619
830
|
|
620
|
-
|
831
|
+
void StoreMetaBlock(const uint8_t* input,
|
621
832
|
size_t start_pos,
|
622
833
|
size_t length,
|
623
834
|
size_t mask,
|
624
835
|
uint8_t prev_byte,
|
625
836
|
uint8_t prev_byte2,
|
626
837
|
bool is_last,
|
627
|
-
|
628
|
-
|
629
|
-
|
838
|
+
uint32_t num_direct_distance_codes,
|
839
|
+
uint32_t distance_postfix_bits,
|
840
|
+
ContextType literal_context_mode,
|
630
841
|
const brotli::Command *commands,
|
631
842
|
size_t n_commands,
|
632
843
|
const MetaBlockSplit& mb,
|
633
|
-
|
844
|
+
size_t *storage_ix,
|
634
845
|
uint8_t *storage) {
|
635
|
-
|
636
|
-
return false;
|
637
|
-
}
|
638
|
-
|
639
|
-
if (length == 0) {
|
640
|
-
// Only the last meta-block can be empty, so jump to next byte.
|
641
|
-
JumpToByteBoundary(storage_ix, storage);
|
642
|
-
return true;
|
643
|
-
}
|
846
|
+
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
644
847
|
|
645
|
-
|
848
|
+
size_t num_distance_codes =
|
646
849
|
kNumDistanceShortCodes + num_direct_distance_codes +
|
647
|
-
(
|
850
|
+
(48u << distance_postfix_bits);
|
648
851
|
|
852
|
+
HuffmanTree* tree = static_cast<HuffmanTree*>(
|
853
|
+
malloc(kMaxHuffmanTreeSize * sizeof(HuffmanTree)));
|
649
854
|
BlockEncoder literal_enc(256,
|
650
855
|
mb.literal_split.num_types,
|
651
856
|
mb.literal_split.types,
|
@@ -659,59 +864,57 @@ bool StoreMetaBlock(const uint8_t* input,
|
|
659
864
|
mb.distance_split.types,
|
660
865
|
mb.distance_split.lengths);
|
661
866
|
|
662
|
-
literal_enc.BuildAndStoreBlockSwitchEntropyCodes(storage_ix, storage);
|
663
|
-
command_enc.BuildAndStoreBlockSwitchEntropyCodes(storage_ix, storage);
|
664
|
-
distance_enc.BuildAndStoreBlockSwitchEntropyCodes(storage_ix, storage);
|
867
|
+
literal_enc.BuildAndStoreBlockSwitchEntropyCodes(tree, storage_ix, storage);
|
868
|
+
command_enc.BuildAndStoreBlockSwitchEntropyCodes(tree, storage_ix, storage);
|
869
|
+
distance_enc.BuildAndStoreBlockSwitchEntropyCodes(tree, storage_ix, storage);
|
665
870
|
|
666
871
|
WriteBits(2, distance_postfix_bits, storage_ix, storage);
|
667
872
|
WriteBits(4, num_direct_distance_codes >> distance_postfix_bits,
|
668
873
|
storage_ix, storage);
|
669
|
-
for (
|
874
|
+
for (size_t i = 0; i < mb.literal_split.num_types; ++i) {
|
670
875
|
WriteBits(2, literal_context_mode, storage_ix, storage);
|
671
876
|
}
|
672
877
|
|
673
|
-
|
878
|
+
size_t num_literal_histograms = mb.literal_histograms.size();
|
674
879
|
if (mb.literal_context_map.empty()) {
|
675
|
-
StoreTrivialContextMap(num_literal_histograms, kLiteralContextBits,
|
880
|
+
StoreTrivialContextMap(num_literal_histograms, kLiteralContextBits, tree,
|
676
881
|
storage_ix, storage);
|
677
882
|
} else {
|
678
|
-
EncodeContextMap(mb.literal_context_map, num_literal_histograms,
|
883
|
+
EncodeContextMap(mb.literal_context_map, num_literal_histograms, tree,
|
679
884
|
storage_ix, storage);
|
680
885
|
}
|
681
886
|
|
682
|
-
|
887
|
+
size_t num_dist_histograms = mb.distance_histograms.size();
|
683
888
|
if (mb.distance_context_map.empty()) {
|
684
|
-
StoreTrivialContextMap(num_dist_histograms, kDistanceContextBits,
|
889
|
+
StoreTrivialContextMap(num_dist_histograms, kDistanceContextBits, tree,
|
685
890
|
storage_ix, storage);
|
686
891
|
} else {
|
687
|
-
EncodeContextMap(mb.distance_context_map, num_dist_histograms,
|
892
|
+
EncodeContextMap(mb.distance_context_map, num_dist_histograms, tree,
|
688
893
|
storage_ix, storage);
|
689
894
|
}
|
690
895
|
|
691
|
-
literal_enc.BuildAndStoreEntropyCodes(mb.literal_histograms,
|
896
|
+
literal_enc.BuildAndStoreEntropyCodes(mb.literal_histograms, tree,
|
692
897
|
storage_ix, storage);
|
693
|
-
command_enc.BuildAndStoreEntropyCodes(mb.command_histograms,
|
898
|
+
command_enc.BuildAndStoreEntropyCodes(mb.command_histograms, tree,
|
694
899
|
storage_ix, storage);
|
695
|
-
distance_enc.BuildAndStoreEntropyCodes(mb.distance_histograms,
|
900
|
+
distance_enc.BuildAndStoreEntropyCodes(mb.distance_histograms, tree,
|
696
901
|
storage_ix, storage);
|
902
|
+
free(tree);
|
697
903
|
|
698
904
|
size_t pos = start_pos;
|
699
905
|
for (size_t i = 0; i < n_commands; ++i) {
|
700
906
|
const Command cmd = commands[i];
|
701
|
-
|
702
|
-
int lennumextra = static_cast<int>(cmd.cmd_extra_ >> 48);
|
703
|
-
uint64_t lenextra = cmd.cmd_extra_ & 0xffffffffffffUL;
|
907
|
+
size_t cmd_code = cmd.cmd_prefix_;
|
704
908
|
command_enc.StoreSymbol(cmd_code, storage_ix, storage);
|
705
|
-
|
909
|
+
StoreCommandExtra(cmd, storage_ix, storage);
|
706
910
|
if (mb.literal_context_map.empty()) {
|
707
|
-
for (
|
911
|
+
for (size_t j = cmd.insert_len_; j != 0; --j) {
|
708
912
|
literal_enc.StoreSymbol(input[pos & mask], storage_ix, storage);
|
709
913
|
++pos;
|
710
914
|
}
|
711
915
|
} else {
|
712
|
-
for (
|
713
|
-
|
714
|
-
literal_context_mode);
|
916
|
+
for (size_t j = cmd.insert_len_; j != 0; --j) {
|
917
|
+
size_t context = Context(prev_byte, prev_byte2, literal_context_mode);
|
715
918
|
uint8_t literal = input[pos & mask];
|
716
919
|
literal_enc.StoreSymbolWithContext<kLiteralContextBits>(
|
717
920
|
literal, context, mb.literal_context_map, storage_ix, storage);
|
@@ -720,18 +923,18 @@ bool StoreMetaBlock(const uint8_t* input,
|
|
720
923
|
++pos;
|
721
924
|
}
|
722
925
|
}
|
723
|
-
pos += cmd.
|
724
|
-
if (cmd.
|
926
|
+
pos += cmd.copy_len();
|
927
|
+
if (cmd.copy_len()) {
|
725
928
|
prev_byte2 = input[(pos - 2) & mask];
|
726
929
|
prev_byte = input[(pos - 1) & mask];
|
727
930
|
if (cmd.cmd_prefix_ >= 128) {
|
728
|
-
|
729
|
-
|
730
|
-
|
931
|
+
size_t dist_code = cmd.dist_prefix_;
|
932
|
+
uint32_t distnumextra = cmd.dist_extra_ >> 24;
|
933
|
+
uint64_t distextra = cmd.dist_extra_ & 0xffffff;
|
731
934
|
if (mb.distance_context_map.empty()) {
|
732
935
|
distance_enc.StoreSymbol(dist_code, storage_ix, storage);
|
733
936
|
} else {
|
734
|
-
|
937
|
+
size_t context = cmd.DistanceContext();
|
735
938
|
distance_enc.StoreSymbolWithContext<kDistanceContextBits>(
|
736
939
|
dist_code, context, mb.distance_context_map, storage_ix, storage);
|
737
940
|
}
|
@@ -742,45 +945,84 @@ bool StoreMetaBlock(const uint8_t* input,
|
|
742
945
|
if (is_last) {
|
743
946
|
JumpToByteBoundary(storage_ix, storage);
|
744
947
|
}
|
745
|
-
return true;
|
746
948
|
}
|
747
949
|
|
748
|
-
|
950
|
+
static void BuildHistograms(const uint8_t* input,
|
951
|
+
size_t start_pos,
|
952
|
+
size_t mask,
|
953
|
+
const brotli::Command *commands,
|
954
|
+
size_t n_commands,
|
955
|
+
HistogramLiteral* lit_histo,
|
956
|
+
HistogramCommand* cmd_histo,
|
957
|
+
HistogramDistance* dist_histo) {
|
958
|
+
size_t pos = start_pos;
|
959
|
+
for (size_t i = 0; i < n_commands; ++i) {
|
960
|
+
const Command cmd = commands[i];
|
961
|
+
cmd_histo->Add(cmd.cmd_prefix_);
|
962
|
+
for (size_t j = cmd.insert_len_; j != 0; --j) {
|
963
|
+
lit_histo->Add(input[pos & mask]);
|
964
|
+
++pos;
|
965
|
+
}
|
966
|
+
pos += cmd.copy_len();
|
967
|
+
if (cmd.copy_len() && cmd.cmd_prefix_ >= 128) {
|
968
|
+
dist_histo->Add(cmd.dist_prefix_);
|
969
|
+
}
|
970
|
+
}
|
971
|
+
}
|
972
|
+
|
973
|
+
static void StoreDataWithHuffmanCodes(const uint8_t* input,
|
974
|
+
size_t start_pos,
|
975
|
+
size_t mask,
|
976
|
+
const brotli::Command *commands,
|
977
|
+
size_t n_commands,
|
978
|
+
const uint8_t* lit_depth,
|
979
|
+
const uint16_t* lit_bits,
|
980
|
+
const uint8_t* cmd_depth,
|
981
|
+
const uint16_t* cmd_bits,
|
982
|
+
const uint8_t* dist_depth,
|
983
|
+
const uint16_t* dist_bits,
|
984
|
+
size_t* storage_ix,
|
985
|
+
uint8_t* storage) {
|
986
|
+
size_t pos = start_pos;
|
987
|
+
for (size_t i = 0; i < n_commands; ++i) {
|
988
|
+
const Command cmd = commands[i];
|
989
|
+
const size_t cmd_code = cmd.cmd_prefix_;
|
990
|
+
WriteBits(cmd_depth[cmd_code], cmd_bits[cmd_code], storage_ix, storage);
|
991
|
+
StoreCommandExtra(cmd, storage_ix, storage);
|
992
|
+
for (size_t j = cmd.insert_len_; j != 0; --j) {
|
993
|
+
const uint8_t literal = input[pos & mask];
|
994
|
+
WriteBits(lit_depth[literal], lit_bits[literal], storage_ix, storage);
|
995
|
+
++pos;
|
996
|
+
}
|
997
|
+
pos += cmd.copy_len();
|
998
|
+
if (cmd.copy_len() && cmd.cmd_prefix_ >= 128) {
|
999
|
+
const size_t dist_code = cmd.dist_prefix_;
|
1000
|
+
const uint32_t distnumextra = cmd.dist_extra_ >> 24;
|
1001
|
+
const uint32_t distextra = cmd.dist_extra_ & 0xffffff;
|
1002
|
+
WriteBits(dist_depth[dist_code], dist_bits[dist_code],
|
1003
|
+
storage_ix, storage);
|
1004
|
+
WriteBits(distnumextra, distextra, storage_ix, storage);
|
1005
|
+
}
|
1006
|
+
}
|
1007
|
+
}
|
1008
|
+
|
1009
|
+
void StoreMetaBlockTrivial(const uint8_t* input,
|
749
1010
|
size_t start_pos,
|
750
1011
|
size_t length,
|
751
1012
|
size_t mask,
|
752
1013
|
bool is_last,
|
753
1014
|
const brotli::Command *commands,
|
754
1015
|
size_t n_commands,
|
755
|
-
|
1016
|
+
size_t *storage_ix,
|
756
1017
|
uint8_t *storage) {
|
757
|
-
|
758
|
-
return false;
|
759
|
-
}
|
760
|
-
|
761
|
-
if (length == 0) {
|
762
|
-
// Only the last meta-block can be empty, so jump to next byte.
|
763
|
-
JumpToByteBoundary(storage_ix, storage);
|
764
|
-
return true;
|
765
|
-
}
|
1018
|
+
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
766
1019
|
|
767
1020
|
HistogramLiteral lit_histo;
|
768
1021
|
HistogramCommand cmd_histo;
|
769
1022
|
HistogramDistance dist_histo;
|
770
1023
|
|
771
|
-
|
772
|
-
|
773
|
-
const Command cmd = commands[i];
|
774
|
-
cmd_histo.Add(cmd.cmd_prefix_);
|
775
|
-
for (int j = 0; j < cmd.insert_len_; ++j) {
|
776
|
-
lit_histo.Add(input[pos & mask]);
|
777
|
-
++pos;
|
778
|
-
}
|
779
|
-
pos += cmd.copy_len_;
|
780
|
-
if (cmd.copy_len_ > 0 && cmd.cmd_prefix_ >= 128) {
|
781
|
-
dist_histo.Add(cmd.dist_prefix_);
|
782
|
-
}
|
783
|
-
}
|
1024
|
+
BuildHistograms(input, start_pos, mask, commands, n_commands,
|
1025
|
+
&lit_histo, &cmd_histo, &dist_histo);
|
784
1026
|
|
785
1027
|
WriteBits(13, 0, storage_ix, storage);
|
786
1028
|
|
@@ -791,68 +1033,126 @@ bool StoreMetaBlockTrivial(const uint8_t* input,
|
|
791
1033
|
std::vector<uint8_t> dist_depth(64);
|
792
1034
|
std::vector<uint16_t> dist_bits(64);
|
793
1035
|
|
794
|
-
|
1036
|
+
HuffmanTree* tree = static_cast<HuffmanTree*>(
|
1037
|
+
malloc(kMaxHuffmanTreeSize * sizeof(HuffmanTree)));
|
1038
|
+
BuildAndStoreHuffmanTree(&lit_histo.data_[0], 256, tree,
|
795
1039
|
&lit_depth[0], &lit_bits[0],
|
796
1040
|
storage_ix, storage);
|
797
|
-
BuildAndStoreHuffmanTree(&cmd_histo.data_[0], kNumCommandPrefixes,
|
1041
|
+
BuildAndStoreHuffmanTree(&cmd_histo.data_[0], kNumCommandPrefixes, tree,
|
798
1042
|
&cmd_depth[0], &cmd_bits[0],
|
799
1043
|
storage_ix, storage);
|
800
|
-
BuildAndStoreHuffmanTree(&dist_histo.data_[0], 64,
|
1044
|
+
BuildAndStoreHuffmanTree(&dist_histo.data_[0], 64, tree,
|
801
1045
|
&dist_depth[0], &dist_bits[0],
|
802
1046
|
storage_ix, storage);
|
1047
|
+
free(tree);
|
1048
|
+
StoreDataWithHuffmanCodes(input, start_pos, mask, commands,
|
1049
|
+
n_commands, &lit_depth[0], &lit_bits[0],
|
1050
|
+
&cmd_depth[0], &cmd_bits[0],
|
1051
|
+
&dist_depth[0], &dist_bits[0],
|
1052
|
+
storage_ix, storage);
|
1053
|
+
if (is_last) {
|
1054
|
+
JumpToByteBoundary(storage_ix, storage);
|
1055
|
+
}
|
1056
|
+
}
|
803
1057
|
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
1058
|
+
void StoreMetaBlockFast(const uint8_t* input,
|
1059
|
+
size_t start_pos,
|
1060
|
+
size_t length,
|
1061
|
+
size_t mask,
|
1062
|
+
bool is_last,
|
1063
|
+
const brotli::Command *commands,
|
1064
|
+
size_t n_commands,
|
1065
|
+
size_t *storage_ix,
|
1066
|
+
uint8_t *storage) {
|
1067
|
+
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
1068
|
+
|
1069
|
+
WriteBits(13, 0, storage_ix, storage);
|
1070
|
+
|
1071
|
+
if (n_commands <= 128) {
|
1072
|
+
uint32_t histogram[256] = { 0 };
|
1073
|
+
size_t pos = start_pos;
|
1074
|
+
size_t num_literals = 0;
|
1075
|
+
for (size_t i = 0; i < n_commands; ++i) {
|
1076
|
+
const Command cmd = commands[i];
|
1077
|
+
for (size_t j = cmd.insert_len_; j != 0; --j) {
|
1078
|
+
++histogram[input[pos & mask]];
|
1079
|
+
++pos;
|
1080
|
+
}
|
1081
|
+
num_literals += cmd.insert_len_;
|
1082
|
+
pos += cmd.copy_len();
|
825
1083
|
}
|
1084
|
+
uint8_t lit_depth[256] = { 0 };
|
1085
|
+
uint16_t lit_bits[256] = { 0 };
|
1086
|
+
BuildAndStoreHuffmanTreeFast(histogram, num_literals,
|
1087
|
+
/* max_bits = */ 8,
|
1088
|
+
lit_depth, lit_bits,
|
1089
|
+
storage_ix, storage);
|
1090
|
+
StoreStaticCommandHuffmanTree(storage_ix, storage);
|
1091
|
+
StoreStaticDistanceHuffmanTree(storage_ix, storage);
|
1092
|
+
StoreDataWithHuffmanCodes(input, start_pos, mask, commands,
|
1093
|
+
n_commands, &lit_depth[0], &lit_bits[0],
|
1094
|
+
kStaticCommandCodeDepth,
|
1095
|
+
kStaticCommandCodeBits,
|
1096
|
+
kStaticDistanceCodeDepth,
|
1097
|
+
kStaticDistanceCodeBits,
|
1098
|
+
storage_ix, storage);
|
1099
|
+
} else {
|
1100
|
+
HistogramLiteral lit_histo;
|
1101
|
+
HistogramCommand cmd_histo;
|
1102
|
+
HistogramDistance dist_histo;
|
1103
|
+
BuildHistograms(input, start_pos, mask, commands, n_commands,
|
1104
|
+
&lit_histo, &cmd_histo, &dist_histo);
|
1105
|
+
std::vector<uint8_t> lit_depth(256);
|
1106
|
+
std::vector<uint16_t> lit_bits(256);
|
1107
|
+
std::vector<uint8_t> cmd_depth(kNumCommandPrefixes);
|
1108
|
+
std::vector<uint16_t> cmd_bits(kNumCommandPrefixes);
|
1109
|
+
std::vector<uint8_t> dist_depth(64);
|
1110
|
+
std::vector<uint16_t> dist_bits(64);
|
1111
|
+
BuildAndStoreHuffmanTreeFast(&lit_histo.data_[0], lit_histo.total_count_,
|
1112
|
+
/* max_bits = */ 8,
|
1113
|
+
&lit_depth[0], &lit_bits[0],
|
1114
|
+
storage_ix, storage);
|
1115
|
+
BuildAndStoreHuffmanTreeFast(&cmd_histo.data_[0], cmd_histo.total_count_,
|
1116
|
+
/* max_bits = */ 10,
|
1117
|
+
&cmd_depth[0], &cmd_bits[0],
|
1118
|
+
storage_ix, storage);
|
1119
|
+
BuildAndStoreHuffmanTreeFast(&dist_histo.data_[0], dist_histo.total_count_,
|
1120
|
+
/* max_bits = */ 6,
|
1121
|
+
&dist_depth[0], &dist_bits[0],
|
1122
|
+
storage_ix, storage);
|
1123
|
+
StoreDataWithHuffmanCodes(input, start_pos, mask, commands,
|
1124
|
+
n_commands, &lit_depth[0], &lit_bits[0],
|
1125
|
+
&cmd_depth[0], &cmd_bits[0],
|
1126
|
+
&dist_depth[0], &dist_bits[0],
|
1127
|
+
storage_ix, storage);
|
826
1128
|
}
|
1129
|
+
|
827
1130
|
if (is_last) {
|
828
1131
|
JumpToByteBoundary(storage_ix, storage);
|
829
1132
|
}
|
830
|
-
return true;
|
831
1133
|
}
|
832
1134
|
|
833
1135
|
// This is for storing uncompressed blocks (simple raw storage of
|
834
1136
|
// bytes-as-bytes).
|
835
|
-
|
1137
|
+
void StoreUncompressedMetaBlock(bool final_block,
|
836
1138
|
const uint8_t * __restrict input,
|
837
1139
|
size_t position, size_t mask,
|
838
1140
|
size_t len,
|
839
|
-
|
1141
|
+
size_t * __restrict storage_ix,
|
840
1142
|
uint8_t * __restrict storage) {
|
841
|
-
|
842
|
-
return false;
|
843
|
-
}
|
1143
|
+
StoreUncompressedMetaBlockHeader(len, storage_ix, storage);
|
844
1144
|
JumpToByteBoundary(storage_ix, storage);
|
845
1145
|
|
846
1146
|
size_t masked_pos = position & mask;
|
847
1147
|
if (masked_pos + len > mask + 1) {
|
848
1148
|
size_t len1 = mask + 1 - masked_pos;
|
849
1149
|
memcpy(&storage[*storage_ix >> 3], &input[masked_pos], len1);
|
850
|
-
*storage_ix +=
|
1150
|
+
*storage_ix += len1 << 3;
|
851
1151
|
len -= len1;
|
852
1152
|
masked_pos = 0;
|
853
1153
|
}
|
854
1154
|
memcpy(&storage[*storage_ix >> 3], &input[masked_pos], len);
|
855
|
-
*storage_ix +=
|
1155
|
+
*storage_ix += len << 3;
|
856
1156
|
|
857
1157
|
// We need to clear the next 4 bytes to continue to be
|
858
1158
|
// compatible with WriteBits.
|
@@ -865,10 +1165,9 @@ bool StoreUncompressedMetaBlock(bool final_block,
|
|
865
1165
|
brotli::WriteBits(1, 1, storage_ix, storage); // isempty
|
866
1166
|
JumpToByteBoundary(storage_ix, storage);
|
867
1167
|
}
|
868
|
-
return true;
|
869
1168
|
}
|
870
1169
|
|
871
|
-
void StoreSyncMetaBlock(
|
1170
|
+
void StoreSyncMetaBlock(size_t * __restrict storage_ix,
|
872
1171
|
uint8_t * __restrict storage) {
|
873
1172
|
// Empty metadata meta-block bit pattern:
|
874
1173
|
// 1 bit: is_last (0)
|