Updates to Brotli compression format, decoder and encoder
This commit contains a batch of changes that were made to the Brotli
compression algorithm in the last month. Most important changes:
* Fixes to the spec.
* Change of code length code order.
* Use a 2-level Huffman lookup table in the decoder.
* Faster uncompressed meta-block decoding.
* Optimized encoding of the Huffman code.
* Detection of UTF-8 input encoding.
* UTF-8 based literal cost modeling for improved
backward reference selection.
This commit is contained in:
+108
-201
@@ -12,11 +12,12 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Utilities for building and looking up Huffman trees.
|
||||
Utilities for building Huffman decoding tables.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "./huffman.h"
|
||||
#include "./safe_malloc.h"
|
||||
@@ -25,231 +26,137 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NON_EXISTENT_SYMBOL (-1)
|
||||
#define MAX_ALLOWED_CODE_LENGTH 15
|
||||
#define MAX_LENGTH 15
|
||||
|
||||
static void TreeNodeInit(HuffmanTreeNode* const node) {
|
||||
node->children_ = -1; /* means: 'unassigned so far' */
|
||||
}
|
||||
|
||||
static int NodeIsEmpty(const HuffmanTreeNode* const node) {
|
||||
return (node->children_ < 0);
|
||||
}
|
||||
|
||||
static int IsFull(const HuffmanTree* const tree) {
|
||||
return (tree->num_nodes_ == tree->max_nodes_);
|
||||
}
|
||||
|
||||
static void AssignChildren(HuffmanTree* const tree,
|
||||
HuffmanTreeNode* const node) {
|
||||
HuffmanTreeNode* const children = tree->root_ + tree->num_nodes_;
|
||||
node->children_ = (int)(children - node);
|
||||
assert(children - node == (int)(children - node));
|
||||
tree->num_nodes_ += 2;
|
||||
TreeNodeInit(children + 0);
|
||||
TreeNodeInit(children + 1);
|
||||
}
|
||||
|
||||
static int TreeInit(HuffmanTree* const tree, int num_leaves) {
|
||||
assert(tree != NULL);
|
||||
tree->root_ = NULL;
|
||||
if (num_leaves == 0) return 0;
|
||||
/* We allocate maximum possible nodes in the tree at once. */
|
||||
/* Note that a Huffman tree is a full binary tree; and in a full binary */
|
||||
/* tree with L leaves, the total number of nodes N = 2 * L - 1. */
|
||||
tree->max_nodes_ = 2 * num_leaves - 1;
|
||||
assert(tree->max_nodes_ < (1 << 16)); /* limit for the lut_jump_ table */
|
||||
tree->root_ = (HuffmanTreeNode*)BrotliSafeMalloc((uint64_t)tree->max_nodes_,
|
||||
sizeof(*tree->root_));
|
||||
if (tree->root_ == NULL) return 0;
|
||||
TreeNodeInit(tree->root_); /* Initialize root. */
|
||||
tree->num_nodes_ = 1;
|
||||
memset(tree->lut_bits_, 255, sizeof(tree->lut_bits_));
|
||||
memset(tree->lut_jump_, 0, sizeof(tree->lut_jump_));
|
||||
return 1;
|
||||
}
|
||||
|
||||
void BrotliHuffmanTreeRelease(HuffmanTree* const tree) {
|
||||
if (tree != NULL) {
|
||||
if (tree->root_ != NULL) {
|
||||
free(tree->root_);
|
||||
}
|
||||
tree->root_ = NULL;
|
||||
tree->max_nodes_ = 0;
|
||||
tree->num_nodes_ = 0;
|
||||
/* Returns reverse(reverse(key, len) + 1, len), where reverse(key, len) is the
|
||||
bit-wise reversal of the len least significant bits of key. */
|
||||
static BROTLI_INLINE int GetNextKey(int key, int len) {
|
||||
int step = 1 << (len - 1);
|
||||
while (key & step) {
|
||||
step >>= 1;
|
||||
}
|
||||
return (key & (step - 1)) + step;
|
||||
}
|
||||
|
||||
/* Utility: converts Huffman code lengths to corresponding Huffman codes. */
|
||||
/* 'huff_codes' should be pre-allocated. */
|
||||
/* Returns false in case of error (memory allocation, invalid codes). */
|
||||
static int HuffmanCodeLengthsToCodes(const uint8_t* const code_lengths,
|
||||
int code_lengths_size,
|
||||
int* const huff_codes) {
|
||||
int symbol;
|
||||
int code_len;
|
||||
int code_length_hist[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
|
||||
int curr_code;
|
||||
int next_codes[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
|
||||
int max_code_length = 0;
|
||||
/* Stores code in table[0], table[step], table[2*step], ..., table[end] */
|
||||
/* Assumes that end is an integer multiple of step */
|
||||
static BROTLI_INLINE void ReplicateValue(HuffmanCode* table,
|
||||
int step, int end,
|
||||
HuffmanCode code) {
|
||||
do {
|
||||
end -= step;
|
||||
table[end] = code;
|
||||
} while (end > 0);
|
||||
}
|
||||
|
||||
assert(code_lengths != NULL);
|
||||
assert(code_lengths_size > 0);
|
||||
assert(huff_codes != NULL);
|
||||
|
||||
/* Calculate max code length. */
|
||||
for (symbol = 0; symbol < code_lengths_size; ++symbol) {
|
||||
if (code_lengths[symbol] > max_code_length) {
|
||||
max_code_length = code_lengths[symbol];
|
||||
}
|
||||
/* Returns the table width of the next 2nd level table. count is the histogram
|
||||
of bit lengths for the remaining symbols, len is the code length of the next
|
||||
processed symbol */
|
||||
static BROTLI_INLINE int NextTableBitSize(const int* const count,
|
||||
int len, int root_bits) {
|
||||
int left = 1 << (len - root_bits);
|
||||
while (len < MAX_LENGTH) {
|
||||
left -= count[len];
|
||||
if (left <= 0) break;
|
||||
++len;
|
||||
left <<= 1;
|
||||
}
|
||||
if (max_code_length > MAX_ALLOWED_CODE_LENGTH) return 0;
|
||||
return len - root_bits;
|
||||
}
|
||||
|
||||
/* Calculate code length histogram. */
|
||||
for (symbol = 0; symbol < code_lengths_size; ++symbol) {
|
||||
++code_length_hist[code_lengths[symbol]];
|
||||
}
|
||||
code_length_hist[0] = 0;
|
||||
int BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
||||
int root_bits,
|
||||
const uint8_t* const code_lengths,
|
||||
int code_lengths_size) {
|
||||
HuffmanCode code; /* current table entry */
|
||||
HuffmanCode* table; /* next available space in table */
|
||||
int len; /* current code length */
|
||||
int symbol; /* symbol index in original or sorted table */
|
||||
int key; /* reversed prefix code */
|
||||
int step; /* step size to replicate values in current table */
|
||||
int low; /* low bits for current root entry */
|
||||
int mask; /* mask for low bits */
|
||||
int table_bits; /* key length of current table */
|
||||
int table_size; /* size of current table */
|
||||
int total_size; /* sum of root table size and 2nd level table sizes */
|
||||
int* sorted; /* symbols sorted by code length */
|
||||
int count[MAX_LENGTH + 1] = { 0 }; /* number of codes of each length */
|
||||
int offset[MAX_LENGTH + 1]; /* offsets in sorted table for each length */
|
||||
|
||||
/* Calculate the initial values of 'next_codes' for each code length. */
|
||||
/* next_codes[code_len] denotes the code to be assigned to the next symbol */
|
||||
/* of code length 'code_len'. */
|
||||
curr_code = 0;
|
||||
next_codes[0] = -1; /* Unused, as code length = 0 implies */
|
||||
/* code doesn't exist. */
|
||||
for (code_len = 1; code_len <= max_code_length; ++code_len) {
|
||||
curr_code = (curr_code + code_length_hist[code_len - 1]) << 1;
|
||||
next_codes[code_len] = curr_code;
|
||||
sorted = (int*)malloc((size_t)code_lengths_size * sizeof(*sorted));
|
||||
if (sorted == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get symbols. */
|
||||
for (symbol = 0; symbol < code_lengths_size; ++symbol) {
|
||||
if (code_lengths[symbol] > 0) {
|
||||
huff_codes[symbol] = next_codes[code_lengths[symbol]]++;
|
||||
} else {
|
||||
huff_codes[symbol] = NON_EXISTENT_SYMBOL;
|
||||
}
|
||||
/* build histogram of code lengths */
|
||||
for (symbol = 0; symbol < code_lengths_size; symbol++) {
|
||||
count[code_lengths[symbol]]++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const uint8_t kReverse7[128] = {
|
||||
0, 64, 32, 96, 16, 80, 48, 112, 8, 72, 40, 104, 24, 88, 56, 120,
|
||||
4, 68, 36, 100, 20, 84, 52, 116, 12, 76, 44, 108, 28, 92, 60, 124,
|
||||
2, 66, 34, 98, 18, 82, 50, 114, 10, 74, 42, 106, 26, 90, 58, 122,
|
||||
6, 70, 38, 102, 22, 86, 54, 118, 14, 78, 46, 110, 30, 94, 62, 126,
|
||||
1, 65, 33, 97, 17, 81, 49, 113, 9, 73, 41, 105, 25, 89, 57, 121,
|
||||
5, 69, 37, 101, 21, 85, 53, 117, 13, 77, 45, 109, 29, 93, 61, 125,
|
||||
3, 67, 35, 99, 19, 83, 51, 115, 11, 75, 43, 107, 27, 91, 59, 123,
|
||||
7, 71, 39, 103, 23, 87, 55, 119, 15, 79, 47, 111, 31, 95, 63, 127
|
||||
};
|
||||
|
||||
static int ReverseBitsShort(int bits, int num_bits) {
|
||||
return kReverse7[bits] >> (7 - num_bits);
|
||||
}
|
||||
|
||||
static int TreeAddSymbol(HuffmanTree* const tree,
|
||||
int symbol, int code, int code_length) {
|
||||
int step = HUFF_LUT_BITS;
|
||||
int base_code;
|
||||
HuffmanTreeNode* node = tree->root_;
|
||||
const HuffmanTreeNode* const max_node = tree->root_ + tree->max_nodes_;
|
||||
assert(symbol == (int16_t)symbol);
|
||||
if (code_length <= HUFF_LUT_BITS) {
|
||||
int i = 1 << (HUFF_LUT_BITS - code_length);
|
||||
base_code = ReverseBitsShort(code, code_length);
|
||||
do {
|
||||
int idx;
|
||||
--i;
|
||||
idx = base_code | (i << code_length);
|
||||
tree->lut_symbol_[idx] = (int16_t)symbol;
|
||||
tree->lut_bits_[idx] = (uint8_t)code_length;
|
||||
} while (i > 0);
|
||||
} else {
|
||||
base_code = ReverseBitsShort((code >> (code_length - HUFF_LUT_BITS)),
|
||||
HUFF_LUT_BITS);
|
||||
/* generate offsets into sorted symbol table by code length */
|
||||
offset[1] = 0;
|
||||
for (len = 1; len < MAX_LENGTH; len++) {
|
||||
offset[len + 1] = offset[len] + count[len];
|
||||
}
|
||||
while (code_length-- > 0) {
|
||||
if (node >= max_node) {
|
||||
return 0;
|
||||
}
|
||||
if (NodeIsEmpty(node)) {
|
||||
if (IsFull(tree)) return 0; /* error: too many symbols. */
|
||||
AssignChildren(tree, node);
|
||||
} else if (!HuffmanTreeNodeIsNotLeaf(node)) {
|
||||
return 0; /* leaf is already occupied. */
|
||||
}
|
||||
node += node->children_ + ((code >> code_length) & 1);
|
||||
if (--step == 0) {
|
||||
tree->lut_jump_[base_code] = (int16_t)(node - tree->root_);
|
||||
}
|
||||
}
|
||||
if (NodeIsEmpty(node)) {
|
||||
node->children_ = 0; /* turn newly created node into a leaf. */
|
||||
} else if (HuffmanTreeNodeIsNotLeaf(node)) {
|
||||
return 0; /* trying to assign a symbol to already used code. */
|
||||
}
|
||||
node->symbol_ = symbol; /* Add symbol in this node. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BrotliHuffmanTreeBuildImplicit(HuffmanTree* const tree,
|
||||
const uint8_t* const code_lengths,
|
||||
int code_lengths_size) {
|
||||
int symbol;
|
||||
int num_symbols = 0;
|
||||
int root_symbol = 0;
|
||||
|
||||
assert(tree != NULL);
|
||||
assert(code_lengths != NULL);
|
||||
|
||||
/* Find out number of symbols and the root symbol. */
|
||||
for (symbol = 0; symbol < code_lengths_size; ++symbol) {
|
||||
if (code_lengths[symbol] > 0) {
|
||||
/* Note: code length = 0 indicates non-existent symbol. */
|
||||
++num_symbols;
|
||||
root_symbol = symbol;
|
||||
/* sort symbols by length, by symbol order within each length */
|
||||
for (symbol = 0; symbol < code_lengths_size; symbol++) {
|
||||
if (code_lengths[symbol] != 0) {
|
||||
sorted[offset[code_lengths[symbol]]++] = symbol;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the tree. Will fail for num_symbols = 0 */
|
||||
if (!TreeInit(tree, num_symbols)) return 0;
|
||||
table = root_table;
|
||||
table_bits = root_bits;
|
||||
table_size = 1 << table_bits;
|
||||
total_size = table_size;
|
||||
|
||||
/* Build tree. */
|
||||
if (num_symbols == 1) { /* Trivial case. */
|
||||
const int max_symbol = code_lengths_size;
|
||||
if (root_symbol < 0 || root_symbol >= max_symbol) {
|
||||
BrotliHuffmanTreeRelease(tree);
|
||||
return 0;
|
||||
/* special case code with only one value */
|
||||
if (offset[MAX_LENGTH] == 1) {
|
||||
code.bits = 0;
|
||||
code.value = (uint16_t)sorted[0];
|
||||
for (key = 0; key < total_size; ++key) {
|
||||
table[key] = code;
|
||||
}
|
||||
return TreeAddSymbol(tree, root_symbol, 0, 0);
|
||||
} else { /* Normal case. */
|
||||
int ok = 0;
|
||||
free(sorted);
|
||||
return total_size;
|
||||
}
|
||||
|
||||
/* Get Huffman codes from the code lengths. */
|
||||
int* const codes =
|
||||
(int*)BrotliSafeMalloc((uint64_t)code_lengths_size, sizeof(*codes));
|
||||
if (codes == NULL) goto End;
|
||||
|
||||
if (!HuffmanCodeLengthsToCodes(code_lengths, code_lengths_size, codes)) {
|
||||
goto End;
|
||||
/* fill in root table */
|
||||
key = 0;
|
||||
symbol = 0;
|
||||
for (len = 1, step = 2; len <= root_bits; ++len, step <<= 1) {
|
||||
for (; count[len] > 0; --count[len]) {
|
||||
code.bits = (uint8_t)(len);
|
||||
code.value = (uint16_t)sorted[symbol++];
|
||||
ReplicateValue(&table[key], step, table_size, code);
|
||||
key = GetNextKey(key, len);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add symbols one-by-one. */
|
||||
for (symbol = 0; symbol < code_lengths_size; ++symbol) {
|
||||
if (code_lengths[symbol] > 0) {
|
||||
if (!TreeAddSymbol(tree, symbol, codes[symbol], code_lengths[symbol])) {
|
||||
goto End;
|
||||
}
|
||||
/* fill in 2nd level tables and add pointers to root table */
|
||||
mask = total_size - 1;
|
||||
low = -1;
|
||||
for (len = root_bits + 1, step = 2; len <= MAX_LENGTH; ++len, step <<= 1) {
|
||||
for (; count[len] > 0; --count[len]) {
|
||||
if ((key & mask) != low) {
|
||||
table += table_size;
|
||||
table_bits = NextTableBitSize(count, len, root_bits);
|
||||
table_size = 1 << table_bits;
|
||||
total_size += table_size;
|
||||
low = key & mask;
|
||||
root_table[low].bits = (uint8_t)(table_bits + root_bits);
|
||||
root_table[low].value = (uint16_t)((table - root_table) - low);
|
||||
}
|
||||
code.bits = (uint8_t)(len - root_bits);
|
||||
code.value = (uint16_t)sorted[symbol++];
|
||||
ReplicateValue(&table[key >> root_bits], step, table_size, code);
|
||||
key = GetNextKey(key, len);
|
||||
}
|
||||
ok = 1;
|
||||
End:
|
||||
free(codes);
|
||||
ok = ok && IsFull(tree);
|
||||
if (!ok) BrotliHuffmanTreeRelease(tree);
|
||||
return ok;
|
||||
}
|
||||
|
||||
free(sorted);
|
||||
return total_size;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
|
||||
Reference in New Issue
Block a user