/* Function for fast encoding of an input fragment, independently from the input history.Thisfunctionusesone-passprocessing:whenwefindabackward match,weimmediatelyemitthecorrespondingcommandandliteralcodesto thebitstream.
/* Builds a literal prefix code into "depths" and "bits" based on the statistics ofthe"input"stringandstoresitintothebitstream. Notethattheprefixcodehereisbuiltfromthepre-LZ77input,therefore wecanonlyapproximatethestatisticsoftheactualliteralstream. Moreover,forlonginputswebuildahistogramfromasampleoftheinput andthushavetoassignanon-zerodepthforeachliteral. Returnsestimatedcompressionratiomillibytes/charforencodinggiveninput
with generated code. */ static size_t BuildAndStoreLiteralPrefixCode(BrotliOnePassArena* s, const uint8_t* input, const size_t input_size,
uint8_t depths[256],
uint16_t bits[256],
size_t* storage_ix,
uint8_t* storage) {
uint32_t* BROTLI_RESTRICT const histogram = s->histogram;
size_t histogram_total;
size_t i;
memset(histogram, 0, sizeof(s->histogram));
if (input_size < (1 << 15)) { for (i = 0; i < input_size; ++i) {
++histogram[input[i]];
}
histogram_total = input_size; for (i = 0; i < 256; ++i) { /* We weigh the first 11 samples with weight 3 to account for the
balancing effect of the LZ77 phase on the histogram. */ const uint32_t adjust = 2 * BROTLI_MIN(uint32_t, histogram[i], 11u);
histogram[i] += adjust;
histogram_total += adjust;
}
} else { staticconst size_t kSampleRate = 29; for (i = 0; i < input_size; i += kSampleRate) {
++histogram[input[i]];
}
histogram_total = (input_size + kSampleRate - 1) / kSampleRate; for (i = 0; i < 256; ++i) { /* We add 1 to each population count to avoid 0 bit depths (since this is onlyasampleandwedon'tknowifthesymbolappearsornot),andwe weighthefirst11sampleswithweight3toaccountforthebalancing effectoftheLZ77phaseonthehistogram(morefrequentsymbolsare
more likely to be in backward references instead as literals). */ const uint32_t adjust = 1 + 2 * BROTLI_MIN(uint32_t, histogram[i], 11u);
histogram[i] += adjust;
histogram_total += adjust;
}
}
BrotliBuildAndStoreHuffmanTreeFast(s->tree, histogram, histogram_total, /* max_bits = */ 8,
depths, bits, storage_ix, storage);
{
size_t literal_ratio = 0; for (i = 0; i < 256; ++i) { if (histogram[i]) literal_ratio += histogram[i] * depths[i];
} /* Estimated encoding ratio, millibytes per symbol. */ return (literal_ratio * 125) / histogram_total;
}
}
/* Builds a command and distance prefix code (each 64 symbols) into "depth" and
"bits" based on "histogram" and stores it into the bit stream. */ staticvoid BuildAndStoreCommandPrefixCode(BrotliOnePassArena* s,
size_t* storage_ix, uint8_t* storage) { const uint32_t* const histogram = s->cmd_histo;
uint8_t* const depth = s->cmd_depth;
uint16_t* const bits = s->cmd_bits;
uint8_t* BROTLI_RESTRICT const tmp_depth = s->tmp_depth;
uint16_t* BROTLI_RESTRICT const tmp_bits = s->tmp_bits; /* TODO(eustas): do only once on initialization. */
memset(tmp_depth, 0, BROTLI_NUM_COMMAND_SYMBOLS);
BrotliCreateHuffmanTree(histogram, 64, 15, s->tree, depth);
BrotliCreateHuffmanTree(&histogram[64], 64, 14, s->tree, &depth[64]); /* We have to jump through a few hoops here in order to compute thecommandbitsbecausethesymbolsareinadifferentorderthanin thefullalphabet.Thislookscomplicated,buthavingthesymbols inthisorderinthecommandbitssavesafewbranchesintheEmit*
functions. */
memcpy(tmp_depth, depth, 24);
memcpy(tmp_depth + 24, depth + 40, 8);
memcpy(tmp_depth + 32, depth + 24, 8);
memcpy(tmp_depth + 40, depth + 48, 8);
memcpy(tmp_depth + 48, depth + 32, 8);
memcpy(tmp_depth + 56, depth + 56, 8);
BrotliConvertBitDepthsToSymbols(tmp_depth, 64, tmp_bits);
memcpy(bits, tmp_bits, 48);
memcpy(bits + 24, tmp_bits + 32, 16);
memcpy(bits + 32, tmp_bits + 48, 16);
memcpy(bits + 40, tmp_bits + 24, 16);
memcpy(bits + 48, tmp_bits + 40, 16);
memcpy(bits + 56, tmp_bits + 56, 16);
BrotliConvertBitDepthsToSymbols(&depth[64], 64, &bits[64]);
{ /* Create the bit length array for the full command alphabet. */
size_t i;
memset(tmp_depth, 0, 64); /* only 64 first values were used */
memcpy(tmp_depth, depth, 8);
memcpy(tmp_depth + 64, depth + 8, 8);
memcpy(tmp_depth + 128, depth + 16, 8);
memcpy(tmp_depth + 192, depth + 24, 8);
memcpy(tmp_depth + 384, depth + 32, 8); for (i = 0; i < 8; ++i) {
tmp_depth[128 + 8 * i] = depth[40 + i];
tmp_depth[256 + 8 * i] = depth[48 + i];
tmp_depth[448 + 8 * i] = depth[56 + i];
} /* TODO(eustas): could/should full-length machinery be avoided? */
BrotliStoreHuffmanTree(
tmp_depth, BROTLI_NUM_COMMAND_SYMBOLS, s->tree, storage_ix, storage);
}
BrotliStoreHuffmanTree(&depth[64], 64, s->tree, storage_ix, storage);
}
/* "next_emit" is a pointer to the first byte that is not covered by a previouscopy.Bytesbetween"next_emit"andthestartofthenextcopyor
the end of the input will be emitted as literal bytes. */ const uint8_t* next_emit = input; /* Save the start of the first block for position and distance computations.
*/ const uint8_t* base_ip = input;
const uint8_t* metablock_start = input;
size_t block_size = BROTLI_MIN(size_t, input_size, kFirstBlockSize);
size_t total_block_size = block_size; /* Save the bit position of the MLEN field of the meta-block header, so that
we can update it later if we decide to extend this meta-block. */
size_t mlen_storage_ix = *storage_ix + 3;
size_t literal_ratio;
const uint8_t* ip; int last_distance;
const size_t shift = 64u - table_bits;
BrotliStoreMetaBlockHeader(block_size, 0, storage_ix, storage); /* No block splits, no contexts. */
BrotliWriteBits(13, 0, storage_ix, storage);
{ /* Store the pre-compressed command and distance prefix codes. */
size_t i; for (i = 0; i + 7 < s->cmd_code_numbits; i += 8) {
BrotliWriteBits(8, s->cmd_code[i >> 3], storage_ix, storage);
}
}
BrotliWriteBits(s->cmd_code_numbits & 7,
s->cmd_code[s->cmd_code_numbits >> 3], storage_ix, storage);
emit_commands: /* Initialize the command and distance histograms. We will gather statisticsofcommandanddistancecodesduringtheprocessing ofthisblockanduseittoupdatethecommandanddistance
prefix codes for the next block. */
memcpy(s->cmd_histo, kCmdHistoSeed, sizeof(kCmdHistoSeed));
/* "ip" is the input pointer. */
ip = input;
last_distance = -1;
ip_end = input + block_size;
if (BROTLI_PREDICT_TRUE(block_size >= kInputMarginBytes)) { /* For the last block, we need to keep a 16 bytes margin so that we can be surethatalldistancesareatmostwindowsize-16. Forallotherblocks,weonlyneedtokeepamarginof5bytessothat
we don't go over the block size with a copy. */ const size_t len_limit = BROTLI_MIN(size_t, block_size - kMinMatchLen,
input_size - kInputMarginBytes); const uint8_t* ip_limit = input + len_limit;
uint32_t next_hash; for (next_hash = Hash(++ip, shift); ; ) { /* Step 1: Scan forward in the input looking for a 5-byte-long match. Ifwegetclosetoexhaustingtheinputthengotoemit_remainder.
The"skip"variablekeepstrackofhowmanybytestherearesincethe lastmatch;dividingitby32(i.e.right-shiftingbyfive)givesthe
number of bytes to move ahead for each iteration. */
uint32_t skip = 32;
table[hash] = (int)(ip - base_ip);
} while (BROTLI_PREDICT_TRUE(!IsMatch(ip, candidate)));
/* Check copy distance. If candidate is not feasible, continue search.
Checking is done outside of hot loop to reduce overhead. */ if (ip - candidate > MAX_DISTANCE) goto trawl;
/* Step 2: Emit the found match together with the literal bytes from "next_emit"tothebitstream,andthenseeifwecanfindanextmatch immediatelyafterwards.Repeatuntilwefindnomatchfortheinput
without emitting some literal bytes. */
next_block: /* If we have more data, write a new meta-block header and prefix codes and
then continue emitting commands. */ if (input_size > 0) {
metablock_start = input;
block_size = BROTLI_MIN(size_t, input_size, kFirstBlockSize);
total_block_size = block_size; /* Save the bit position of the MLEN field of the meta-block header, so that
we can update it later if we decide to extend this meta-block. */
mlen_storage_ix = *storage_ix + 3;
BrotliStoreMetaBlockHeader(block_size, 0, storage_ix, storage); /* No block splits, no contexts. */
BrotliWriteBits(13, 0, storage_ix, storage);
literal_ratio = BuildAndStoreLiteralPrefixCode(
s, input, block_size, lit_depth, lit_bits, storage_ix, storage);
BuildAndStoreCommandPrefixCode(s, storage_ix, storage); goto emit_commands;
}
if (!is_last) { /* If this is not the last block, update the command and distance prefix
codes for the next block and store the compressed forms. */
s->cmd_code[0] = 0;
s->cmd_code_numbits = 0;
BuildAndStoreCommandPrefixCode(s, &s->cmd_code_numbits, s->cmd_code);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.