brotli 0.2.3 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +34 -0
- data/.github/workflows/publish.yml +34 -0
- data/Gemfile +6 -3
- data/Rakefile +16 -9
- data/brotli.gemspec +7 -13
- data/ext/brotli/brotli.c +209 -31
- data/ext/brotli/buffer.c +1 -7
- data/ext/brotli/buffer.h +1 -1
- data/ext/brotli/extconf.rb +20 -18
- data/lib/brotli/version.rb +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 +136 -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 +10 -1
- data/vendor/brotli/c/common/platform.c +22 -0
- data/vendor/brotli/c/common/platform.h +43 -17
- data/vendor/brotli/c/common/transform.c +59 -3
- data/vendor/brotli/c/common/transform.h +5 -0
- data/vendor/brotli/c/common/version.h +2 -2
- data/vendor/brotli/c/dec/bit_reader.c +28 -0
- data/vendor/brotli/c/dec/bit_reader.h +58 -16
- data/vendor/brotli/c/dec/decode.c +353 -251
- data/vendor/brotli/c/dec/huffman.h +6 -12
- data/vendor/brotli/c/dec/prefix.h +0 -18
- data/vendor/brotli/c/dec/state.c +9 -14
- data/vendor/brotli/c/dec/state.h +144 -37
- data/vendor/brotli/c/enc/backward_references.c +8 -7
- data/vendor/brotli/c/enc/backward_references.h +5 -4
- data/vendor/brotli/c/enc/backward_references_hq.c +51 -33
- data/vendor/brotli/c/enc/backward_references_hq.h +11 -8
- data/vendor/brotli/c/enc/backward_references_inc.h +24 -14
- data/vendor/brotli/c/enc/block_splitter.c +3 -3
- data/vendor/brotli/c/enc/block_splitter_inc.h +15 -6
- data/vendor/brotli/c/enc/brotli_bit_stream.c +13 -30
- 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 +12 -12
- data/vendor/brotli/c/enc/compress_fragment_two_pass.c +1 -1
- data/vendor/brotli/c/enc/dictionary_hash.c +1826 -1100
- data/vendor/brotli/c/enc/dictionary_hash.h +2 -1
- data/vendor/brotli/c/enc/encode.c +104 -39
- data/vendor/brotli/c/enc/encoder_dict.c +3 -2
- data/vendor/brotli/c/enc/encoder_dict.h +3 -1
- data/vendor/brotli/c/enc/entropy_encode.c +2 -0
- data/vendor/brotli/c/enc/entropy_encode.h +2 -2
- data/vendor/brotli/c/enc/fast_log.c +105 -0
- data/vendor/brotli/c/enc/fast_log.h +19 -100
- data/vendor/brotli/c/enc/find_match_length.h +2 -3
- data/vendor/brotli/c/enc/hash.h +80 -90
- data/vendor/brotli/c/enc/hash_composite_inc.h +52 -63
- data/vendor/brotli/c/enc/hash_forgetful_chain_inc.h +88 -49
- data/vendor/brotli/c/enc/hash_longest_match64_inc.h +50 -50
- data/vendor/brotli/c/enc/hash_longest_match_inc.h +53 -50
- data/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h +91 -60
- data/vendor/brotli/c/enc/hash_rolling_inc.h +23 -27
- data/vendor/brotli/c/enc/hash_to_binary_tree_inc.h +39 -38
- data/vendor/brotli/c/enc/memory.h +24 -12
- data/vendor/brotli/c/enc/metablock.c +23 -27
- data/vendor/brotli/c/enc/metablock_inc.h +1 -1
- data/vendor/brotli/c/enc/params.h +3 -1
- data/vendor/brotli/c/enc/ringbuffer.h +4 -1
- data/vendor/brotli/c/enc/utf8_util.c +1 -1
- data/vendor/brotli/c/enc/write_bits.h +27 -25
- data/vendor/brotli/c/include/brotli/encode.h +22 -1
- data/vendor/brotli/c/include/brotli/port.h +14 -0
- metadata +17 -97
- data/.travis.yml +0 -31
- data/docs/Brotli.html +0 -485
- data/docs/Brotli/Error.html +0 -124
- 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
@@ -20,7 +20,8 @@ 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)(
|
23
|
+
static uint32_t FN(HashBytes)(
|
24
|
+
const uint8_t* BROTLI_RESTRICT data, const int shift) {
|
24
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. */
|
@@ -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* data, const size_t mask,
|
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,17 +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)(
|
158
|
+
static BROTLI_INLINE void FN(FindLongestMatch)(
|
159
|
+
HashLongestMatch* BROTLI_RESTRICT self,
|
154
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
163
|
const size_t max_length, const size_t max_backward,
|
158
|
-
const size_t
|
164
|
+
const size_t dictionary_distance, const size_t max_distance,
|
159
165
|
HasherSearchResult* BROTLI_RESTRICT out) {
|
160
|
-
|
161
|
-
|
162
|
-
uint16_t* num = FN(Num)(self);
|
163
|
-
uint32_t* buckets = FN(Buckets)(self);
|
166
|
+
uint16_t* BROTLI_RESTRICT num = self->num_;
|
167
|
+
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
164
168
|
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
165
169
|
/* Don't accept a short copy from far away. */
|
166
170
|
score_t min_score = out->score;
|
@@ -170,7 +174,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|
170
174
|
out->len = 0;
|
171
175
|
out->len_code_delta = 0;
|
172
176
|
/* Try last distance first. */
|
173
|
-
for (i = 0; i < (size_t)
|
177
|
+
for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
|
174
178
|
const size_t backward = (size_t)distance_cache[i];
|
175
179
|
size_t prev_ix = (size_t)(cur_ix - backward);
|
176
180
|
if (prev_ix >= cur_ix) {
|
@@ -211,8 +215,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|
211
215
|
{
|
212
216
|
const uint32_t key =
|
213
217
|
FN(HashBytes)(&data[cur_ix_masked], self->hash_shift_);
|
214
|
-
uint32_t* BROTLI_RESTRICT bucket =
|
215
|
-
&buckets[key << common->params.block_bits];
|
218
|
+
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
|
216
219
|
const size_t down =
|
217
220
|
(num[key] > self->block_size_) ? (num[key] - self->block_size_) : 0u;
|
218
221
|
for (i = num[key]; i > down;) {
|
@@ -251,7 +254,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|
251
254
|
}
|
252
255
|
if (min_score == out->score) {
|
253
256
|
SearchInStaticDictionary(dictionary,
|
254
|
-
|
257
|
+
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
|
255
258
|
max_distance, out, BROTLI_FALSE);
|
256
259
|
}
|
257
260
|
}
|
@@ -5,15 +5,16 @@
|
|
5
5
|
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
6
6
|
*/
|
7
7
|
|
8
|
-
/* template parameters: FN, BUCKET_BITS,
|
8
|
+
/* template parameters: FN, BUCKET_BITS, BUCKET_SWEEP_BITS, HASH_LEN,
|
9
9
|
USE_DICTIONARY
|
10
10
|
*/
|
11
11
|
|
12
12
|
#define HashLongestMatchQuickly HASHER()
|
13
13
|
|
14
14
|
#define BUCKET_SIZE (1 << BUCKET_BITS)
|
15
|
-
|
16
|
-
#define
|
15
|
+
#define BUCKET_MASK (BUCKET_SIZE - 1)
|
16
|
+
#define BUCKET_SWEEP (1 << BUCKET_SWEEP_BITS)
|
17
|
+
#define BUCKET_SWEEP_MASK ((BUCKET_SWEEP - 1) << 3)
|
17
18
|
|
18
19
|
static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; }
|
19
20
|
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
|
@@ -32,39 +33,50 @@ static uint32_t FN(HashBytes)(const uint8_t* data) {
|
|
32
33
|
/* A (forgetful) hash table to the data seen by the compressor, to
|
33
34
|
help create backward references to previous data.
|
34
35
|
|
35
|
-
This is a hash map of fixed size (BUCKET_SIZE).
|
36
|
-
given index, BUCKET_SWEEP buckets are used to store values of a key. */
|
36
|
+
This is a hash map of fixed size (BUCKET_SIZE). */
|
37
37
|
typedef struct HashLongestMatchQuickly {
|
38
|
-
|
39
|
-
|
38
|
+
/* Shortcuts. */
|
39
|
+
HasherCommon* common;
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
/* --- Dynamic size members --- */
|
42
|
+
|
43
|
+
uint32_t* buckets_; /* uint32_t[BUCKET_SIZE]; */
|
44
|
+
} HashLongestMatchQuickly;
|
44
45
|
|
45
46
|
static void FN(Initialize)(
|
46
|
-
|
47
|
-
|
47
|
+
HasherCommon* common, HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
48
|
+
const BrotliEncoderParams* params) {
|
49
|
+
self->common = common;
|
50
|
+
|
48
51
|
BROTLI_UNUSED(params);
|
52
|
+
self->buckets_ = (uint32_t*)common->extra;
|
49
53
|
}
|
50
54
|
|
51
|
-
static void FN(Prepare)(
|
52
|
-
|
53
|
-
|
55
|
+
static void FN(Prepare)(
|
56
|
+
HashLongestMatchQuickly* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
57
|
+
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
58
|
+
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
54
59
|
/* Partial preparation is 100 times slower (per socket). */
|
55
|
-
size_t partial_prepare_threshold =
|
60
|
+
size_t partial_prepare_threshold = BUCKET_SIZE >> 5;
|
56
61
|
if (one_shot && input_size <= partial_prepare_threshold) {
|
57
62
|
size_t i;
|
58
63
|
for (i = 0; i < input_size; ++i) {
|
59
64
|
const uint32_t key = FN(HashBytes)(&data[i]);
|
60
|
-
|
65
|
+
if (BUCKET_SWEEP == 1) {
|
66
|
+
buckets[key] = 0;
|
67
|
+
} else {
|
68
|
+
uint32_t j;
|
69
|
+
for (j = 0; j < BUCKET_SWEEP; ++j) {
|
70
|
+
buckets[(key + (j << 3)) & BUCKET_MASK] = 0;
|
71
|
+
}
|
72
|
+
}
|
61
73
|
}
|
62
74
|
} else {
|
63
75
|
/* It is not strictly necessary to fill this buffer here, but
|
64
76
|
not filling will make the results of the compression stochastic
|
65
77
|
(but correct). This is because random data would cause the
|
66
78
|
system to find accidentally good backward references here and there. */
|
67
|
-
memset(
|
79
|
+
memset(buckets, 0, sizeof(uint32_t) * BUCKET_SIZE);
|
68
80
|
}
|
69
81
|
}
|
70
82
|
|
@@ -74,45 +86,53 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
|
74
86
|
BROTLI_UNUSED(params);
|
75
87
|
BROTLI_UNUSED(one_shot);
|
76
88
|
BROTLI_UNUSED(input_size);
|
77
|
-
return sizeof(
|
89
|
+
return sizeof(uint32_t) * BUCKET_SIZE;
|
78
90
|
}
|
79
91
|
|
80
92
|
/* Look at 5 bytes at &data[ix & mask].
|
81
93
|
Compute a hash from these, and store the value somewhere within
|
82
94
|
[ix .. ix+3]. */
|
83
|
-
static BROTLI_INLINE void FN(Store)(
|
84
|
-
|
95
|
+
static BROTLI_INLINE void FN(Store)(
|
96
|
+
HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
97
|
+
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
|
85
98
|
const uint32_t key = FN(HashBytes)(&data[ix & mask]);
|
86
|
-
|
87
|
-
|
88
|
-
|
99
|
+
if (BUCKET_SWEEP == 1) {
|
100
|
+
self->buckets_[key] = (uint32_t)ix;
|
101
|
+
} else {
|
102
|
+
/* Wiggle the value with the bucket sweep range. */
|
103
|
+
const uint32_t off = ix & BUCKET_SWEEP_MASK;
|
104
|
+
self->buckets_[(key + off) & BUCKET_MASK] = (uint32_t)ix;
|
105
|
+
}
|
89
106
|
}
|
90
107
|
|
91
|
-
static BROTLI_INLINE void FN(StoreRange)(
|
92
|
-
|
93
|
-
const size_t
|
108
|
+
static BROTLI_INLINE void FN(StoreRange)(
|
109
|
+
HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
110
|
+
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
111
|
+
const size_t ix_start, const size_t ix_end) {
|
94
112
|
size_t i;
|
95
113
|
for (i = ix_start; i < ix_end; ++i) {
|
96
|
-
FN(Store)(
|
114
|
+
FN(Store)(self, data, mask, i);
|
97
115
|
}
|
98
116
|
}
|
99
117
|
|
100
118
|
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
101
|
-
|
119
|
+
HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
120
|
+
size_t num_bytes, size_t position,
|
102
121
|
const uint8_t* ringbuffer, size_t ringbuffer_mask) {
|
103
122
|
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
104
123
|
/* Prepare the hashes for three last bytes of the last write.
|
105
124
|
These could not be calculated before, since they require knowledge
|
106
125
|
of both the previous and the current block. */
|
107
|
-
FN(Store)(
|
108
|
-
FN(Store)(
|
109
|
-
FN(Store)(
|
126
|
+
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
|
127
|
+
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
|
128
|
+
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
|
110
129
|
}
|
111
130
|
}
|
112
131
|
|
113
132
|
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
114
|
-
|
115
|
-
|
133
|
+
HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
134
|
+
int* BROTLI_RESTRICT distance_cache) {
|
135
|
+
BROTLI_UNUSED(self);
|
116
136
|
BROTLI_UNUSED(distance_cache);
|
117
137
|
}
|
118
138
|
|
@@ -125,17 +145,19 @@ static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
|
125
145
|
Writes the best match into |out|.
|
126
146
|
|out|->score is updated only if a better match is found. */
|
127
147
|
static BROTLI_INLINE void FN(FindLongestMatch)(
|
128
|
-
|
148
|
+
HashLongestMatchQuickly* BROTLI_RESTRICT self,
|
149
|
+
const BrotliEncoderDictionary* dictionary,
|
129
150
|
const uint8_t* BROTLI_RESTRICT data,
|
130
151
|
const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache,
|
131
152
|
const size_t cur_ix, const size_t max_length, const size_t max_backward,
|
132
|
-
const size_t
|
153
|
+
const size_t dictionary_distance, const size_t max_distance,
|
133
154
|
HasherSearchResult* BROTLI_RESTRICT out) {
|
134
|
-
|
155
|
+
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
135
156
|
const size_t best_len_in = out->len;
|
136
157
|
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
137
|
-
const uint32_t key = FN(HashBytes)(&data[cur_ix_masked]);
|
138
158
|
int compare_char = data[cur_ix_masked + best_len_in];
|
159
|
+
size_t key = FN(HashBytes)(&data[cur_ix_masked]);
|
160
|
+
size_t key_out;
|
139
161
|
score_t min_score = out->score;
|
140
162
|
score_t best_score = out->score;
|
141
163
|
size_t best_len = best_len_in;
|
@@ -145,21 +167,21 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
|
145
167
|
if (prev_ix < cur_ix) {
|
146
168
|
prev_ix &= (uint32_t)ring_buffer_mask;
|
147
169
|
if (compare_char == data[prev_ix + best_len]) {
|
148
|
-
size_t len = FindMatchLengthWithLimit(
|
149
|
-
|
150
|
-
max_length);
|
170
|
+
const size_t len = FindMatchLengthWithLimit(
|
171
|
+
&data[prev_ix], &data[cur_ix_masked], max_length);
|
151
172
|
if (len >= 4) {
|
152
173
|
const score_t score = BackwardReferenceScoreUsingLastDistance(len);
|
153
174
|
if (best_score < score) {
|
154
|
-
best_score = score;
|
155
|
-
best_len = len;
|
156
175
|
out->len = len;
|
157
176
|
out->distance = cached_backward;
|
158
|
-
out->score =
|
159
|
-
compare_char = data[cur_ix_masked + best_len];
|
177
|
+
out->score = score;
|
160
178
|
if (BUCKET_SWEEP == 1) {
|
161
|
-
|
179
|
+
buckets[key] = (uint32_t)cur_ix;
|
162
180
|
return;
|
181
|
+
} else {
|
182
|
+
best_len = len;
|
183
|
+
best_score = score;
|
184
|
+
compare_char = data[cur_ix_masked + len];
|
163
185
|
}
|
164
186
|
}
|
165
187
|
}
|
@@ -169,8 +191,8 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
|
169
191
|
size_t backward;
|
170
192
|
size_t len;
|
171
193
|
/* Only one to look for, don't bother to prepare for a loop. */
|
172
|
-
prev_ix =
|
173
|
-
|
194
|
+
prev_ix = buckets[key];
|
195
|
+
buckets[key] = (uint32_t)cur_ix;
|
174
196
|
backward = cur_ix - prev_ix;
|
175
197
|
prev_ix &= (uint32_t)ring_buffer_mask;
|
176
198
|
if (compare_char != data[prev_ix + best_len_in]) {
|
@@ -192,12 +214,17 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
|
192
214
|
}
|
193
215
|
}
|
194
216
|
} else {
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
217
|
+
size_t keys[BUCKET_SWEEP];
|
218
|
+
size_t i;
|
219
|
+
for (i = 0; i < BUCKET_SWEEP; ++i) {
|
220
|
+
keys[i] = (key + (i << 3)) & BUCKET_MASK;
|
221
|
+
}
|
222
|
+
key_out = keys[(cur_ix & BUCKET_SWEEP_MASK) >> 3];
|
223
|
+
for (i = 0; i < BUCKET_SWEEP; ++i) {
|
200
224
|
size_t len;
|
225
|
+
size_t backward;
|
226
|
+
prev_ix = buckets[keys[i]];
|
227
|
+
backward = cur_ix - prev_ix;
|
201
228
|
prev_ix &= (uint32_t)ring_buffer_mask;
|
202
229
|
if (compare_char != data[prev_ix + best_len]) {
|
203
230
|
continue;
|
@@ -211,25 +238,29 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
|
211
238
|
if (len >= 4) {
|
212
239
|
const score_t score = BackwardReferenceScore(len, backward);
|
213
240
|
if (best_score < score) {
|
214
|
-
best_score = score;
|
215
241
|
best_len = len;
|
216
|
-
out->len =
|
217
|
-
|
242
|
+
out->len = len;
|
243
|
+
compare_char = data[cur_ix_masked + len];
|
244
|
+
best_score = score;
|
218
245
|
out->score = score;
|
219
|
-
|
246
|
+
out->distance = backward;
|
220
247
|
}
|
221
248
|
}
|
222
249
|
}
|
223
250
|
}
|
224
251
|
if (USE_DICTIONARY && min_score == out->score) {
|
225
252
|
SearchInStaticDictionary(dictionary,
|
226
|
-
|
253
|
+
self->common, &data[cur_ix_masked], max_length, dictionary_distance,
|
227
254
|
max_distance, out, BROTLI_TRUE);
|
228
255
|
}
|
229
|
-
|
256
|
+
if (BUCKET_SWEEP != 1) {
|
257
|
+
buckets[key_out] = (uint32_t)cur_ix;
|
258
|
+
}
|
230
259
|
}
|
231
260
|
|
232
|
-
#undef
|
261
|
+
#undef BUCKET_SWEEP_MASK
|
262
|
+
#undef BUCKET_SWEEP
|
263
|
+
#undef BUCKET_MASK
|
233
264
|
#undef BUCKET_SIZE
|
234
265
|
|
235
266
|
#undef HashLongestMatchQuickly
|