brotli 0.2.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +37 -0
- data/.github/workflows/publish.yml +24 -0
- data/.gitmodules +1 -1
- data/Gemfile +6 -3
- data/README.md +2 -2
- data/Rakefile +16 -9
- data/brotli.gemspec +7 -13
- data/ext/brotli/brotli.c +210 -31
- data/ext/brotli/buffer.c +1 -7
- data/ext/brotli/buffer.h +1 -1
- data/ext/brotli/extconf.rb +25 -17
- data/lib/brotli/version.rb +1 -1
- data/test/brotli_test.rb +107 -0
- data/test/brotli_writer_test.rb +36 -0
- data/test/test_helper.rb +8 -0
- data/vendor/brotli/c/common/constants.c +15 -0
- data/vendor/brotli/c/common/constants.h +137 -0
- data/vendor/brotli/c/common/context.c +156 -0
- data/vendor/brotli/c/common/context.h +4 -152
- data/vendor/brotli/c/common/dictionary.bin.br +0 -0
- data/vendor/brotli/c/common/dictionary.c +14 -3
- data/vendor/brotli/c/common/platform.c +23 -0
- data/vendor/brotli/c/common/platform.h +95 -122
- data/vendor/brotli/c/common/shared_dictionary.c +521 -0
- data/vendor/brotli/c/common/shared_dictionary_internal.h +75 -0
- data/vendor/brotli/c/common/transform.c +60 -4
- data/vendor/brotli/c/common/transform.h +5 -0
- data/vendor/brotli/c/common/version.h +31 -6
- data/vendor/brotli/c/dec/bit_reader.c +34 -4
- data/vendor/brotli/c/dec/bit_reader.h +221 -107
- data/vendor/brotli/c/dec/decode.c +772 -403
- data/vendor/brotli/c/dec/huffman.c +7 -4
- data/vendor/brotli/c/dec/huffman.h +8 -13
- data/vendor/brotli/c/dec/prefix.h +1 -18
- data/vendor/brotli/c/dec/state.c +40 -21
- data/vendor/brotli/c/dec/state.h +201 -59
- data/vendor/brotli/c/enc/backward_references.c +88 -25
- data/vendor/brotli/c/enc/backward_references.h +10 -8
- data/vendor/brotli/c/enc/backward_references_hq.c +194 -80
- data/vendor/brotli/c/enc/backward_references_hq.h +17 -13
- data/vendor/brotli/c/enc/backward_references_inc.h +52 -16
- data/vendor/brotli/c/enc/bit_cost.c +8 -7
- data/vendor/brotli/c/enc/bit_cost.h +5 -4
- data/vendor/brotli/c/enc/block_splitter.c +40 -17
- data/vendor/brotli/c/enc/block_splitter.h +5 -4
- data/vendor/brotli/c/enc/block_splitter_inc.h +99 -49
- data/vendor/brotli/c/enc/brotli_bit_stream.c +142 -137
- data/vendor/brotli/c/enc/brotli_bit_stream.h +11 -6
- data/vendor/brotli/c/enc/cluster.c +10 -9
- data/vendor/brotli/c/enc/cluster.h +7 -6
- data/vendor/brotli/c/enc/cluster_inc.h +30 -22
- data/vendor/brotli/c/enc/command.c +28 -0
- data/vendor/brotli/c/enc/command.h +17 -16
- data/vendor/brotli/c/enc/compound_dictionary.c +207 -0
- data/vendor/brotli/c/enc/compound_dictionary.h +74 -0
- data/vendor/brotli/c/enc/compress_fragment.c +93 -83
- data/vendor/brotli/c/enc/compress_fragment.h +32 -7
- data/vendor/brotli/c/enc/compress_fragment_two_pass.c +100 -88
- data/vendor/brotli/c/enc/compress_fragment_two_pass.h +21 -3
- data/vendor/brotli/c/enc/dictionary_hash.c +1829 -1101
- data/vendor/brotli/c/enc/dictionary_hash.h +2 -1
- data/vendor/brotli/c/enc/encode.c +550 -416
- data/vendor/brotli/c/enc/encoder_dict.c +613 -5
- data/vendor/brotli/c/enc/encoder_dict.h +120 -4
- data/vendor/brotli/c/enc/entropy_encode.c +5 -2
- data/vendor/brotli/c/enc/entropy_encode.h +4 -3
- data/vendor/brotli/c/enc/entropy_encode_static.h +5 -2
- data/vendor/brotli/c/enc/fast_log.c +105 -0
- data/vendor/brotli/c/enc/fast_log.h +21 -101
- data/vendor/brotli/c/enc/find_match_length.h +17 -25
- data/vendor/brotli/c/enc/hash.h +350 -120
- data/vendor/brotli/c/enc/hash_composite_inc.h +71 -67
- data/vendor/brotli/c/enc/hash_forgetful_chain_inc.h +92 -51
- data/vendor/brotli/c/enc/hash_longest_match64_inc.h +79 -84
- data/vendor/brotli/c/enc/hash_longest_match_inc.h +53 -54
- data/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h +93 -62
- data/vendor/brotli/c/enc/hash_rolling_inc.h +25 -29
- data/vendor/brotli/c/enc/hash_to_binary_tree_inc.h +42 -40
- data/vendor/brotli/c/enc/histogram.c +4 -4
- data/vendor/brotli/c/enc/histogram.h +7 -6
- data/vendor/brotli/c/enc/literal_cost.c +20 -15
- data/vendor/brotli/c/enc/literal_cost.h +4 -2
- data/vendor/brotli/c/enc/memory.c +29 -5
- data/vendor/brotli/c/enc/memory.h +43 -14
- data/vendor/brotli/c/enc/metablock.c +95 -85
- data/vendor/brotli/c/enc/metablock.h +9 -8
- data/vendor/brotli/c/enc/metablock_inc.h +9 -7
- data/vendor/brotli/c/enc/params.h +7 -4
- data/vendor/brotli/c/enc/prefix.h +3 -2
- data/vendor/brotli/c/enc/quality.h +40 -3
- data/vendor/brotli/c/enc/ringbuffer.h +8 -4
- data/vendor/brotli/c/enc/state.h +104 -0
- data/vendor/brotli/c/enc/static_dict.c +60 -4
- data/vendor/brotli/c/enc/static_dict.h +3 -2
- data/vendor/brotli/c/enc/static_dict_lut.h +2 -0
- data/vendor/brotli/c/enc/utf8_util.c +2 -2
- data/vendor/brotli/c/enc/utf8_util.h +2 -1
- data/vendor/brotli/c/enc/write_bits.h +29 -26
- data/vendor/brotli/c/include/brotli/decode.h +67 -2
- data/vendor/brotli/c/include/brotli/encode.h +77 -3
- data/vendor/brotli/c/include/brotli/port.h +34 -3
- data/vendor/brotli/c/include/brotli/shared_dictionary.h +100 -0
- metadata +23 -97
- data/.travis.yml +0 -31
- data/docs/Brotli/Error.html +0 -124
- data/docs/Brotli.html +0 -485
- data/docs/_index.html +0 -122
- data/docs/class_list.html +0 -51
- data/docs/css/common.css +0 -1
- data/docs/css/full_list.css +0 -58
- data/docs/css/style.css +0 -496
- data/docs/file.README.html +0 -127
- data/docs/file_list.html +0 -56
- data/docs/frames.html +0 -17
- data/docs/index.html +0 -127
- data/docs/js/app.js +0 -292
- data/docs/js/full_list.js +0 -216
- data/docs/js/jquery.js +0 -4
- data/docs/method_list.html +0 -67
- data/docs/top-level-namespace.html +0 -110
- data/spec/brotli_spec.rb +0 -88
- data/spec/inflate_spec.rb +0 -75
- data/spec/spec_helper.rb +0 -4
@@ -9,10 +9,11 @@
|
|
9
9
|
#ifndef BROTLI_ENC_CLUSTER_H_
|
10
10
|
#define BROTLI_ENC_CLUSTER_H_
|
11
11
|
|
12
|
-
#include "../common/platform.h"
|
13
12
|
#include <brotli/types.h>
|
14
|
-
|
15
|
-
#include "
|
13
|
+
|
14
|
+
#include "../common/platform.h"
|
15
|
+
#include "histogram.h"
|
16
|
+
#include "memory.h"
|
16
17
|
|
17
18
|
#if defined(__cplusplus) || defined(c_plusplus)
|
18
19
|
extern "C" {
|
@@ -28,15 +29,15 @@ typedef struct HistogramPair {
|
|
28
29
|
#define CODE(X) /* Declaration */;
|
29
30
|
|
30
31
|
#define FN(X) X ## Literal
|
31
|
-
#include "
|
32
|
+
#include "cluster_inc.h" /* NOLINT(build/include) */
|
32
33
|
#undef FN
|
33
34
|
|
34
35
|
#define FN(X) X ## Command
|
35
|
-
#include "
|
36
|
+
#include "cluster_inc.h" /* NOLINT(build/include) */
|
36
37
|
#undef FN
|
37
38
|
|
38
39
|
#define FN(X) X ## Distance
|
39
|
-
#include "
|
40
|
+
#include "cluster_inc.h" /* NOLINT(build/include) */
|
40
41
|
#undef FN
|
41
42
|
|
42
43
|
#undef CODE
|
@@ -12,8 +12,8 @@
|
|
12
12
|
/* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if
|
13
13
|
it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */
|
14
14
|
BROTLI_INTERNAL void FN(BrotliCompareAndPushToQueue)(
|
15
|
-
const HistogramType* out, const uint32_t* cluster_size,
|
16
|
-
uint32_t idx2, size_t max_num_pairs, HistogramPair* pairs,
|
15
|
+
const HistogramType* out, HistogramType* tmp, const uint32_t* cluster_size,
|
16
|
+
uint32_t idx1, uint32_t idx2, size_t max_num_pairs, HistogramPair* pairs,
|
17
17
|
size_t* num_pairs) CODE({
|
18
18
|
BROTLI_BOOL is_good_pair = BROTLI_FALSE;
|
19
19
|
HistogramPair p;
|
@@ -42,10 +42,10 @@ BROTLI_INTERNAL void FN(BrotliCompareAndPushToQueue)(
|
|
42
42
|
} else {
|
43
43
|
double threshold = *num_pairs == 0 ? 1e99 :
|
44
44
|
BROTLI_MAX(double, 0.0, pairs[0].cost_diff);
|
45
|
-
HistogramType combo = out[idx1];
|
46
45
|
double cost_combo;
|
47
|
-
|
48
|
-
|
46
|
+
*tmp = out[idx1];
|
47
|
+
FN(HistogramAddHistogram)(tmp, &out[idx2]);
|
48
|
+
cost_combo = FN(BrotliPopulationCost)(tmp);
|
49
49
|
if (cost_combo < threshold - p.cost_diff) {
|
50
50
|
p.cost_combo = cost_combo;
|
51
51
|
is_good_pair = BROTLI_TRUE;
|
@@ -68,6 +68,7 @@ BROTLI_INTERNAL void FN(BrotliCompareAndPushToQueue)(
|
|
68
68
|
})
|
69
69
|
|
70
70
|
BROTLI_INTERNAL size_t FN(BrotliHistogramCombine)(HistogramType* out,
|
71
|
+
HistogramType* tmp,
|
71
72
|
uint32_t* cluster_size,
|
72
73
|
uint32_t* symbols,
|
73
74
|
uint32_t* clusters,
|
@@ -87,7 +88,7 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramCombine)(HistogramType* out,
|
|
87
88
|
for (idx1 = 0; idx1 < num_clusters; ++idx1) {
|
88
89
|
size_t idx2;
|
89
90
|
for (idx2 = idx1 + 1; idx2 < num_clusters; ++idx2) {
|
90
|
-
FN(BrotliCompareAndPushToQueue)(out, cluster_size, clusters[idx1],
|
91
|
+
FN(BrotliCompareAndPushToQueue)(out, tmp, cluster_size, clusters[idx1],
|
91
92
|
clusters[idx2], max_num_pairs, &pairs[0], &num_pairs);
|
92
93
|
}
|
93
94
|
}
|
@@ -146,8 +147,8 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramCombine)(HistogramType* out,
|
|
146
147
|
|
147
148
|
/* Push new pairs formed with the combined histogram to the heap. */
|
148
149
|
for (i = 0; i < num_clusters; ++i) {
|
149
|
-
FN(BrotliCompareAndPushToQueue)(out, cluster_size, best_idx1,
|
150
|
-
|
150
|
+
FN(BrotliCompareAndPushToQueue)(out, tmp, cluster_size, best_idx1,
|
151
|
+
clusters[i], max_num_pairs, &pairs[0], &num_pairs);
|
151
152
|
}
|
152
153
|
}
|
153
154
|
return num_clusters;
|
@@ -155,13 +156,14 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramCombine)(HistogramType* out,
|
|
155
156
|
|
156
157
|
/* What is the bit cost of moving histogram from cur_symbol to candidate. */
|
157
158
|
BROTLI_INTERNAL double FN(BrotliHistogramBitCostDistance)(
|
158
|
-
const HistogramType* histogram, const HistogramType* candidate
|
159
|
+
const HistogramType* histogram, const HistogramType* candidate,
|
160
|
+
HistogramType* tmp) CODE({
|
159
161
|
if (histogram->total_count_ == 0) {
|
160
162
|
return 0.0;
|
161
163
|
} else {
|
162
|
-
|
163
|
-
FN(HistogramAddHistogram)(
|
164
|
-
return FN(BrotliPopulationCost)(
|
164
|
+
*tmp = *histogram;
|
165
|
+
FN(HistogramAddHistogram)(tmp, candidate);
|
166
|
+
return FN(BrotliPopulationCost)(tmp) - candidate->bit_cost_;
|
165
167
|
}
|
166
168
|
})
|
167
169
|
|
@@ -171,16 +173,16 @@ BROTLI_INTERNAL double FN(BrotliHistogramBitCostDistance)(
|
|
171
173
|
Note: we assume that out[]->bit_cost_ is already up-to-date. */
|
172
174
|
BROTLI_INTERNAL void FN(BrotliHistogramRemap)(const HistogramType* in,
|
173
175
|
size_t in_size, const uint32_t* clusters, size_t num_clusters,
|
174
|
-
HistogramType* out, uint32_t* symbols) CODE({
|
176
|
+
HistogramType* out, HistogramType* tmp, uint32_t* symbols) CODE({
|
175
177
|
size_t i;
|
176
178
|
for (i = 0; i < in_size; ++i) {
|
177
179
|
uint32_t best_out = i == 0 ? symbols[0] : symbols[i - 1];
|
178
180
|
double best_bits =
|
179
|
-
FN(BrotliHistogramBitCostDistance)(&in[i], &out[best_out]);
|
181
|
+
FN(BrotliHistogramBitCostDistance)(&in[i], &out[best_out], tmp);
|
180
182
|
size_t j;
|
181
183
|
for (j = 0; j < num_clusters; ++j) {
|
182
184
|
const double cur_bits =
|
183
|
-
FN(BrotliHistogramBitCostDistance)(&in[i], &out[clusters[j]]);
|
185
|
+
FN(BrotliHistogramBitCostDistance)(&in[i], &out[clusters[j]], tmp);
|
184
186
|
if (cur_bits < best_bits) {
|
185
187
|
best_bits = cur_bits;
|
186
188
|
best_out = clusters[j];
|
@@ -215,7 +217,7 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m,
|
|
215
217
|
uint32_t next_index;
|
216
218
|
HistogramType* tmp;
|
217
219
|
size_t i;
|
218
|
-
if (BROTLI_IS_OOM(m)) return 0;
|
220
|
+
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return 0;
|
219
221
|
for (i = 0; i < length; ++i) {
|
220
222
|
new_index[i] = kInvalidIndex;
|
221
223
|
}
|
@@ -226,10 +228,10 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m,
|
|
226
228
|
++next_index;
|
227
229
|
}
|
228
230
|
}
|
229
|
-
/* TODO: by using idea of "cycle-sort" we can avoid allocation of
|
231
|
+
/* TODO(eustas): by using idea of "cycle-sort" we can avoid allocation of
|
230
232
|
tmp and reduce the number of copying by the factor of 2. */
|
231
233
|
tmp = BROTLI_ALLOC(m, HistogramType, next_index);
|
232
|
-
if (BROTLI_IS_OOM(m)) return 0;
|
234
|
+
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp)) return 0;
|
233
235
|
next_index = 0;
|
234
236
|
for (i = 0; i < length; ++i) {
|
235
237
|
if (new_index[symbols[i]] == next_index) {
|
@@ -257,9 +259,14 @@ BROTLI_INTERNAL void FN(BrotliClusterHistograms)(
|
|
257
259
|
size_t pairs_capacity = max_input_histograms * max_input_histograms / 2;
|
258
260
|
/* For the first pass of clustering, we allow all pairs. */
|
259
261
|
HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity + 1);
|
262
|
+
/* TODO(eustas): move to "persistent" arena? */
|
263
|
+
HistogramType* tmp = BROTLI_ALLOC(m, HistogramType, 1);
|
260
264
|
size_t i;
|
261
265
|
|
262
|
-
if (BROTLI_IS_OOM(m))
|
266
|
+
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(cluster_size) ||
|
267
|
+
BROTLI_IS_NULL(clusters) || BROTLI_IS_NULL(pairs)|| BROTLI_IS_NULL(tmp)) {
|
268
|
+
return;
|
269
|
+
}
|
263
270
|
|
264
271
|
for (i = 0; i < in_size; ++i) {
|
265
272
|
cluster_size[i] = 1;
|
@@ -280,7 +287,7 @@ BROTLI_INTERNAL void FN(BrotliClusterHistograms)(
|
|
280
287
|
clusters[num_clusters + j] = (uint32_t)(i + j);
|
281
288
|
}
|
282
289
|
num_new_clusters =
|
283
|
-
FN(BrotliHistogramCombine)(out, cluster_size,
|
290
|
+
FN(BrotliHistogramCombine)(out, tmp, cluster_size,
|
284
291
|
&histogram_symbols[i],
|
285
292
|
&clusters[num_clusters], pairs,
|
286
293
|
num_to_combine, num_to_combine,
|
@@ -298,7 +305,7 @@ BROTLI_INTERNAL void FN(BrotliClusterHistograms)(
|
|
298
305
|
if (BROTLI_IS_OOM(m)) return;
|
299
306
|
|
300
307
|
/* Collapse similar histograms. */
|
301
|
-
num_clusters = FN(BrotliHistogramCombine)(out, cluster_size,
|
308
|
+
num_clusters = FN(BrotliHistogramCombine)(out, tmp, cluster_size,
|
302
309
|
histogram_symbols, clusters,
|
303
310
|
pairs, num_clusters, in_size,
|
304
311
|
max_histograms, max_num_pairs);
|
@@ -307,7 +314,8 @@ BROTLI_INTERNAL void FN(BrotliClusterHistograms)(
|
|
307
314
|
BROTLI_FREE(m, cluster_size);
|
308
315
|
/* Find the optimal map from original histograms to the final ones. */
|
309
316
|
FN(BrotliHistogramRemap)(in, in_size, clusters, num_clusters,
|
310
|
-
out, histogram_symbols);
|
317
|
+
out, tmp, histogram_symbols);
|
318
|
+
BROTLI_FREE(m, tmp);
|
311
319
|
BROTLI_FREE(m, clusters);
|
312
320
|
/* Convert the context map to a canonical form. */
|
313
321
|
*out_size = FN(BrotliHistogramReindex)(m, out, histogram_symbols, in_size);
|
@@ -0,0 +1,28 @@
|
|
1
|
+
/* Copyright 2013 Google Inc. All Rights Reserved.
|
2
|
+
|
3
|
+
Distributed under MIT license.
|
4
|
+
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
5
|
+
*/
|
6
|
+
|
7
|
+
#include "command.h"
|
8
|
+
|
9
|
+
#include <brotli/types.h>
|
10
|
+
|
11
|
+
#if defined(__cplusplus) || defined(c_plusplus)
|
12
|
+
extern "C" {
|
13
|
+
#endif
|
14
|
+
|
15
|
+
const uint32_t kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES] = {
|
16
|
+
0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26,
|
17
|
+
34, 50, 66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594};
|
18
|
+
const uint32_t kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES] = {
|
19
|
+
0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 12, 14, 24};
|
20
|
+
const uint32_t kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES] = {
|
21
|
+
2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18,
|
22
|
+
22, 30, 38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118};
|
23
|
+
const uint32_t kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES] = {
|
24
|
+
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24};
|
25
|
+
|
26
|
+
#if defined(__cplusplus) || defined(c_plusplus)
|
27
|
+
} /* extern "C" */
|
28
|
+
#endif
|
@@ -9,25 +9,26 @@
|
|
9
9
|
#ifndef BROTLI_ENC_COMMAND_H_
|
10
10
|
#define BROTLI_ENC_COMMAND_H_
|
11
11
|
|
12
|
+
#include <brotli/types.h>
|
13
|
+
|
12
14
|
#include "../common/constants.h"
|
13
15
|
#include "../common/platform.h"
|
14
|
-
#include
|
15
|
-
#include "
|
16
|
-
#include "
|
17
|
-
#include "./prefix.h"
|
16
|
+
#include "fast_log.h"
|
17
|
+
#include "params.h"
|
18
|
+
#include "prefix.h"
|
18
19
|
|
19
20
|
#if defined(__cplusplus) || defined(c_plusplus)
|
20
21
|
extern "C" {
|
21
22
|
#endif
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
BROTLI_INTERNAL extern const uint32_t
|
25
|
+
kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES];
|
26
|
+
BROTLI_INTERNAL extern const uint32_t
|
27
|
+
kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES];
|
28
|
+
BROTLI_INTERNAL extern const uint32_t
|
29
|
+
kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES];
|
30
|
+
BROTLI_INTERNAL extern const uint32_t
|
31
|
+
kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES];
|
31
32
|
|
32
33
|
static BROTLI_INLINE uint16_t GetInsertLengthCode(size_t insertlen) {
|
33
34
|
if (insertlen < 6) {
|
@@ -89,19 +90,19 @@ static BROTLI_INLINE void GetLengthCode(size_t insertlen, size_t copylen,
|
|
89
90
|
}
|
90
91
|
|
91
92
|
static BROTLI_INLINE uint32_t GetInsertBase(uint16_t inscode) {
|
92
|
-
return
|
93
|
+
return kBrotliInsBase[inscode];
|
93
94
|
}
|
94
95
|
|
95
96
|
static BROTLI_INLINE uint32_t GetInsertExtra(uint16_t inscode) {
|
96
|
-
return
|
97
|
+
return kBrotliInsExtra[inscode];
|
97
98
|
}
|
98
99
|
|
99
100
|
static BROTLI_INLINE uint32_t GetCopyBase(uint16_t copycode) {
|
100
|
-
return
|
101
|
+
return kBrotliCopyBase[copycode];
|
101
102
|
}
|
102
103
|
|
103
104
|
static BROTLI_INLINE uint32_t GetCopyExtra(uint16_t copycode) {
|
104
|
-
return
|
105
|
+
return kBrotliCopyExtra[copycode];
|
105
106
|
}
|
106
107
|
|
107
108
|
typedef struct Command {
|
@@ -0,0 +1,207 @@
|
|
1
|
+
/* Copyright 2017 Google Inc. All Rights Reserved.
|
2
|
+
|
3
|
+
Distributed under MIT license.
|
4
|
+
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
5
|
+
*/
|
6
|
+
|
7
|
+
#include "compound_dictionary.h"
|
8
|
+
|
9
|
+
#include <brotli/types.h>
|
10
|
+
|
11
|
+
#include "../common/platform.h"
|
12
|
+
#include "memory.h"
|
13
|
+
#include "quality.h"
|
14
|
+
|
15
|
+
static PreparedDictionary* CreatePreparedDictionaryWithParams(MemoryManager* m,
|
16
|
+
const uint8_t* source, size_t source_size, uint32_t bucket_bits,
|
17
|
+
uint32_t slot_bits, uint32_t hash_bits, uint16_t bucket_limit) {
|
18
|
+
/* Step 1: create "bloated" hasher. */
|
19
|
+
uint32_t num_slots = 1u << slot_bits;
|
20
|
+
uint32_t num_buckets = 1u << bucket_bits;
|
21
|
+
uint32_t hash_shift = 64u - bucket_bits;
|
22
|
+
uint64_t hash_mask = (~((uint64_t)0U)) >> (64 - hash_bits);
|
23
|
+
uint32_t slot_mask = num_slots - 1;
|
24
|
+
size_t alloc_size = (sizeof(uint32_t) << slot_bits) +
|
25
|
+
(sizeof(uint32_t) << slot_bits) +
|
26
|
+
(sizeof(uint16_t) << bucket_bits) +
|
27
|
+
(sizeof(uint32_t) << bucket_bits) +
|
28
|
+
(sizeof(uint32_t) * source_size);
|
29
|
+
uint8_t* flat = NULL;
|
30
|
+
PreparedDictionary* result = NULL;
|
31
|
+
uint16_t* num = NULL;
|
32
|
+
uint32_t* bucket_heads = NULL;
|
33
|
+
uint32_t* next_bucket = NULL;
|
34
|
+
uint32_t* slot_offsets = NULL;
|
35
|
+
uint16_t* heads = NULL;
|
36
|
+
uint32_t* items = NULL;
|
37
|
+
uint8_t** source_ref = NULL;
|
38
|
+
uint32_t i;
|
39
|
+
uint32_t* slot_size = NULL;
|
40
|
+
uint32_t* slot_limit = NULL;
|
41
|
+
uint32_t total_items = 0;
|
42
|
+
if (slot_bits > 16) return NULL;
|
43
|
+
if (slot_bits > bucket_bits) return NULL;
|
44
|
+
if (bucket_bits - slot_bits >= 16) return NULL;
|
45
|
+
|
46
|
+
flat = BROTLI_ALLOC(m, uint8_t, alloc_size);
|
47
|
+
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(flat)) return NULL;
|
48
|
+
|
49
|
+
slot_size = (uint32_t*)flat;
|
50
|
+
slot_limit = (uint32_t*)(&slot_size[num_slots]);
|
51
|
+
num = (uint16_t*)(&slot_limit[num_slots]);
|
52
|
+
bucket_heads = (uint32_t*)(&num[num_buckets]);
|
53
|
+
next_bucket = (uint32_t*)(&bucket_heads[num_buckets]);
|
54
|
+
memset(num, 0, num_buckets * sizeof(num[0]));
|
55
|
+
|
56
|
+
/* TODO(eustas): apply custom "store" order. */
|
57
|
+
for (i = 0; i + 7 < source_size; ++i) {
|
58
|
+
const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(&source[i]) & hash_mask) *
|
59
|
+
kPreparedDictionaryHashMul64Long;
|
60
|
+
const uint32_t key = (uint32_t)(h >> hash_shift);
|
61
|
+
uint16_t count = num[key];
|
62
|
+
next_bucket[i] = (count == 0) ? ((uint32_t)(-1)) : bucket_heads[key];
|
63
|
+
bucket_heads[key] = i;
|
64
|
+
count++;
|
65
|
+
if (count > bucket_limit) count = bucket_limit;
|
66
|
+
num[key] = count;
|
67
|
+
}
|
68
|
+
|
69
|
+
/* Step 2: find slot limits. */
|
70
|
+
for (i = 0; i < num_slots; ++i) {
|
71
|
+
BROTLI_BOOL overflow = BROTLI_FALSE;
|
72
|
+
slot_limit[i] = bucket_limit;
|
73
|
+
while (BROTLI_TRUE) {
|
74
|
+
uint32_t limit = slot_limit[i];
|
75
|
+
size_t j;
|
76
|
+
uint32_t count = 0;
|
77
|
+
overflow = BROTLI_FALSE;
|
78
|
+
for (j = i; j < num_buckets; j += num_slots) {
|
79
|
+
uint32_t size = num[j];
|
80
|
+
/* Last chain may span behind 64K limit; overflow happens only if
|
81
|
+
we are about to use 0xFFFF+ as item offset. */
|
82
|
+
if (count >= 0xFFFF) {
|
83
|
+
overflow = BROTLI_TRUE;
|
84
|
+
break;
|
85
|
+
}
|
86
|
+
if (size > limit) size = limit;
|
87
|
+
count += size;
|
88
|
+
}
|
89
|
+
if (!overflow) {
|
90
|
+
slot_size[i] = count;
|
91
|
+
total_items += count;
|
92
|
+
break;
|
93
|
+
}
|
94
|
+
slot_limit[i]--;
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
/* Step 3: transfer data to "slim" hasher. */
|
99
|
+
alloc_size = sizeof(PreparedDictionary) + (sizeof(uint32_t) << slot_bits) +
|
100
|
+
(sizeof(uint16_t) << bucket_bits) + (sizeof(uint32_t) * total_items) +
|
101
|
+
sizeof(uint8_t*);
|
102
|
+
|
103
|
+
result = (PreparedDictionary*)BROTLI_ALLOC(m, uint8_t, alloc_size);
|
104
|
+
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(result)) {
|
105
|
+
BROTLI_FREE(m, flat);
|
106
|
+
return NULL;
|
107
|
+
}
|
108
|
+
slot_offsets = (uint32_t*)(&result[1]);
|
109
|
+
heads = (uint16_t*)(&slot_offsets[num_slots]);
|
110
|
+
items = (uint32_t*)(&heads[num_buckets]);
|
111
|
+
source_ref = (uint8_t**)(&items[total_items]);
|
112
|
+
|
113
|
+
result->magic = kLeanPreparedDictionaryMagic;
|
114
|
+
result->num_items = total_items;
|
115
|
+
result->source_size = (uint32_t)source_size;
|
116
|
+
result->hash_bits = hash_bits;
|
117
|
+
result->bucket_bits = bucket_bits;
|
118
|
+
result->slot_bits = slot_bits;
|
119
|
+
BROTLI_UNALIGNED_STORE_PTR(source_ref, source);
|
120
|
+
|
121
|
+
total_items = 0;
|
122
|
+
for (i = 0; i < num_slots; ++i) {
|
123
|
+
slot_offsets[i] = total_items;
|
124
|
+
total_items += slot_size[i];
|
125
|
+
slot_size[i] = 0;
|
126
|
+
}
|
127
|
+
for (i = 0; i < num_buckets; ++i) {
|
128
|
+
uint32_t slot = i & slot_mask;
|
129
|
+
uint32_t count = num[i];
|
130
|
+
uint32_t pos;
|
131
|
+
size_t j;
|
132
|
+
size_t cursor = slot_size[slot];
|
133
|
+
if (count > slot_limit[slot]) count = slot_limit[slot];
|
134
|
+
if (count == 0) {
|
135
|
+
heads[i] = 0xFFFF;
|
136
|
+
continue;
|
137
|
+
}
|
138
|
+
heads[i] = (uint16_t)cursor;
|
139
|
+
cursor += slot_offsets[slot];
|
140
|
+
slot_size[slot] += count;
|
141
|
+
pos = bucket_heads[i];
|
142
|
+
for (j = 0; j < count; j++) {
|
143
|
+
items[cursor++] = pos;
|
144
|
+
pos = next_bucket[pos];
|
145
|
+
}
|
146
|
+
items[cursor - 1] |= 0x80000000;
|
147
|
+
}
|
148
|
+
|
149
|
+
BROTLI_FREE(m, flat);
|
150
|
+
return result;
|
151
|
+
}
|
152
|
+
|
153
|
+
PreparedDictionary* CreatePreparedDictionary(MemoryManager* m,
|
154
|
+
const uint8_t* source, size_t source_size) {
|
155
|
+
uint32_t bucket_bits = 17;
|
156
|
+
uint32_t slot_bits = 7;
|
157
|
+
uint32_t hash_bits = 40;
|
158
|
+
uint16_t bucket_limit = 32;
|
159
|
+
size_t volume = 16u << bucket_bits;
|
160
|
+
/* Tune parameters to fit dictionary size. */
|
161
|
+
while (volume < source_size && bucket_bits < 22) {
|
162
|
+
bucket_bits++;
|
163
|
+
slot_bits++;
|
164
|
+
volume <<= 1;
|
165
|
+
}
|
166
|
+
return CreatePreparedDictionaryWithParams(m,
|
167
|
+
source, source_size, bucket_bits, slot_bits, hash_bits, bucket_limit);
|
168
|
+
}
|
169
|
+
|
170
|
+
void DestroyPreparedDictionary(MemoryManager* m,
|
171
|
+
PreparedDictionary* dictionary) {
|
172
|
+
if (!dictionary) return;
|
173
|
+
BROTLI_FREE(m, dictionary);
|
174
|
+
}
|
175
|
+
|
176
|
+
BROTLI_BOOL AttachPreparedDictionary(
|
177
|
+
CompoundDictionary* compound, const PreparedDictionary* dictionary) {
|
178
|
+
size_t length = 0;
|
179
|
+
size_t index = 0;
|
180
|
+
|
181
|
+
if (compound->num_chunks == SHARED_BROTLI_MAX_COMPOUND_DICTS) {
|
182
|
+
return BROTLI_FALSE;
|
183
|
+
}
|
184
|
+
|
185
|
+
if (!dictionary) return BROTLI_FALSE;
|
186
|
+
|
187
|
+
length = dictionary->source_size;
|
188
|
+
index = compound->num_chunks;
|
189
|
+
compound->total_size += length;
|
190
|
+
compound->chunks[index] = dictionary;
|
191
|
+
compound->chunk_offsets[index + 1] = compound->total_size;
|
192
|
+
{
|
193
|
+
uint32_t* slot_offsets = (uint32_t*)(&dictionary[1]);
|
194
|
+
uint16_t* heads = (uint16_t*)(&slot_offsets[1u << dictionary->slot_bits]);
|
195
|
+
uint32_t* items = (uint32_t*)(&heads[1u << dictionary->bucket_bits]);
|
196
|
+
const void* tail = (void*)&items[dictionary->num_items];
|
197
|
+
if (dictionary->magic == kPreparedDictionaryMagic) {
|
198
|
+
compound->chunk_source[index] = (const uint8_t*)tail;
|
199
|
+
} else {
|
200
|
+
/* dictionary->magic == kLeanPreparedDictionaryMagic */
|
201
|
+
compound->chunk_source[index] =
|
202
|
+
(const uint8_t*)BROTLI_UNALIGNED_LOAD_PTR((const uint8_t**)tail);
|
203
|
+
}
|
204
|
+
}
|
205
|
+
compound->num_chunks++;
|
206
|
+
return BROTLI_TRUE;
|
207
|
+
}
|
@@ -0,0 +1,74 @@
|
|
1
|
+
/* Copyright 2017 Google Inc. All Rights Reserved.
|
2
|
+
|
3
|
+
Distributed under MIT license.
|
4
|
+
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
5
|
+
*/
|
6
|
+
|
7
|
+
#ifndef BROTLI_ENC_PREPARED_DICTIONARY_H_
|
8
|
+
#define BROTLI_ENC_PREPARED_DICTIONARY_H_
|
9
|
+
|
10
|
+
#include <brotli/shared_dictionary.h>
|
11
|
+
#include <brotli/types.h>
|
12
|
+
|
13
|
+
#include "../common/platform.h"
|
14
|
+
#include "../common/constants.h"
|
15
|
+
#include "memory.h"
|
16
|
+
|
17
|
+
/* "Fat" prepared dictionary, could be cooked outside of C implementation,
|
18
|
+
* e.g. on Java side. LZ77 data is copied inside PreparedDictionary struct. */
|
19
|
+
static const uint32_t kPreparedDictionaryMagic = 0xDEBCEDE0;
|
20
|
+
|
21
|
+
static const uint32_t kSharedDictionaryMagic = 0xDEBCEDE1;
|
22
|
+
|
23
|
+
static const uint32_t kManagedDictionaryMagic = 0xDEBCEDE2;
|
24
|
+
|
25
|
+
/* "Lean" prepared dictionary. LZ77 data is referenced. It is the responsibility
|
26
|
+
* of caller of "prepare dictionary" to keep the LZ77 data while prepared
|
27
|
+
* dictionary is in use. */
|
28
|
+
static const uint32_t kLeanPreparedDictionaryMagic = 0xDEBCEDE3;
|
29
|
+
|
30
|
+
static const uint64_t kPreparedDictionaryHashMul64Long =
|
31
|
+
BROTLI_MAKE_UINT64_T(0x1FE35A7Bu, 0xD3579BD3u);
|
32
|
+
|
33
|
+
typedef struct PreparedDictionary {
|
34
|
+
uint32_t magic;
|
35
|
+
uint32_t num_items;
|
36
|
+
uint32_t source_size;
|
37
|
+
uint32_t hash_bits;
|
38
|
+
uint32_t bucket_bits;
|
39
|
+
uint32_t slot_bits;
|
40
|
+
|
41
|
+
/* --- Dynamic size members --- */
|
42
|
+
|
43
|
+
/* uint32_t slot_offsets[1 << slot_bits]; */
|
44
|
+
/* uint16_t heads[1 << bucket_bits]; */
|
45
|
+
/* uint32_t items[variable]; */
|
46
|
+
|
47
|
+
/* [maybe] uint8_t* source_ref, depending on magic. */
|
48
|
+
/* [maybe] uint8_t source[source_size], depending on magic. */
|
49
|
+
} PreparedDictionary;
|
50
|
+
|
51
|
+
BROTLI_INTERNAL PreparedDictionary* CreatePreparedDictionary(MemoryManager* m,
|
52
|
+
const uint8_t* source, size_t source_size);
|
53
|
+
|
54
|
+
BROTLI_INTERNAL void DestroyPreparedDictionary(MemoryManager* m,
|
55
|
+
PreparedDictionary* dictionary);
|
56
|
+
|
57
|
+
typedef struct CompoundDictionary {
|
58
|
+
/* LZ77 prefix, compound dictionary */
|
59
|
+
size_t num_chunks;
|
60
|
+
size_t total_size;
|
61
|
+
/* Client instances. */
|
62
|
+
const PreparedDictionary* chunks[SHARED_BROTLI_MAX_COMPOUND_DICTS + 1];
|
63
|
+
const uint8_t* chunk_source[SHARED_BROTLI_MAX_COMPOUND_DICTS + 1];
|
64
|
+
size_t chunk_offsets[SHARED_BROTLI_MAX_COMPOUND_DICTS + 1];
|
65
|
+
|
66
|
+
size_t num_prepared_instances_;
|
67
|
+
/* Owned instances. */
|
68
|
+
PreparedDictionary* prepared_instances_[SHARED_BROTLI_MAX_COMPOUND_DICTS + 1];
|
69
|
+
} CompoundDictionary;
|
70
|
+
|
71
|
+
BROTLI_INTERNAL BROTLI_BOOL AttachPreparedDictionary(
|
72
|
+
CompoundDictionary* compound, const PreparedDictionary* dictionary);
|
73
|
+
|
74
|
+
#endif /* BROTLI_ENC_PREPARED_DICTIONARY */
|