/* A (forgetful) hash table where each hash bucket contains a binary tree of sequenceswhosefirst4bytessharethesamehashcode. EachsequenceisMAX_TREE_COMP_LENGTHlongandisidentifiedbyitsstarting positionintheinputdata.Thebinarytreeissortedbythelexicographic orderofthesequences,anditisalsoamax-heapwithrespecttothe
starting positions. */
static uint32_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data) {
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32; /* The higher bits contain more mixture from the multiplication,
so we take our results from there. */ return h >> (32 - BUCKET_BITS);
}
typedefstruct HashToBinaryTree { /* The window size minus 1 */
size_t window_mask_;
/* Hash table that maps the 4-byte hashes of the sequence to the last positionwherethishashwasfound,whichistherootofthebinary
tree of sequences that share this hash bucket. */
uint32_t* buckets_; /* uint32_t[BUCKET_SIZE]; */
/* A position used to mark a non-existent sequence, i.e. a tree is empty if itsrootisatinvalid_pos_andanodeisaleafifbothitschildren
are at invalid_pos_. */
uint32_t invalid_pos_;
/* --- Dynamic size members --- */
/* The union of the binary trees of each hash bucket. The root of the tree correspondingtoahashisasequencestartingatbuckets_[hash]and theleftandrightchildrenofasequencestartingatposare
forest_[2 * pos] and forest_[2 * pos + 1]. */
uint32_t* forest_; /* uint32_t[2 * num_nodes] */
} HashToBinaryTree;
/* Stores the hash of the next 4 bytes and in a single tree-traversal, the hashbucket'sbinarytreeissearchedformatchesandisre-rootedatthe currentposition.
This function must be called with increasing cur_ix positions. */ static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
HashToBinaryTree* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data, const size_t cur_ix, const size_t ring_buffer_mask, const size_t max_length, const size_t max_backward, size_t* const BROTLI_RESTRICT best_len,
BackwardMatch* BROTLI_RESTRICT matches) { const size_t cur_ix_masked = cur_ix & ring_buffer_mask; const size_t max_comp_len =
BROTLI_MIN(size_t, max_length, MAX_TREE_COMP_LENGTH); const BROTLI_BOOL should_reroot_tree =
TO_BROTLI_BOOL(max_length >= MAX_TREE_COMP_LENGTH); const uint32_t key = FN(HashBytes)(&data[cur_ix_masked]);
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
uint32_t* BROTLI_RESTRICT forest = self->forest_;
size_t prev_ix = buckets[key]; /* The forest index of the rightmost node of the left subtree of the new
root, updated as we traverse and re-root the tree of the hash bucket. */
size_t node_left = FN(LeftChildIndex)(self, cur_ix); /* The forest index of the leftmost node of the right subtree of the new
root, updated as we traverse and re-root the tree of the hash bucket. */
size_t node_right = FN(RightChildIndex)(self, cur_ix); /* The match length of the rightmost node of the left subtree of the new
root, updated as we traverse and re-root the tree of the hash bucket. */
size_t best_len_left = 0; /* The match length of the leftmost node of the right subtree of the new
root, updated as we traverse and re-root the tree of the hash bucket. */
size_t best_len_right = 0;
size_t depth_remaining; if (should_reroot_tree) {
buckets[key] = (uint32_t)cur_ix;
} for (depth_remaining = MAX_TREE_SEARCH_DEPTH; ; --depth_remaining) { const size_t backward = cur_ix - prev_ix; const size_t prev_ix_masked = prev_ix & ring_buffer_mask; if (backward == 0 || backward > max_backward || depth_remaining == 0) { if (should_reroot_tree) {
forest[node_left] = self->invalid_pos_;
forest[node_right] = self->invalid_pos_;
} break;
}
{ const size_t cur_len = BROTLI_MIN(size_t, best_len_left, best_len_right);
size_t len;
BROTLI_DCHECK(cur_len <= MAX_TREE_COMP_LENGTH);
len = cur_len +
FindMatchLengthWithLimit(&data[cur_ix_masked + cur_len],
&data[prev_ix_masked + cur_len],
max_length - cur_len);
BROTLI_DCHECK( 0 == memcmp(&data[cur_ix_masked], &data[prev_ix_masked], len)); if (matches && len > *best_len) {
*best_len = len;
InitBackwardMatch(matches++, backward, len);
} if (len >= max_comp_len) { if (should_reroot_tree) {
forest[node_left] = forest[FN(LeftChildIndex)(self, prev_ix)];
forest[node_right] = forest[FN(RightChildIndex)(self, prev_ix)];
} break;
} if (data[cur_ix_masked + len] > data[prev_ix_masked + len]) {
best_len_left = len; if (should_reroot_tree) {
forest[node_left] = (uint32_t)prev_ix;
}
node_left = FN(RightChildIndex)(self, prev_ix);
prev_ix = forest[node_left];
} else {
best_len_right = len; if (should_reroot_tree) {
forest[node_right] = (uint32_t)prev_ix;
}
node_right = FN(LeftChildIndex)(self, prev_ix);
prev_ix = forest[node_right];
}
}
} return matches;
}
/* Finds all backward matches of &data[cur_ix & ring_buffer_mask] up to the lengthofmax_lengthandstoresthepositioncur_ixinthehashtable.
/* Stores the hash of the next 4 bytes and re-roots the binary tree at the currentsequence,withoutreturninganymatches.
REQUIRES: ix + MAX_TREE_COMP_LENGTH <= end-of-current-block */ static BROTLI_INLINE void FN(Store)(HashToBinaryTree* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) { /* Maximum distance is window size - 16, see section 9.1. of the spec. */ const size_t max_backward = self->window_mask_ - BROTLI_WINDOW_GAP + 1;
FN(StoreAndFindMatches)(self, data, ix, mask, MAX_TREE_COMP_LENGTH,
max_backward, NULL, NULL);
}
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
HashToBinaryTree* BROTLI_RESTRICT self,
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
size_t ringbuffer_mask) { if (num_bytes >= FN(HashTypeLength)() - 1 &&
position >= MAX_TREE_COMP_LENGTH) { /* Store the last `MAX_TREE_COMP_LENGTH - 1` positions in the hasher. Thesecouldnotbecalculatedbefore,sincetheyrequireknowledge
of both the previous and the current block. */ const size_t i_start = position - MAX_TREE_COMP_LENGTH + 1; const size_t i_end = BROTLI_MIN(size_t, position, i_start + num_bytes);
size_t i; for (i = i_start; i < i_end; ++i) { /* Maximum distance is window size - 16, see section 9.1. of the spec. Furthermore,wehavetomakesurethatwedon'tlookfurtherback fromthestartofthenextblockthanthewindowsize,otherwisewe
could access already overwritten areas of the ring-buffer. */ const size_t max_backward =
self->window_mask_ - BROTLI_MAX(size_t,
BROTLI_WINDOW_GAP - 1,
position - i); /* We know that i + MAX_TREE_COMP_LENGTH <= position + num_bytes, i.e. the endofthecurrentblockandthatwehaveatleast
MAX_TREE_COMP_LENGTH tail in the ring-buffer. */
FN(StoreAndFindMatches)(self, ringbuffer, i, ringbuffer_mask,
MAX_TREE_COMP_LENGTH, max_backward, NULL, NULL);
}
}
}
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.