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