brotli 0.2.0 → 0.4.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 +5 -5
- data/.github/workflows/main.yml +34 -0
- data/.github/workflows/publish.yml +34 -0
- data/Gemfile +6 -2
- data/Rakefile +18 -6
- data/bin/before_install.sh +9 -0
- data/brotli.gemspec +7 -13
- data/ext/brotli/brotli.c +209 -11
- data/ext/brotli/buffer.c +1 -7
- data/ext/brotli/buffer.h +1 -1
- data/ext/brotli/extconf.rb +45 -26
- data/lib/brotli/version.rb +1 -1
- data/smoke.sh +1 -1
- data/test/brotli_test.rb +104 -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 +149 -6
- data/vendor/brotli/c/{dec/context.h → common/context.c} +91 -186
- data/vendor/brotli/c/common/context.h +113 -0
- data/vendor/brotli/c/common/dictionary.bin +0 -0
- data/vendor/brotli/c/common/dictionary.bin.br +0 -0
- data/vendor/brotli/c/common/dictionary.c +11 -2
- data/vendor/brotli/c/common/dictionary.h +4 -4
- data/vendor/brotli/c/common/platform.c +22 -0
- data/vendor/brotli/c/common/platform.h +594 -0
- data/vendor/brotli/c/common/transform.c +291 -0
- data/vendor/brotli/c/common/transform.h +85 -0
- data/vendor/brotli/c/common/version.h +8 -1
- data/vendor/brotli/c/dec/bit_reader.c +29 -1
- data/vendor/brotli/c/dec/bit_reader.h +91 -100
- data/vendor/brotli/c/dec/decode.c +665 -437
- data/vendor/brotli/c/dec/huffman.c +65 -84
- data/vendor/brotli/c/dec/huffman.h +67 -14
- data/vendor/brotli/c/dec/prefix.h +1 -20
- data/vendor/brotli/c/dec/state.c +32 -45
- data/vendor/brotli/c/dec/state.h +173 -55
- data/vendor/brotli/c/enc/backward_references.c +27 -16
- data/vendor/brotli/c/enc/backward_references.h +7 -7
- data/vendor/brotli/c/enc/backward_references_hq.c +155 -116
- data/vendor/brotli/c/enc/backward_references_hq.h +22 -23
- data/vendor/brotli/c/enc/backward_references_inc.h +32 -22
- data/vendor/brotli/c/enc/bit_cost.c +1 -1
- data/vendor/brotli/c/enc/bit_cost.h +5 -5
- data/vendor/brotli/c/enc/block_encoder_inc.h +7 -6
- data/vendor/brotli/c/enc/block_splitter.c +5 -6
- data/vendor/brotli/c/enc/block_splitter.h +1 -1
- data/vendor/brotli/c/enc/block_splitter_inc.h +26 -17
- data/vendor/brotli/c/enc/brotli_bit_stream.c +107 -123
- data/vendor/brotli/c/enc/brotli_bit_stream.h +19 -38
- data/vendor/brotli/c/enc/cluster.c +1 -1
- data/vendor/brotli/c/enc/cluster.h +1 -1
- data/vendor/brotli/c/enc/cluster_inc.h +6 -3
- data/vendor/brotli/c/enc/command.c +28 -0
- data/vendor/brotli/c/enc/command.h +52 -42
- data/vendor/brotli/c/enc/compress_fragment.c +21 -22
- data/vendor/brotli/c/enc/compress_fragment.h +1 -1
- data/vendor/brotli/c/enc/compress_fragment_two_pass.c +102 -69
- data/vendor/brotli/c/enc/compress_fragment_two_pass.h +1 -1
- data/vendor/brotli/c/enc/dictionary_hash.c +1827 -1101
- data/vendor/brotli/c/enc/dictionary_hash.h +2 -1
- data/vendor/brotli/c/enc/encode.c +358 -195
- data/vendor/brotli/c/enc/encoder_dict.c +33 -0
- data/vendor/brotli/c/enc/encoder_dict.h +43 -0
- data/vendor/brotli/c/enc/entropy_encode.c +16 -14
- data/vendor/brotli/c/enc/entropy_encode.h +7 -7
- data/vendor/brotli/c/enc/entropy_encode_static.h +3 -3
- data/vendor/brotli/c/enc/fast_log.c +105 -0
- data/vendor/brotli/c/enc/fast_log.h +20 -99
- data/vendor/brotli/c/enc/find_match_length.h +5 -6
- data/vendor/brotli/c/enc/hash.h +145 -103
- data/vendor/brotli/c/enc/hash_composite_inc.h +125 -0
- data/vendor/brotli/c/enc/hash_forgetful_chain_inc.h +93 -53
- data/vendor/brotli/c/enc/hash_longest_match64_inc.h +54 -53
- data/vendor/brotli/c/enc/hash_longest_match_inc.h +58 -54
- data/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h +95 -63
- data/vendor/brotli/c/enc/hash_rolling_inc.h +212 -0
- data/vendor/brotli/c/enc/hash_to_binary_tree_inc.h +46 -43
- data/vendor/brotli/c/enc/histogram.c +9 -6
- data/vendor/brotli/c/enc/histogram.h +6 -3
- data/vendor/brotli/c/enc/histogram_inc.h +1 -1
- data/vendor/brotli/c/enc/literal_cost.c +5 -5
- data/vendor/brotli/c/enc/literal_cost.h +2 -2
- data/vendor/brotli/c/enc/memory.c +5 -16
- data/vendor/brotli/c/enc/memory.h +52 -1
- data/vendor/brotli/c/enc/metablock.c +171 -36
- data/vendor/brotli/c/enc/metablock.h +13 -8
- data/vendor/brotli/c/enc/metablock_inc.h +2 -2
- data/vendor/brotli/c/enc/params.h +46 -0
- data/vendor/brotli/c/enc/prefix.h +3 -4
- data/vendor/brotli/c/enc/quality.h +29 -24
- data/vendor/brotli/c/enc/ringbuffer.h +19 -12
- data/vendor/brotli/c/enc/static_dict.c +49 -45
- data/vendor/brotli/c/enc/static_dict.h +4 -3
- data/vendor/brotli/c/enc/static_dict_lut.h +1 -1
- data/vendor/brotli/c/enc/utf8_util.c +21 -21
- data/vendor/brotli/c/enc/utf8_util.h +1 -1
- data/vendor/brotli/c/enc/write_bits.h +35 -38
- data/vendor/brotli/c/include/brotli/decode.h +13 -8
- data/vendor/brotli/c/include/brotli/encode.h +54 -8
- data/vendor/brotli/c/include/brotli/port.h +225 -83
- data/vendor/brotli/c/include/brotli/types.h +0 -7
- metadata +28 -87
- data/.travis.yml +0 -30
- data/spec/brotli_spec.rb +0 -88
- data/spec/inflate_spec.rb +0 -75
- data/spec/spec_helper.rb +0 -4
- data/vendor/brotli/c/dec/port.h +0 -168
- data/vendor/brotli/c/dec/transform.h +0 -300
- data/vendor/brotli/c/enc/context.h +0 -184
- data/vendor/brotli/c/enc/port.h +0 -184
@@ -28,8 +28,8 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
|
|
28
28
|
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
|
29
29
|
|
30
30
|
/* HashBytes is the function that chooses the bucket to place the address in.*/
|
31
|
-
static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t
|
32
|
-
const uint32_t h =
|
31
|
+
static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data) {
|
32
|
+
const uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
|
33
33
|
/* The higher bits contain more mixture from the multiplication,
|
34
34
|
so we take our results from there. */
|
35
35
|
return h >> (32 - BUCKET_BITS);
|
@@ -45,28 +45,56 @@ typedef struct FN(Bank) {
|
|
45
45
|
} FN(Bank);
|
46
46
|
|
47
47
|
typedef struct HashForgetfulChain {
|
48
|
-
|
49
|
-
uint16_t head[BUCKET_SIZE];
|
50
|
-
/* Truncated hash used for quick rejection of "distance cache" candidates. */
|
51
|
-
uint8_t tiny_hash[65536];
|
52
|
-
FN(Bank) banks[NUM_BANKS];
|
53
|
-
uint16_t free_slot_idx[NUM_BANKS];
|
48
|
+
uint16_t free_slot_idx[NUM_BANKS]; /* Up to 1KiB. Move to dynamic? */
|
54
49
|
size_t max_hops;
|
50
|
+
|
51
|
+
/* Shortcuts. */
|
52
|
+
void* extra;
|
53
|
+
HasherCommon* common;
|
54
|
+
|
55
|
+
/* --- Dynamic size members --- */
|
56
|
+
|
57
|
+
/* uint32_t addr[BUCKET_SIZE]; */
|
58
|
+
|
59
|
+
/* uint16_t head[BUCKET_SIZE]; */
|
60
|
+
|
61
|
+
/* Truncated hash used for quick rejection of "distance cache" candidates. */
|
62
|
+
/* uint8_t tiny_hash[65536];*/
|
63
|
+
|
64
|
+
/* FN(Bank) banks[NUM_BANKS]; */
|
55
65
|
} HashForgetfulChain;
|
56
66
|
|
57
|
-
static
|
58
|
-
return (
|
67
|
+
static uint32_t* FN(Addr)(void* extra) {
|
68
|
+
return (uint32_t*)extra;
|
69
|
+
}
|
70
|
+
|
71
|
+
static uint16_t* FN(Head)(void* extra) {
|
72
|
+
return (uint16_t*)(&FN(Addr)(extra)[BUCKET_SIZE]);
|
73
|
+
}
|
74
|
+
|
75
|
+
static uint8_t* FN(TinyHash)(void* extra) {
|
76
|
+
return (uint8_t*)(&FN(Head)(extra)[BUCKET_SIZE]);
|
77
|
+
}
|
78
|
+
|
79
|
+
static FN(Bank)* FN(Banks)(void* extra) {
|
80
|
+
return (FN(Bank)*)(&FN(TinyHash)(extra)[65536]);
|
59
81
|
}
|
60
82
|
|
61
83
|
static void FN(Initialize)(
|
62
|
-
|
63
|
-
|
64
|
-
|
84
|
+
HasherCommon* common, HashForgetfulChain* BROTLI_RESTRICT self,
|
85
|
+
const BrotliEncoderParams* params) {
|
86
|
+
self->common = common;
|
87
|
+
self->extra = common->extra;
|
88
|
+
|
89
|
+
self->max_hops = (params->quality > 6 ? 7u : 8u) << (params->quality - 4);
|
65
90
|
}
|
66
91
|
|
67
|
-
static void FN(Prepare)(
|
68
|
-
|
69
|
-
|
92
|
+
static void FN(Prepare)(
|
93
|
+
HashForgetfulChain* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
94
|
+
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
95
|
+
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
|
96
|
+
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
|
97
|
+
uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra);
|
70
98
|
/* Partial preparation is 100 times slower (per socket). */
|
71
99
|
size_t partial_prepare_threshold = BUCKET_SIZE >> 6;
|
72
100
|
if (one_shot && input_size <= partial_prepare_threshold) {
|
@@ -74,17 +102,17 @@ static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
|
|
74
102
|
for (i = 0; i < input_size; ++i) {
|
75
103
|
size_t bucket = FN(HashBytes)(&data[i]);
|
76
104
|
/* See InitEmpty comment. */
|
77
|
-
|
78
|
-
|
105
|
+
addr[bucket] = 0xCCCCCCCC;
|
106
|
+
head[bucket] = 0xCCCC;
|
79
107
|
}
|
80
108
|
} else {
|
81
109
|
/* Fill |addr| array with 0xCCCCCCCC value. Because of wrapping, position
|
82
110
|
processed by hasher never reaches 3GB + 64M; this makes all new chains
|
83
111
|
to be terminated after the first node. */
|
84
|
-
memset(
|
85
|
-
memset(
|
112
|
+
memset(addr, 0xCC, sizeof(uint32_t) * BUCKET_SIZE);
|
113
|
+
memset(head, 0, sizeof(uint16_t) * BUCKET_SIZE);
|
86
114
|
}
|
87
|
-
memset(
|
115
|
+
memset(tiny_hash, 0, sizeof(uint8_t) * 65536);
|
88
116
|
memset(self->free_slot_idx, 0, sizeof(self->free_slot_idx));
|
89
117
|
}
|
90
118
|
|
@@ -94,51 +122,58 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
|
94
122
|
BROTLI_UNUSED(params);
|
95
123
|
BROTLI_UNUSED(one_shot);
|
96
124
|
BROTLI_UNUSED(input_size);
|
97
|
-
return sizeof(
|
125
|
+
return sizeof(uint32_t) * BUCKET_SIZE + sizeof(uint16_t) * BUCKET_SIZE +
|
126
|
+
sizeof(uint8_t) * 65536 + sizeof(FN(Bank)) * NUM_BANKS;
|
98
127
|
}
|
99
128
|
|
100
129
|
/* Look at 4 bytes at &data[ix & mask]. Compute a hash from these, and prepend
|
101
130
|
node to corresponding chain; also update tiny_hash for current position. */
|
102
|
-
static BROTLI_INLINE void FN(Store)(
|
131
|
+
static BROTLI_INLINE void FN(Store)(HashForgetfulChain* BROTLI_RESTRICT self,
|
103
132
|
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
|
104
|
-
|
133
|
+
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
|
134
|
+
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
|
135
|
+
uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra);
|
136
|
+
FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra);
|
105
137
|
const size_t key = FN(HashBytes)(&data[ix & mask]);
|
106
138
|
const size_t bank = key & (NUM_BANKS - 1);
|
107
139
|
const size_t idx = self->free_slot_idx[bank]++ & (BANK_SIZE - 1);
|
108
|
-
size_t delta = ix -
|
109
|
-
|
140
|
+
size_t delta = ix - addr[key];
|
141
|
+
tiny_hash[(uint16_t)ix] = (uint8_t)key;
|
110
142
|
if (delta > 0xFFFF) delta = CAPPED_CHAINS ? 0 : 0xFFFF;
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
143
|
+
banks[bank].slots[idx].delta = (uint16_t)delta;
|
144
|
+
banks[bank].slots[idx].next = head[key];
|
145
|
+
addr[key] = (uint32_t)ix;
|
146
|
+
head[key] = (uint16_t)idx;
|
115
147
|
}
|
116
148
|
|
117
|
-
static BROTLI_INLINE void FN(StoreRange)(
|
118
|
-
|
119
|
-
const size_t
|
149
|
+
static BROTLI_INLINE void FN(StoreRange)(
|
150
|
+
HashForgetfulChain* BROTLI_RESTRICT self,
|
151
|
+
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
152
|
+
const size_t ix_start, const size_t ix_end) {
|
120
153
|
size_t i;
|
121
154
|
for (i = ix_start; i < ix_end; ++i) {
|
122
|
-
FN(Store)(
|
155
|
+
FN(Store)(self, data, mask, i);
|
123
156
|
}
|
124
157
|
}
|
125
158
|
|
126
|
-
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
159
|
+
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
160
|
+
HashForgetfulChain* BROTLI_RESTRICT self,
|
127
161
|
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
128
162
|
size_t ring_buffer_mask) {
|
129
163
|
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
130
164
|
/* Prepare the hashes for three last bytes of the last write.
|
131
165
|
These could not be calculated before, since they require knowledge
|
132
166
|
of both the previous and the current block. */
|
133
|
-
FN(Store)(
|
134
|
-
FN(Store)(
|
135
|
-
FN(Store)(
|
167
|
+
FN(Store)(self, ringbuffer, ring_buffer_mask, position - 3);
|
168
|
+
FN(Store)(self, ringbuffer, ring_buffer_mask, position - 2);
|
169
|
+
FN(Store)(self, ringbuffer, ring_buffer_mask, position - 1);
|
136
170
|
}
|
137
171
|
}
|
138
172
|
|
139
173
|
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
140
|
-
|
141
|
-
|
174
|
+
HashForgetfulChain* BROTLI_RESTRICT self,
|
175
|
+
int* BROTLI_RESTRICT distance_cache) {
|
176
|
+
BROTLI_UNUSED(self);
|
142
177
|
PrepareDistanceCache(distance_cache, NUM_LAST_DISTANCES_TO_CHECK);
|
143
178
|
}
|
144
179
|
|
@@ -153,13 +188,18 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
|
153
188
|
Does not look for matches further away than max_backward.
|
154
189
|
Writes the best match into |out|.
|
155
190
|
|out|->score is updated only if a better match is found. */
|
156
|
-
static BROTLI_INLINE void FN(FindLongestMatch)(
|
157
|
-
|
191
|
+
static BROTLI_INLINE void FN(FindLongestMatch)(
|
192
|
+
HashForgetfulChain* BROTLI_RESTRICT self,
|
193
|
+
const BrotliEncoderDictionary* dictionary,
|
158
194
|
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
159
195
|
const int* BROTLI_RESTRICT distance_cache,
|
160
196
|
const size_t cur_ix, const size_t max_length, const size_t max_backward,
|
161
|
-
const size_t
|
162
|
-
|
197
|
+
const size_t dictionary_distance, const size_t max_distance,
|
198
|
+
HasherSearchResult* BROTLI_RESTRICT out) {
|
199
|
+
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
|
200
|
+
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
|
201
|
+
uint8_t* BROTLI_RESTRICT tiny_hashes = FN(TinyHash)(self->extra);
|
202
|
+
FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra);
|
163
203
|
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
164
204
|
/* Don't accept a short copy from far away. */
|
165
205
|
score_t min_score = out->score;
|
@@ -175,7 +215,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|
175
215
|
const size_t backward = (size_t)distance_cache[i];
|
176
216
|
size_t prev_ix = (cur_ix - backward);
|
177
217
|
/* For distance code 0 we want to consider 2-byte matches. */
|
178
|
-
if (i > 0 &&
|
218
|
+
if (i > 0 && tiny_hashes[(uint16_t)prev_ix] != tiny_hash) continue;
|
179
219
|
if (prev_ix >= cur_ix || backward > max_backward) {
|
180
220
|
continue;
|
181
221
|
}
|
@@ -203,16 +243,16 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|
203
243
|
const size_t bank = key & (NUM_BANKS - 1);
|
204
244
|
size_t backward = 0;
|
205
245
|
size_t hops = self->max_hops;
|
206
|
-
size_t delta = cur_ix -
|
207
|
-
size_t slot =
|
246
|
+
size_t delta = cur_ix - addr[key];
|
247
|
+
size_t slot = head[key];
|
208
248
|
while (hops--) {
|
209
249
|
size_t prev_ix;
|
210
250
|
size_t last = slot;
|
211
251
|
backward += delta;
|
212
252
|
if (backward > max_backward || (CAPPED_CHAINS && !delta)) break;
|
213
253
|
prev_ix = (cur_ix - backward) & ring_buffer_mask;
|
214
|
-
slot =
|
215
|
-
delta =
|
254
|
+
slot = banks[bank].slots[last].next;
|
255
|
+
delta = banks[bank].slots[last].delta;
|
216
256
|
if (cur_ix_masked + best_len > ring_buffer_mask ||
|
217
257
|
prev_ix + best_len > ring_buffer_mask ||
|
218
258
|
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
@@ -237,12 +277,12 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|
237
277
|
}
|
238
278
|
}
|
239
279
|
}
|
240
|
-
FN(Store)(
|
280
|
+
FN(Store)(self, data, ring_buffer_mask, cur_ix);
|
241
281
|
}
|
242
282
|
if (out->score == min_score) {
|
243
|
-
SearchInStaticDictionary(dictionary,
|
244
|
-
|
245
|
-
BROTLI_FALSE);
|
283
|
+
SearchInStaticDictionary(dictionary,
|
284
|
+
self->common, &data[cur_ix_masked], max_length, dictionary_distance,
|
285
|
+
max_distance, out, BROTLI_FALSE);
|
246
286
|
}
|
247
287
|
}
|
248
288
|
|
@@ -20,7 +20,7 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; }
|
|
20
20
|
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
|
21
21
|
|
22
22
|
/* HashBytes is the function that chooses the bucket to place the address in. */
|
23
|
-
static BROTLI_INLINE uint32_t FN(HashBytes)(const uint8_t
|
23
|
+
static BROTLI_INLINE uint32_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data,
|
24
24
|
const uint64_t mask,
|
25
25
|
const int shift) {
|
26
26
|
const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(data) & mask) * kHashMul64Long;
|
@@ -42,43 +42,43 @@ typedef struct HashLongestMatch {
|
|
42
42
|
/* Mask for accessing entries in a block (in a ring-buffer manner). */
|
43
43
|
uint32_t block_mask_;
|
44
44
|
|
45
|
+
int block_bits_;
|
46
|
+
int num_last_distances_to_check_;
|
47
|
+
|
48
|
+
/* Shortcuts. */
|
49
|
+
HasherCommon* common_;
|
50
|
+
|
45
51
|
/* --- Dynamic size members --- */
|
46
52
|
|
47
53
|
/* Number of entries in a particular bucket. */
|
48
|
-
/* uint16_t
|
54
|
+
uint16_t* num_; /* uint16_t[bucket_size]; */
|
49
55
|
|
50
56
|
/* Buckets containing block_size_ of backward references. */
|
51
|
-
/* uint32_t
|
57
|
+
uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
|
52
58
|
} HashLongestMatch;
|
53
59
|
|
54
|
-
static BROTLI_INLINE HashLongestMatch* FN(Self)(HasherHandle handle) {
|
55
|
-
return (HashLongestMatch*)&(GetHasherCommon(handle)[1]);
|
56
|
-
}
|
57
|
-
|
58
|
-
static BROTLI_INLINE uint16_t* FN(Num)(HashLongestMatch* self) {
|
59
|
-
return (uint16_t*)(&self[1]);
|
60
|
-
}
|
61
|
-
|
62
|
-
static BROTLI_INLINE uint32_t* FN(Buckets)(HashLongestMatch* self) {
|
63
|
-
return (uint32_t*)(&FN(Num)(self)[self->bucket_size_]);
|
64
|
-
}
|
65
|
-
|
66
60
|
static void FN(Initialize)(
|
67
|
-
|
68
|
-
|
69
|
-
|
61
|
+
HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
|
62
|
+
const BrotliEncoderParams* params) {
|
63
|
+
self->common_ = common;
|
64
|
+
|
70
65
|
BROTLI_UNUSED(params);
|
71
66
|
self->hash_shift_ = 64 - common->params.bucket_bits;
|
72
67
|
self->hash_mask_ = (~((uint64_t)0U)) >> (64 - 8 * common->params.hash_len);
|
73
68
|
self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
|
69
|
+
self->block_bits_ = common->params.block_bits;
|
74
70
|
self->block_size_ = (size_t)1 << common->params.block_bits;
|
75
71
|
self->block_mask_ = (uint32_t)(self->block_size_ - 1);
|
72
|
+
self->num_last_distances_to_check_ =
|
73
|
+
common->params.num_last_distances_to_check;
|
74
|
+
self->num_ = (uint16_t*)common->extra;
|
75
|
+
self->buckets_ = (uint32_t*)&self->num_[self->bucket_size_];
|
76
76
|
}
|
77
77
|
|
78
|
-
static void FN(Prepare)(
|
79
|
-
|
80
|
-
|
81
|
-
uint16_t* num =
|
78
|
+
static void FN(Prepare)(
|
79
|
+
HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
80
|
+
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
81
|
+
uint16_t* BROTLI_RESTRICT num = self->num_;
|
82
82
|
/* Partial preparation is 100 times slower (per socket). */
|
83
83
|
size_t partial_prepare_threshold = self->bucket_size_ >> 6;
|
84
84
|
if (one_shot && input_size <= partial_prepare_threshold) {
|
@@ -100,50 +100,52 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
|
100
100
|
size_t block_size = (size_t)1 << params->hasher.block_bits;
|
101
101
|
BROTLI_UNUSED(one_shot);
|
102
102
|
BROTLI_UNUSED(input_size);
|
103
|
-
return sizeof(
|
103
|
+
return sizeof(uint16_t) * bucket_size +
|
104
|
+
sizeof(uint32_t) * bucket_size * block_size;
|
104
105
|
}
|
105
106
|
|
106
107
|
/* Look at 4 bytes at &data[ix & mask].
|
107
108
|
Compute a hash from these, and store the value of ix at that position. */
|
108
|
-
static BROTLI_INLINE void FN(Store)(
|
109
|
+
static BROTLI_INLINE void FN(Store)(
|
110
|
+
HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
|
109
111
|
const size_t mask, const size_t ix) {
|
110
|
-
|
111
|
-
|
112
|
+
uint16_t* BROTLI_RESTRICT num = self->num_;
|
113
|
+
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
112
114
|
const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_mask_,
|
113
115
|
self->hash_shift_);
|
114
116
|
const size_t minor_ix = num[key] & self->block_mask_;
|
115
|
-
const size_t offset =
|
116
|
-
minor_ix + (key << GetHasherCommon(handle)->params.block_bits);
|
117
|
-
FN(Buckets)(self)[offset] = (uint32_t)ix;
|
117
|
+
const size_t offset = minor_ix + (key << self->block_bits_);
|
118
118
|
++num[key];
|
119
|
+
buckets[offset] = (uint32_t)ix;
|
119
120
|
}
|
120
121
|
|
121
|
-
static BROTLI_INLINE void FN(StoreRange)(
|
122
|
-
const uint8_t
|
123
|
-
const size_t ix_end) {
|
122
|
+
static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
|
123
|
+
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
124
|
+
const size_t ix_start, const size_t ix_end) {
|
124
125
|
size_t i;
|
125
126
|
for (i = ix_start; i < ix_end; ++i) {
|
126
|
-
FN(Store)(
|
127
|
+
FN(Store)(self, data, mask, i);
|
127
128
|
}
|
128
129
|
}
|
129
130
|
|
130
|
-
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
131
|
+
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
132
|
+
HashLongestMatch* BROTLI_RESTRICT self,
|
131
133
|
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
132
134
|
size_t ringbuffer_mask) {
|
133
135
|
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
134
136
|
/* Prepare the hashes for three last bytes of the last write.
|
135
137
|
These could not be calculated before, since they require knowledge
|
136
138
|
of both the previous and the current block. */
|
137
|
-
FN(Store)(
|
138
|
-
FN(Store)(
|
139
|
-
FN(Store)(
|
139
|
+
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
|
140
|
+
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
|
141
|
+
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
|
140
142
|
}
|
141
143
|
}
|
142
144
|
|
143
145
|
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
144
|
-
|
145
|
-
|
146
|
-
|
146
|
+
HashLongestMatch* BROTLI_RESTRICT self,
|
147
|
+
int* BROTLI_RESTRICT distance_cache) {
|
148
|
+
PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
|
147
149
|
}
|
148
150
|
|
149
151
|
/* Find a longest backward match of &data[cur_ix] up to the length of
|
@@ -157,16 +159,16 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
|
157
159
|
Does not look for matches further away than max_backward.
|
158
160
|
Writes the best match into |out|.
|
159
161
|
|out|->score is updated only if a better match is found. */
|
160
|
-
static BROTLI_INLINE void FN(FindLongestMatch)(
|
161
|
-
|
162
|
+
static BROTLI_INLINE void FN(FindLongestMatch)(
|
163
|
+
HashLongestMatch* BROTLI_RESTRICT self,
|
164
|
+
const BrotliEncoderDictionary* dictionary,
|
162
165
|
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
163
166
|
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
|
164
|
-
const size_t max_length, const size_t max_backward,
|
167
|
+
const size_t max_length, const size_t max_backward,
|
168
|
+
const size_t dictionary_distance, const size_t max_distance,
|
165
169
|
HasherSearchResult* BROTLI_RESTRICT out) {
|
166
|
-
|
167
|
-
|
168
|
-
uint16_t* num = FN(Num)(self);
|
169
|
-
uint32_t* buckets = FN(Buckets)(self);
|
170
|
+
uint16_t* BROTLI_RESTRICT num = self->num_;
|
171
|
+
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
170
172
|
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
171
173
|
/* Don't accept a short copy from far away. */
|
172
174
|
score_t min_score = out->score;
|
@@ -176,7 +178,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|
176
178
|
out->len = 0;
|
177
179
|
out->len_code_delta = 0;
|
178
180
|
/* Try last distance first. */
|
179
|
-
for (i = 0; i < (size_t)
|
181
|
+
for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
|
180
182
|
const size_t backward = (size_t)distance_cache[i];
|
181
183
|
size_t prev_ix = (size_t)(cur_ix - backward);
|
182
184
|
if (prev_ix >= cur_ix) {
|
@@ -217,8 +219,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|
217
219
|
{
|
218
220
|
const uint32_t key = FN(HashBytes)(
|
219
221
|
&data[cur_ix_masked], self->hash_mask_, self->hash_shift_);
|
220
|
-
uint32_t* BROTLI_RESTRICT bucket =
|
221
|
-
&buckets[key << common->params.block_bits];
|
222
|
+
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
|
222
223
|
const size_t down =
|
223
224
|
(num[key] > self->block_size_) ?
|
224
225
|
(num[key] - self->block_size_) : 0u;
|
@@ -257,9 +258,9 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|
257
258
|
++num[key];
|
258
259
|
}
|
259
260
|
if (min_score == out->score) {
|
260
|
-
SearchInStaticDictionary(dictionary,
|
261
|
-
|
262
|
-
BROTLI_FALSE);
|
261
|
+
SearchInStaticDictionary(dictionary,
|
262
|
+
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
|
263
|
+
max_distance, out, BROTLI_FALSE);
|
263
264
|
}
|
264
265
|
}
|
265
266
|
|
@@ -20,8 +20,9 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
|
|
20
20
|
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
|
21
21
|
|
22
22
|
/* HashBytes is the function that chooses the bucket to place the address in. */
|
23
|
-
static uint32_t FN(HashBytes)(
|
24
|
-
|
23
|
+
static uint32_t FN(HashBytes)(
|
24
|
+
const uint8_t* BROTLI_RESTRICT data, const int shift) {
|
25
|
+
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
|
25
26
|
/* The higher bits contain more mixture from the multiplication,
|
26
27
|
so we take our results from there. */
|
27
28
|
return (uint32_t)(h >> shift);
|
@@ -38,42 +39,46 @@ typedef struct HashLongestMatch {
|
|
38
39
|
/* Mask for accessing entries in a block (in a ring-buffer manner). */
|
39
40
|
uint32_t block_mask_;
|
40
41
|
|
42
|
+
int block_bits_;
|
43
|
+
int num_last_distances_to_check_;
|
44
|
+
|
45
|
+
/* Shortcuts. */
|
46
|
+
HasherCommon* common_;
|
47
|
+
|
41
48
|
/* --- Dynamic size members --- */
|
42
49
|
|
43
50
|
/* Number of entries in a particular bucket. */
|
44
|
-
/* uint16_t
|
51
|
+
uint16_t* num_; /* uint16_t[bucket_size]; */
|
45
52
|
|
46
53
|
/* Buckets containing block_size_ of backward references. */
|
47
|
-
/* uint32_t
|
54
|
+
uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
|
48
55
|
} HashLongestMatch;
|
49
56
|
|
50
|
-
static BROTLI_INLINE
|
51
|
-
return (
|
52
|
-
}
|
53
|
-
|
54
|
-
static BROTLI_INLINE uint16_t* FN(Num)(HashLongestMatch* self) {
|
55
|
-
return (uint16_t*)(&self[1]);
|
56
|
-
}
|
57
|
-
|
58
|
-
static BROTLI_INLINE uint32_t* FN(Buckets)(HashLongestMatch* self) {
|
59
|
-
return (uint32_t*)(&FN(Num)(self)[self->bucket_size_]);
|
57
|
+
static BROTLI_INLINE uint16_t* FN(Num)(void* extra) {
|
58
|
+
return (uint16_t*)extra;
|
60
59
|
}
|
61
60
|
|
62
61
|
static void FN(Initialize)(
|
63
|
-
|
64
|
-
|
65
|
-
|
62
|
+
HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
|
63
|
+
const BrotliEncoderParams* params) {
|
64
|
+
self->common_ = common;
|
65
|
+
|
66
66
|
BROTLI_UNUSED(params);
|
67
67
|
self->hash_shift_ = 32 - common->params.bucket_bits;
|
68
68
|
self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
|
69
69
|
self->block_size_ = (size_t)1 << common->params.block_bits;
|
70
70
|
self->block_mask_ = (uint32_t)(self->block_size_ - 1);
|
71
|
+
self->num_ = (uint16_t*)common->extra;
|
72
|
+
self->buckets_ = (uint32_t*)(&self->num_[self->bucket_size_]);
|
73
|
+
self->block_bits_ = common->params.block_bits;
|
74
|
+
self->num_last_distances_to_check_ =
|
75
|
+
common->params.num_last_distances_to_check;
|
71
76
|
}
|
72
77
|
|
73
|
-
static void FN(Prepare)(
|
74
|
-
|
75
|
-
|
76
|
-
uint16_t* num =
|
78
|
+
static void FN(Prepare)(
|
79
|
+
HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
80
|
+
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
81
|
+
uint16_t* BROTLI_RESTRICT num = self->num_;
|
77
82
|
/* Partial preparation is 100 times slower (per socket). */
|
78
83
|
size_t partial_prepare_threshold = self->bucket_size_ >> 6;
|
79
84
|
if (one_shot && input_size <= partial_prepare_threshold) {
|
@@ -94,49 +99,49 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
|
94
99
|
size_t block_size = (size_t)1 << params->hasher.block_bits;
|
95
100
|
BROTLI_UNUSED(one_shot);
|
96
101
|
BROTLI_UNUSED(input_size);
|
97
|
-
return sizeof(
|
102
|
+
return sizeof(uint16_t) * bucket_size +
|
103
|
+
sizeof(uint32_t) * bucket_size * block_size;
|
98
104
|
}
|
99
105
|
|
100
106
|
/* Look at 4 bytes at &data[ix & mask].
|
101
107
|
Compute a hash from these, and store the value of ix at that position. */
|
102
|
-
static BROTLI_INLINE void FN(Store)(
|
108
|
+
static BROTLI_INLINE void FN(Store)(
|
109
|
+
HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
|
103
110
|
const size_t mask, const size_t ix) {
|
104
|
-
HashLongestMatch* self = FN(Self)(handle);
|
105
|
-
uint16_t* num = FN(Num)(self);
|
106
111
|
const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_shift_);
|
107
|
-
const size_t minor_ix =
|
108
|
-
const size_t offset =
|
109
|
-
|
110
|
-
|
111
|
-
++num[key];
|
112
|
+
const size_t minor_ix = self->num_[key] & self->block_mask_;
|
113
|
+
const size_t offset = minor_ix + (key << self->block_bits_);
|
114
|
+
self->buckets_[offset] = (uint32_t)ix;
|
115
|
+
++self->num_[key];
|
112
116
|
}
|
113
117
|
|
114
|
-
static BROTLI_INLINE void FN(StoreRange)(
|
115
|
-
const uint8_t
|
116
|
-
const size_t ix_end) {
|
118
|
+
static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
|
119
|
+
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
120
|
+
const size_t ix_start, const size_t ix_end) {
|
117
121
|
size_t i;
|
118
122
|
for (i = ix_start; i < ix_end; ++i) {
|
119
|
-
FN(Store)(
|
123
|
+
FN(Store)(self, data, mask, i);
|
120
124
|
}
|
121
125
|
}
|
122
126
|
|
123
|
-
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
127
|
+
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
128
|
+
HashLongestMatch* BROTLI_RESTRICT self,
|
124
129
|
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
125
130
|
size_t ringbuffer_mask) {
|
126
131
|
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
127
132
|
/* Prepare the hashes for three last bytes of the last write.
|
128
133
|
These could not be calculated before, since they require knowledge
|
129
134
|
of both the previous and the current block. */
|
130
|
-
FN(Store)(
|
131
|
-
FN(Store)(
|
132
|
-
FN(Store)(
|
135
|
+
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
|
136
|
+
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
|
137
|
+
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
|
133
138
|
}
|
134
139
|
}
|
135
140
|
|
136
141
|
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
137
|
-
|
138
|
-
|
139
|
-
|
142
|
+
HashLongestMatch* BROTLI_RESTRICT self,
|
143
|
+
int* BROTLI_RESTRICT distance_cache) {
|
144
|
+
PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
|
140
145
|
}
|
141
146
|
|
142
147
|
/* Find a longest backward match of &data[cur_ix] up to the length of
|
@@ -150,16 +155,16 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
|
150
155
|
Does not look for matches further away than max_backward.
|
151
156
|
Writes the best match into |out|.
|
152
157
|
|out|->score is updated only if a better match is found. */
|
153
|
-
static BROTLI_INLINE void FN(FindLongestMatch)(
|
154
|
-
|
158
|
+
static BROTLI_INLINE void FN(FindLongestMatch)(
|
159
|
+
HashLongestMatch* BROTLI_RESTRICT self,
|
160
|
+
const BrotliEncoderDictionary* dictionary,
|
155
161
|
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
156
162
|
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
|
157
|
-
const size_t max_length, const size_t max_backward,
|
163
|
+
const size_t max_length, const size_t max_backward,
|
164
|
+
const size_t dictionary_distance, const size_t max_distance,
|
158
165
|
HasherSearchResult* BROTLI_RESTRICT out) {
|
159
|
-
|
160
|
-
|
161
|
-
uint16_t* num = FN(Num)(self);
|
162
|
-
uint32_t* buckets = FN(Buckets)(self);
|
166
|
+
uint16_t* BROTLI_RESTRICT num = self->num_;
|
167
|
+
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
163
168
|
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
164
169
|
/* Don't accept a short copy from far away. */
|
165
170
|
score_t min_score = out->score;
|
@@ -169,7 +174,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|
169
174
|
out->len = 0;
|
170
175
|
out->len_code_delta = 0;
|
171
176
|
/* Try last distance first. */
|
172
|
-
for (i = 0; i < (size_t)
|
177
|
+
for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
|
173
178
|
const size_t backward = (size_t)distance_cache[i];
|
174
179
|
size_t prev_ix = (size_t)(cur_ix - backward);
|
175
180
|
if (prev_ix >= cur_ix) {
|
@@ -210,8 +215,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|
210
215
|
{
|
211
216
|
const uint32_t key =
|
212
217
|
FN(HashBytes)(&data[cur_ix_masked], self->hash_shift_);
|
213
|
-
uint32_t* BROTLI_RESTRICT bucket =
|
214
|
-
&buckets[key << common->params.block_bits];
|
218
|
+
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
|
215
219
|
const size_t down =
|
216
220
|
(num[key] > self->block_size_) ? (num[key] - self->block_size_) : 0u;
|
217
221
|
for (i = num[key]; i > down;) {
|
@@ -249,9 +253,9 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|
249
253
|
++num[key];
|
250
254
|
}
|
251
255
|
if (min_score == out->score) {
|
252
|
-
SearchInStaticDictionary(dictionary,
|
253
|
-
|
254
|
-
BROTLI_FALSE);
|
256
|
+
SearchInStaticDictionary(dictionary,
|
257
|
+
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
|
258
|
+
max_distance, out, BROTLI_FALSE);
|
255
259
|
}
|
256
260
|
}
|
257
261
|
|