brotli 0.4.0 → 0.5.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 +6 -3
- data/.github/workflows/publish.yml +7 -17
- data/.gitmodules +1 -1
- data/README.md +2 -2
- data/ext/brotli/brotli.c +1 -0
- data/ext/brotli/extconf.rb +6 -0
- data/lib/brotli/version.rb +1 -1
- data/test/brotli_test.rb +4 -1
- 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
@@ -6,22 +6,24 @@
|
|
6
6
|
|
7
7
|
/* Function to find backward reference copies. */
|
8
8
|
|
9
|
-
#include "
|
9
|
+
#include "backward_references_hq.h"
|
10
10
|
|
11
11
|
#include <string.h> /* memcpy, memset */
|
12
12
|
|
13
|
+
#include <brotli/types.h>
|
14
|
+
|
13
15
|
#include "../common/constants.h"
|
14
|
-
#include "../common/context.h"
|
15
16
|
#include "../common/platform.h"
|
16
|
-
#include
|
17
|
-
#include "
|
18
|
-
#include "
|
19
|
-
#include "
|
20
|
-
#include "
|
21
|
-
#include "
|
22
|
-
#include "
|
23
|
-
#include "
|
24
|
-
#include "
|
17
|
+
#include "command.h"
|
18
|
+
#include "compound_dictionary.h"
|
19
|
+
#include "encoder_dict.h"
|
20
|
+
#include "fast_log.h"
|
21
|
+
#include "find_match_length.h"
|
22
|
+
#include "literal_cost.h"
|
23
|
+
#include "memory.h"
|
24
|
+
#include "params.h"
|
25
|
+
#include "prefix.h"
|
26
|
+
#include "quality.h"
|
25
27
|
|
26
28
|
#if defined(__cplusplus) || defined(c_plusplus)
|
27
29
|
extern "C" {
|
@@ -73,6 +75,14 @@ static BROTLI_INLINE uint32_t ZopfliNodeCommandLength(const ZopfliNode* self) {
|
|
73
75
|
return ZopfliNodeCopyLength(self) + (self->dcode_insert_length & 0x7FFFFFF);
|
74
76
|
}
|
75
77
|
|
78
|
+
/* Temporary data for ZopfliCostModelSetFromCommands. */
|
79
|
+
typedef struct ZopfliCostModelArena {
|
80
|
+
uint32_t histogram_literal[BROTLI_NUM_LITERAL_SYMBOLS];
|
81
|
+
uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS];
|
82
|
+
uint32_t histogram_dist[BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE];
|
83
|
+
float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS];
|
84
|
+
} ZopfliCostModelArena;
|
85
|
+
|
76
86
|
/* Histogram based cost model for zopflification. */
|
77
87
|
typedef struct ZopfliCostModel {
|
78
88
|
/* The insert and copy length symbols. */
|
@@ -83,6 +93,12 @@ typedef struct ZopfliCostModel {
|
|
83
93
|
float* literal_costs_;
|
84
94
|
float min_cost_cmd_;
|
85
95
|
size_t num_bytes_;
|
96
|
+
|
97
|
+
/* Temporary data. */
|
98
|
+
union {
|
99
|
+
size_t literal_histograms[3 * 256];
|
100
|
+
ZopfliCostModelArena arena;
|
101
|
+
};
|
86
102
|
} ZopfliCostModel;
|
87
103
|
|
88
104
|
static void InitZopfliCostModel(
|
@@ -139,18 +155,15 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
|
|
139
155
|
const Command* commands,
|
140
156
|
size_t num_commands,
|
141
157
|
size_t last_insert_len) {
|
142
|
-
|
143
|
-
uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS];
|
144
|
-
uint32_t histogram_dist[BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE];
|
145
|
-
float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS];
|
158
|
+
ZopfliCostModelArena* arena = &self->arena;
|
146
159
|
size_t pos = position - last_insert_len;
|
147
160
|
float min_cost_cmd = kInfinity;
|
148
161
|
size_t i;
|
149
162
|
float* cost_cmd = self->cost_cmd_;
|
150
163
|
|
151
|
-
memset(histogram_literal, 0, sizeof(histogram_literal));
|
152
|
-
memset(histogram_cmd, 0, sizeof(histogram_cmd));
|
153
|
-
memset(histogram_dist, 0, sizeof(histogram_dist));
|
164
|
+
memset(arena->histogram_literal, 0, sizeof(arena->histogram_literal));
|
165
|
+
memset(arena->histogram_cmd, 0, sizeof(arena->histogram_cmd));
|
166
|
+
memset(arena->histogram_dist, 0, sizeof(arena->histogram_dist));
|
154
167
|
|
155
168
|
for (i = 0; i < num_commands; i++) {
|
156
169
|
size_t inslength = commands[i].insert_len_;
|
@@ -159,21 +172,21 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
|
|
159
172
|
size_t cmdcode = commands[i].cmd_prefix_;
|
160
173
|
size_t j;
|
161
174
|
|
162
|
-
histogram_cmd[cmdcode]++;
|
163
|
-
if (cmdcode >= 128) histogram_dist[distcode]++;
|
175
|
+
arena->histogram_cmd[cmdcode]++;
|
176
|
+
if (cmdcode >= 128) arena->histogram_dist[distcode]++;
|
164
177
|
|
165
178
|
for (j = 0; j < inslength; j++) {
|
166
|
-
histogram_literal[ringbuffer[(pos + j) & ringbuffer_mask]]++;
|
179
|
+
arena->histogram_literal[ringbuffer[(pos + j) & ringbuffer_mask]]++;
|
167
180
|
}
|
168
181
|
|
169
182
|
pos += inslength + copylength;
|
170
183
|
}
|
171
184
|
|
172
|
-
SetCost(histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, BROTLI_TRUE,
|
173
|
-
cost_literal);
|
174
|
-
SetCost(histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, BROTLI_FALSE,
|
185
|
+
SetCost(arena->histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, BROTLI_TRUE,
|
186
|
+
arena->cost_literal);
|
187
|
+
SetCost(arena->histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, BROTLI_FALSE,
|
175
188
|
cost_cmd);
|
176
|
-
SetCost(histogram_dist, self->distance_histogram_size, BROTLI_FALSE,
|
189
|
+
SetCost(arena->histogram_dist, self->distance_histogram_size, BROTLI_FALSE,
|
177
190
|
self->cost_dist_);
|
178
191
|
|
179
192
|
for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
|
@@ -188,7 +201,7 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
|
|
188
201
|
literal_costs[0] = 0.0;
|
189
202
|
for (i = 0; i < num_bytes; ++i) {
|
190
203
|
literal_carry +=
|
191
|
-
cost_literal[ringbuffer[(position + i) & ringbuffer_mask]];
|
204
|
+
arena->cost_literal[ringbuffer[(position + i) & ringbuffer_mask]];
|
192
205
|
literal_costs[i + 1] = literal_costs[i] + literal_carry;
|
193
206
|
literal_carry -= literal_costs[i + 1] - literal_costs[i];
|
194
207
|
}
|
@@ -206,7 +219,8 @@ static void ZopfliCostModelSetFromLiteralCosts(ZopfliCostModel* self,
|
|
206
219
|
size_t num_bytes = self->num_bytes_;
|
207
220
|
size_t i;
|
208
221
|
BrotliEstimateBitCostsForLiterals(position, num_bytes, ringbuffer_mask,
|
209
|
-
ringbuffer,
|
222
|
+
ringbuffer, self->literal_histograms,
|
223
|
+
&literal_costs[1]);
|
210
224
|
literal_costs[0] = 0.0;
|
211
225
|
for (i = 0; i < num_bytes; ++i) {
|
212
226
|
literal_carry += literal_costs[i + 1];
|
@@ -418,7 +432,8 @@ static size_t UpdateNodes(
|
|
418
432
|
size_t min_len;
|
419
433
|
size_t result = 0;
|
420
434
|
size_t k;
|
421
|
-
|
435
|
+
const CompoundDictionary* addon = ¶ms->dictionary.compound;
|
436
|
+
size_t gap = addon->total_size;
|
422
437
|
|
423
438
|
EvaluateNode(block_start + stream_offset, pos, max_backward_limit, gap,
|
424
439
|
starting_dist_cache, model, queue, nodes);
|
@@ -472,6 +487,24 @@ static size_t UpdateNodes(
|
|
472
487
|
len = FindMatchLengthWithLimit(&ringbuffer[prev_ix],
|
473
488
|
&ringbuffer[cur_ix_masked],
|
474
489
|
max_len);
|
490
|
+
} else if (backward > dictionary_start) {
|
491
|
+
size_t d = 0;
|
492
|
+
size_t offset;
|
493
|
+
size_t limit;
|
494
|
+
const uint8_t* source;
|
495
|
+
offset = dictionary_start + 1 + addon->total_size - 1;
|
496
|
+
while (offset >= backward + addon->chunk_offsets[d + 1]) d++;
|
497
|
+
source = addon->chunk_source[d];
|
498
|
+
offset = offset - addon->chunk_offsets[d] - backward;
|
499
|
+
limit = addon->chunk_offsets[d + 1] - addon->chunk_offsets[d] - offset;
|
500
|
+
limit = limit > max_len ? max_len : limit;
|
501
|
+
if (best_len >= limit ||
|
502
|
+
continuation != source[offset + best_len]) {
|
503
|
+
continue;
|
504
|
+
}
|
505
|
+
len = FindMatchLengthWithLimit(&source[offset],
|
506
|
+
&ringbuffer[cur_ix_masked],
|
507
|
+
limit);
|
475
508
|
} else {
|
476
509
|
/* "Gray" area. It is addressable by decoder, but this encoder
|
477
510
|
instance does not have that data -> should not touch it. */
|
@@ -577,7 +610,7 @@ void BrotliZopfliCreateCommands(const size_t num_bytes,
|
|
577
610
|
size_t pos = 0;
|
578
611
|
uint32_t offset = nodes[0].u.next;
|
579
612
|
size_t i;
|
580
|
-
size_t gap =
|
613
|
+
size_t gap = params->dictionary.compound.total_size;
|
581
614
|
for (i = 0; offset != BROTLI_UINT32_MAX; i++) {
|
582
615
|
const ZopfliNode* next = &nodes[pos + offset];
|
583
616
|
size_t copy_length = ZopfliNodeCopyLength(next);
|
@@ -653,6 +686,23 @@ static size_t ZopfliIterate(size_t num_bytes, size_t position,
|
|
653
686
|
return ComputeShortestPathFromNodes(num_bytes, nodes);
|
654
687
|
}
|
655
688
|
|
689
|
+
static void MergeMatches(BackwardMatch* dst,
|
690
|
+
BackwardMatch* src1, size_t len1, BackwardMatch* src2, size_t len2) {
|
691
|
+
while (len1 > 0 && len2 > 0) {
|
692
|
+
size_t l1 = BackwardMatchLength(src1);
|
693
|
+
size_t l2 = BackwardMatchLength(src2);
|
694
|
+
if (l1 < l2 || ((l1 == l2) && (src1->distance < src2->distance))) {
|
695
|
+
*dst++ = *src1++;
|
696
|
+
len1--;
|
697
|
+
} else {
|
698
|
+
*dst++ = *src2++;
|
699
|
+
len2--;
|
700
|
+
}
|
701
|
+
}
|
702
|
+
while (len1-- > 0) *dst++ = *src1++;
|
703
|
+
while (len2-- > 0) *dst++ = *src2++;
|
704
|
+
}
|
705
|
+
|
656
706
|
/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
|
657
707
|
size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
658
708
|
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
@@ -661,21 +711,26 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
|
661
711
|
const size_t stream_offset = params->stream_offset;
|
662
712
|
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
663
713
|
const size_t max_zopfli_len = MaxZopfliLen(params);
|
664
|
-
ZopfliCostModel model;
|
665
714
|
StartPosQueue queue;
|
666
|
-
BackwardMatch
|
715
|
+
BackwardMatch* BROTLI_RESTRICT matches =
|
716
|
+
BROTLI_ALLOC(m, BackwardMatch, 2 * (MAX_NUM_MATCHES_H10 + 64));
|
667
717
|
const size_t store_end = num_bytes >= StoreLookaheadH10() ?
|
668
718
|
position + num_bytes - StoreLookaheadH10() + 1 : position;
|
669
719
|
size_t i;
|
670
|
-
|
671
|
-
size_t
|
672
|
-
|
720
|
+
const CompoundDictionary* addon = ¶ms->dictionary.compound;
|
721
|
+
size_t gap = addon->total_size;
|
722
|
+
size_t lz_matches_offset =
|
723
|
+
(addon->num_chunks != 0) ? (MAX_NUM_MATCHES_H10 + 128) : 0;
|
724
|
+
ZopfliCostModel* model = BROTLI_ALLOC(m, ZopfliCostModel, 1);
|
725
|
+
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(model) || BROTLI_IS_NULL(matches)) {
|
726
|
+
return 0;
|
727
|
+
}
|
673
728
|
nodes[0].length = 0;
|
674
729
|
nodes[0].u.cost = 0;
|
675
|
-
InitZopfliCostModel(m,
|
730
|
+
InitZopfliCostModel(m, model, ¶ms->dist, num_bytes);
|
676
731
|
if (BROTLI_IS_OOM(m)) return 0;
|
677
732
|
ZopfliCostModelSetFromLiteralCosts(
|
678
|
-
|
733
|
+
model, position, ringbuffer, ringbuffer_mask);
|
679
734
|
InitStartPosQueue(&queue);
|
680
735
|
for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) {
|
681
736
|
const size_t pos = position + i;
|
@@ -684,17 +739,35 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
|
684
739
|
pos + stream_offset, max_backward_limit);
|
685
740
|
size_t skip;
|
686
741
|
size_t num_matches;
|
742
|
+
int dict_id = 0;
|
743
|
+
if (params->dictionary.contextual.context_based) {
|
744
|
+
uint8_t p1 = pos >= 1 ?
|
745
|
+
ringbuffer[(size_t)(pos - 1) & ringbuffer_mask] : 0;
|
746
|
+
uint8_t p2 = pos >= 2 ?
|
747
|
+
ringbuffer[(size_t)(pos - 2) & ringbuffer_mask] : 0;
|
748
|
+
dict_id = params->dictionary.contextual.context_map[
|
749
|
+
BROTLI_CONTEXT(p1, p2, literal_context_lut)];
|
750
|
+
}
|
687
751
|
num_matches = FindAllMatchesH10(&hasher->privat._H10,
|
688
|
-
|
752
|
+
params->dictionary.contextual.dict[dict_id],
|
689
753
|
ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance,
|
690
754
|
dictionary_start + gap, params, &matches[lz_matches_offset]);
|
755
|
+
if (addon->num_chunks != 0) {
|
756
|
+
size_t cd_matches = LookupAllCompoundDictionaryMatches(addon,
|
757
|
+
ringbuffer, ringbuffer_mask, pos, 3, num_bytes - i,
|
758
|
+
dictionary_start, params->dist.max_distance,
|
759
|
+
&matches[lz_matches_offset - 64], 64);
|
760
|
+
MergeMatches(matches, &matches[lz_matches_offset - 64], cd_matches,
|
761
|
+
&matches[lz_matches_offset], num_matches);
|
762
|
+
num_matches += cd_matches;
|
763
|
+
}
|
691
764
|
if (num_matches > 0 &&
|
692
765
|
BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) {
|
693
766
|
matches[0] = matches[num_matches - 1];
|
694
767
|
num_matches = 1;
|
695
768
|
}
|
696
769
|
skip = UpdateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask,
|
697
|
-
params, max_backward_limit, dist_cache, num_matches, matches,
|
770
|
+
params, max_backward_limit, dist_cache, num_matches, matches, model,
|
698
771
|
&queue, nodes);
|
699
772
|
if (skip < BROTLI_LONG_COPY_QUICK_STEP) skip = 0;
|
700
773
|
if (num_matches == 1 && BackwardMatchLength(&matches[0]) > max_zopfli_len) {
|
@@ -710,12 +783,14 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
|
710
783
|
i++;
|
711
784
|
if (i + HashTypeLengthH10() - 1 >= num_bytes) break;
|
712
785
|
EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
|
713
|
-
dist_cache,
|
786
|
+
dist_cache, model, &queue, nodes);
|
714
787
|
skip--;
|
715
788
|
}
|
716
789
|
}
|
717
790
|
}
|
718
|
-
CleanupZopfliCostModel(m,
|
791
|
+
CleanupZopfliCostModel(m, model);
|
792
|
+
BROTLI_FREE(m, model);
|
793
|
+
BROTLI_FREE(m, matches);
|
719
794
|
return ComputeShortestPathFromNodes(num_bytes, nodes);
|
720
795
|
}
|
721
796
|
|
@@ -753,14 +828,15 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
|
753
828
|
size_t orig_last_insert_len;
|
754
829
|
int orig_dist_cache[4];
|
755
830
|
size_t orig_num_commands;
|
756
|
-
ZopfliCostModel model;
|
831
|
+
ZopfliCostModel* model = BROTLI_ALLOC(m, ZopfliCostModel, 1);
|
757
832
|
ZopfliNode* nodes;
|
758
833
|
BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size);
|
759
|
-
|
760
|
-
size_t
|
761
|
-
|
762
|
-
|
763
|
-
|
834
|
+
const CompoundDictionary* addon = ¶ms->dictionary.compound;
|
835
|
+
size_t gap = addon->total_size;
|
836
|
+
size_t shadow_matches =
|
837
|
+
(addon->num_chunks != 0) ? (MAX_NUM_MATCHES_H10 + 128) : 0;
|
838
|
+
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(model) ||
|
839
|
+
BROTLI_IS_NULL(num_matches) || BROTLI_IS_NULL(matches)) {
|
764
840
|
return;
|
765
841
|
}
|
766
842
|
for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; ++i) {
|
@@ -772,15 +848,34 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
|
772
848
|
size_t num_found_matches;
|
773
849
|
size_t cur_match_end;
|
774
850
|
size_t j;
|
851
|
+
int dict_id = 0;
|
852
|
+
if (params->dictionary.contextual.context_based) {
|
853
|
+
uint8_t p1 = pos >= 1 ?
|
854
|
+
ringbuffer[(size_t)(pos - 1) & ringbuffer_mask] : 0;
|
855
|
+
uint8_t p2 = pos >= 2 ?
|
856
|
+
ringbuffer[(size_t)(pos - 2) & ringbuffer_mask] : 0;
|
857
|
+
dict_id = params->dictionary.contextual.context_map[
|
858
|
+
BROTLI_CONTEXT(p1, p2, literal_context_lut)];
|
859
|
+
}
|
775
860
|
/* Ensure that we have enough free slots. */
|
776
861
|
BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size,
|
777
862
|
cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches);
|
778
863
|
if (BROTLI_IS_OOM(m)) return;
|
779
864
|
num_found_matches = FindAllMatchesH10(&hasher->privat._H10,
|
780
|
-
|
865
|
+
params->dictionary.contextual.dict[dict_id],
|
781
866
|
ringbuffer, ringbuffer_mask, pos, max_length,
|
782
867
|
max_distance, dictionary_start + gap, params,
|
783
868
|
&matches[cur_match_pos + shadow_matches]);
|
869
|
+
if (addon->num_chunks != 0) {
|
870
|
+
size_t cd_matches = LookupAllCompoundDictionaryMatches(addon,
|
871
|
+
ringbuffer, ringbuffer_mask, pos, 3, max_length,
|
872
|
+
dictionary_start, params->dist.max_distance,
|
873
|
+
&matches[cur_match_pos + shadow_matches - 64], 64);
|
874
|
+
MergeMatches(&matches[cur_match_pos],
|
875
|
+
&matches[cur_match_pos + shadow_matches - 64], cd_matches,
|
876
|
+
&matches[cur_match_pos + shadow_matches], num_found_matches);
|
877
|
+
num_found_matches += cd_matches;
|
878
|
+
}
|
784
879
|
cur_match_end = cur_match_pos + num_found_matches;
|
785
880
|
for (j = cur_match_pos; j + 1 < cur_match_end; ++j) {
|
786
881
|
BROTLI_DCHECK(BackwardMatchLength(&matches[j]) <=
|
@@ -810,15 +905,15 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
|
810
905
|
orig_num_commands = *num_commands;
|
811
906
|
nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
|
812
907
|
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
|
813
|
-
InitZopfliCostModel(m,
|
908
|
+
InitZopfliCostModel(m, model, ¶ms->dist, num_bytes);
|
814
909
|
if (BROTLI_IS_OOM(m)) return;
|
815
910
|
for (i = 0; i < 2; i++) {
|
816
911
|
BrotliInitZopfliNodes(nodes, num_bytes + 1);
|
817
912
|
if (i == 0) {
|
818
913
|
ZopfliCostModelSetFromLiteralCosts(
|
819
|
-
|
914
|
+
model, position, ringbuffer, ringbuffer_mask);
|
820
915
|
} else {
|
821
|
-
ZopfliCostModelSetFromCommands(
|
916
|
+
ZopfliCostModelSetFromCommands(model, position, ringbuffer,
|
822
917
|
ringbuffer_mask, commands, *num_commands - orig_num_commands,
|
823
918
|
orig_last_insert_len);
|
824
919
|
}
|
@@ -827,12 +922,13 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
|
827
922
|
*last_insert_len = orig_last_insert_len;
|
828
923
|
memcpy(dist_cache, orig_dist_cache, 4 * sizeof(dist_cache[0]));
|
829
924
|
*num_commands += ZopfliIterate(num_bytes, position, ringbuffer,
|
830
|
-
ringbuffer_mask, params, gap, dist_cache,
|
925
|
+
ringbuffer_mask, params, gap, dist_cache, model, num_matches, matches,
|
831
926
|
nodes);
|
832
927
|
BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
|
833
928
|
last_insert_len, params, commands, num_literals);
|
834
929
|
}
|
835
|
-
CleanupZopfliCostModel(m,
|
930
|
+
CleanupZopfliCostModel(m, model);
|
931
|
+
BROTLI_FREE(m, model);
|
836
932
|
BROTLI_FREE(m, nodes);
|
837
933
|
BROTLI_FREE(m, matches);
|
838
934
|
BROTLI_FREE(m, num_matches);
|
@@ -9,15 +9,16 @@
|
|
9
9
|
#ifndef BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
|
10
10
|
#define BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
|
11
11
|
|
12
|
+
#include <brotli/types.h>
|
13
|
+
|
12
14
|
#include "../common/constants.h"
|
13
15
|
#include "../common/context.h"
|
14
16
|
#include "../common/dictionary.h"
|
15
17
|
#include "../common/platform.h"
|
16
|
-
#include
|
17
|
-
#include "
|
18
|
-
#include "
|
19
|
-
#include "
|
20
|
-
#include "./quality.h"
|
18
|
+
#include "command.h"
|
19
|
+
#include "hash.h"
|
20
|
+
#include "memory.h"
|
21
|
+
#include "quality.h"
|
21
22
|
|
22
23
|
#if defined(__cplusplus) || defined(c_plusplus)
|
23
24
|
extern "C" {
|
@@ -28,13 +28,11 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
|
28
28
|
const size_t random_heuristics_window_size =
|
29
29
|
LiteralSpreeLengthForSparseSearch(params);
|
30
30
|
size_t apply_random_heuristics = position + random_heuristics_window_size;
|
31
|
-
const size_t gap =
|
31
|
+
const size_t gap = params->dictionary.compound.total_size;
|
32
32
|
|
33
33
|
/* Minimum score to accept a backward reference. */
|
34
34
|
const score_t kMinScore = BROTLI_SCORE_BASE + 100;
|
35
35
|
|
36
|
-
BROTLI_UNUSED(literal_context_lut);
|
37
|
-
|
38
36
|
FN(PrepareDistanceCache)(privat, dist_cache);
|
39
37
|
|
40
38
|
while (position + FN(HashTypeLength)() < pos_end) {
|
@@ -43,13 +41,29 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
|
43
41
|
size_t dictionary_start = BROTLI_MIN(size_t,
|
44
42
|
position + position_offset, max_backward_limit);
|
45
43
|
HasherSearchResult sr;
|
44
|
+
int dict_id = 0;
|
45
|
+
uint8_t p1 = 0;
|
46
|
+
uint8_t p2 = 0;
|
47
|
+
if (params->dictionary.contextual.context_based) {
|
48
|
+
p1 = position >= 1 ?
|
49
|
+
ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
|
50
|
+
p2 = position >= 2 ?
|
51
|
+
ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
|
52
|
+
dict_id = params->dictionary.contextual.context_map[
|
53
|
+
BROTLI_CONTEXT(p1, p2, literal_context_lut)];
|
54
|
+
}
|
46
55
|
sr.len = 0;
|
47
56
|
sr.len_code_delta = 0;
|
48
57
|
sr.distance = 0;
|
49
58
|
sr.score = kMinScore;
|
50
|
-
FN(FindLongestMatch)(privat,
|
59
|
+
FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
|
51
60
|
ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
|
52
61
|
max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
|
62
|
+
if (ENABLE_COMPOUND_DICTIONARY) {
|
63
|
+
LookupCompoundDictionaryMatch(¶ms->dictionary.compound, ringbuffer,
|
64
|
+
ringbuffer_mask, dist_cache, position, max_length,
|
65
|
+
dictionary_start, params->dist.max_distance, &sr);
|
66
|
+
}
|
53
67
|
if (sr.score > kMinScore) {
|
54
68
|
/* Found a match. Let's look for something even better ahead. */
|
55
69
|
int delayed_backward_references_in_row = 0;
|
@@ -65,11 +79,23 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
|
65
79
|
max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
|
66
80
|
dictionary_start = BROTLI_MIN(size_t,
|
67
81
|
position + 1 + position_offset, max_backward_limit);
|
82
|
+
if (params->dictionary.contextual.context_based) {
|
83
|
+
p2 = p1;
|
84
|
+
p1 = ringbuffer[position & ringbuffer_mask];
|
85
|
+
dict_id = params->dictionary.contextual.context_map[
|
86
|
+
BROTLI_CONTEXT(p1, p2, literal_context_lut)];
|
87
|
+
}
|
68
88
|
FN(FindLongestMatch)(privat,
|
69
|
-
|
89
|
+
params->dictionary.contextual.dict[dict_id],
|
70
90
|
ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
|
71
91
|
max_distance, dictionary_start + gap, params->dist.max_distance,
|
72
92
|
&sr2);
|
93
|
+
if (ENABLE_COMPOUND_DICTIONARY) {
|
94
|
+
LookupCompoundDictionaryMatch(
|
95
|
+
¶ms->dictionary.compound, ringbuffer,
|
96
|
+
ringbuffer_mask, dist_cache, position + 1, max_length,
|
97
|
+
dictionary_start, params->dist.max_distance, &sr2);
|
98
|
+
}
|
73
99
|
if (sr2.score >= sr.score + cost_diff_lazy) {
|
74
100
|
/* Ok, let's just write one byte for now and start a match from the
|
75
101
|
next byte. */
|
@@ -6,28 +6,29 @@
|
|
6
6
|
|
7
7
|
/* Functions to estimate the bit cost of Huffman trees. */
|
8
8
|
|
9
|
-
#include "
|
9
|
+
#include "bit_cost.h"
|
10
|
+
|
11
|
+
#include <brotli/types.h>
|
10
12
|
|
11
13
|
#include "../common/constants.h"
|
12
14
|
#include "../common/platform.h"
|
13
|
-
#include
|
14
|
-
#include "
|
15
|
-
#include "./histogram.h"
|
15
|
+
#include "fast_log.h"
|
16
|
+
#include "histogram.h"
|
16
17
|
|
17
18
|
#if defined(__cplusplus) || defined(c_plusplus)
|
18
19
|
extern "C" {
|
19
20
|
#endif
|
20
21
|
|
21
22
|
#define FN(X) X ## Literal
|
22
|
-
#include "
|
23
|
+
#include "bit_cost_inc.h" /* NOLINT(build/include) */
|
23
24
|
#undef FN
|
24
25
|
|
25
26
|
#define FN(X) X ## Command
|
26
|
-
#include "
|
27
|
+
#include "bit_cost_inc.h" /* NOLINT(build/include) */
|
27
28
|
#undef FN
|
28
29
|
|
29
30
|
#define FN(X) X ## Distance
|
30
|
-
#include "
|
31
|
+
#include "bit_cost_inc.h" /* NOLINT(build/include) */
|
31
32
|
#undef FN
|
32
33
|
|
33
34
|
#if defined(__cplusplus) || defined(c_plusplus)
|
@@ -9,10 +9,11 @@
|
|
9
9
|
#ifndef BROTLI_ENC_BIT_COST_H_
|
10
10
|
#define BROTLI_ENC_BIT_COST_H_
|
11
11
|
|
12
|
-
#include "../common/platform.h"
|
13
12
|
#include <brotli/types.h>
|
14
|
-
|
15
|
-
#include "
|
13
|
+
|
14
|
+
#include "../common/platform.h"
|
15
|
+
#include "fast_log.h"
|
16
|
+
#include "histogram.h"
|
16
17
|
|
17
18
|
#if defined(__cplusplus) || defined(c_plusplus)
|
18
19
|
extern "C" {
|
@@ -45,7 +46,7 @@ static BROTLI_INLINE double BitsEntropy(
|
|
45
46
|
const uint32_t* population, size_t size) {
|
46
47
|
size_t sum;
|
47
48
|
double retval = ShannonEntropy(population, size, &sum);
|
48
|
-
if (retval < sum) {
|
49
|
+
if (retval < (double)sum) {
|
49
50
|
/* At least one bit per literal is needed. */
|
50
51
|
retval = (double)sum;
|
51
52
|
}
|
@@ -6,18 +6,18 @@
|
|
6
6
|
|
7
7
|
/* Block split point selection utilities. */
|
8
8
|
|
9
|
-
#include "
|
9
|
+
#include "block_splitter.h"
|
10
10
|
|
11
11
|
#include <string.h> /* memcpy, memset */
|
12
12
|
|
13
13
|
#include "../common/platform.h"
|
14
|
-
#include "
|
15
|
-
#include "
|
16
|
-
#include "
|
17
|
-
#include "
|
18
|
-
#include "
|
19
|
-
#include "
|
20
|
-
#include "
|
14
|
+
#include "bit_cost.h"
|
15
|
+
#include "cluster.h"
|
16
|
+
#include "command.h"
|
17
|
+
#include "fast_log.h"
|
18
|
+
#include "histogram.h"
|
19
|
+
#include "memory.h"
|
20
|
+
#include "quality.h"
|
21
21
|
|
22
22
|
#if defined(__cplusplus) || defined(c_plusplus)
|
23
23
|
extern "C" {
|
@@ -30,6 +30,7 @@ static const double kCommandBlockSwitchCost = 13.5;
|
|
30
30
|
static const double kDistanceBlockSwitchCost = 14.6;
|
31
31
|
static const size_t kLiteralStrideLength = 70;
|
32
32
|
static const size_t kCommandStrideLength = 40;
|
33
|
+
static const size_t kDistanceStrideLength = 40;
|
33
34
|
static const size_t kSymbolsPerLiteralHistogram = 544;
|
34
35
|
static const size_t kSymbolsPerCommandHistogram = 530;
|
35
36
|
static const size_t kSymbolsPerDistanceHistogram = 544;
|
@@ -89,19 +90,19 @@ static BROTLI_INLINE double BitCost(size_t count) {
|
|
89
90
|
#define FN(X) X ## Literal
|
90
91
|
#define DataType uint8_t
|
91
92
|
/* NOLINTNEXTLINE(build/include) */
|
92
|
-
#include "
|
93
|
+
#include "block_splitter_inc.h"
|
93
94
|
#undef DataType
|
94
95
|
#undef FN
|
95
96
|
|
96
97
|
#define FN(X) X ## Command
|
97
98
|
#define DataType uint16_t
|
98
99
|
/* NOLINTNEXTLINE(build/include) */
|
99
|
-
#include "
|
100
|
+
#include "block_splitter_inc.h"
|
100
101
|
#undef FN
|
101
102
|
|
102
103
|
#define FN(X) X ## Distance
|
103
104
|
/* NOLINTNEXTLINE(build/include) */
|
104
|
-
#include "
|
105
|
+
#include "block_splitter_inc.h"
|
105
106
|
#undef DataType
|
106
107
|
#undef FN
|
107
108
|
|
@@ -119,6 +120,8 @@ void BrotliDestroyBlockSplit(MemoryManager* m, BlockSplit* self) {
|
|
119
120
|
BROTLI_FREE(m, self->lengths);
|
120
121
|
}
|
121
122
|
|
123
|
+
/* Extracts literals, command distance and prefix codes, then applies
|
124
|
+
* SplitByteVector to create partitioning. */
|
122
125
|
void BrotliSplitBlock(MemoryManager* m,
|
123
126
|
const Command* cmds,
|
124
127
|
const size_t num_commands,
|
@@ -136,7 +139,9 @@ void BrotliSplitBlock(MemoryManager* m,
|
|
136
139
|
/* Create a continuous array of literals. */
|
137
140
|
CopyLiteralsToByteArray(cmds, num_commands, data, pos, mask, literals);
|
138
141
|
/* Create the block split on the array of literals.
|
139
|
-
|
142
|
+
* Literal histograms can have alphabet size up to 256.
|
143
|
+
* Though, to accomodate context modeling, less than half of maximum size
|
144
|
+
* is allowed. */
|
140
145
|
SplitByteVectorLiteral(
|
141
146
|
m, literals, literals_count,
|
142
147
|
kSymbolsPerLiteralHistogram, kMaxLiteralHistograms,
|
@@ -144,6 +149,10 @@ void BrotliSplitBlock(MemoryManager* m,
|
|
144
149
|
literal_split);
|
145
150
|
if (BROTLI_IS_OOM(m)) return;
|
146
151
|
BROTLI_FREE(m, literals);
|
152
|
+
/* NB: this might be a good place for injecting extra splitting without
|
153
|
+
* increasing encoder complexity; however, output parition would be less
|
154
|
+
* optimal than one produced with forced splitting inside
|
155
|
+
* SplitByteVector (FindBlocks / ClusterBlocks). */
|
147
156
|
}
|
148
157
|
|
149
158
|
{
|
@@ -161,7 +170,7 @@ void BrotliSplitBlock(MemoryManager* m,
|
|
161
170
|
kCommandStrideLength, kCommandBlockSwitchCost, params,
|
162
171
|
insert_and_copy_split);
|
163
172
|
if (BROTLI_IS_OOM(m)) return;
|
164
|
-
/* TODO: reuse for distances? */
|
173
|
+
/* TODO(eustas): reuse for distances? */
|
165
174
|
BROTLI_FREE(m, insert_and_copy_codes);
|
166
175
|
}
|
167
176
|
|
@@ -181,13 +190,27 @@ void BrotliSplitBlock(MemoryManager* m,
|
|
181
190
|
SplitByteVectorDistance(
|
182
191
|
m, distance_prefixes, j,
|
183
192
|
kSymbolsPerDistanceHistogram, kMaxCommandHistograms,
|
184
|
-
|
193
|
+
kDistanceStrideLength, kDistanceBlockSwitchCost, params,
|
185
194
|
dist_split);
|
186
195
|
if (BROTLI_IS_OOM(m)) return;
|
187
196
|
BROTLI_FREE(m, distance_prefixes);
|
188
197
|
}
|
189
198
|
}
|
190
199
|
|
200
|
+
#if defined(BROTLI_TEST)
|
201
|
+
size_t CountLiteralsForTest(const Command*, const size_t);
|
202
|
+
size_t CountLiteralsForTest(const Command* cmds, const size_t num_commands) {
|
203
|
+
return CountLiterals(cmds, num_commands);
|
204
|
+
}
|
205
|
+
|
206
|
+
void CopyLiteralsToByteArrayForTest(const Command*,
|
207
|
+
const size_t, const uint8_t*, const size_t, const size_t, uint8_t*);
|
208
|
+
void CopyLiteralsToByteArrayForTest(const Command* cmds,
|
209
|
+
const size_t num_commands, const uint8_t* data, const size_t offset,
|
210
|
+
const size_t mask, uint8_t* literals) {
|
211
|
+
CopyLiteralsToByteArray(cmds, num_commands, data, offset, mask, literals);
|
212
|
+
}
|
213
|
+
#endif
|
191
214
|
|
192
215
|
#if defined(__cplusplus) || defined(c_plusplus)
|
193
216
|
} /* extern "C" */
|
@@ -9,11 +9,12 @@
|
|
9
9
|
#ifndef BROTLI_ENC_BLOCK_SPLITTER_H_
|
10
10
|
#define BROTLI_ENC_BLOCK_SPLITTER_H_
|
11
11
|
|
12
|
-
#include "../common/platform.h"
|
13
12
|
#include <brotli/types.h>
|
14
|
-
|
15
|
-
#include "
|
16
|
-
#include "
|
13
|
+
|
14
|
+
#include "../common/platform.h"
|
15
|
+
#include "command.h"
|
16
|
+
#include "memory.h"
|
17
|
+
#include "quality.h"
|
17
18
|
|
18
19
|
#if defined(__cplusplus) || defined(c_plusplus)
|
19
20
|
extern "C" {
|