brotli 0.2.3 → 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 +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
|