/* A (forgetful) hash table to the data seen by the compressor, to helpcreatebackwardreferencestopreviousdata.
Thisisahashmapoffixedsize(bucket_size_)toaringbufferof fixedsize(block_size_).Theringbuffercontainsthelastblock_size_
index positions of the given hash key in the compressed data. */
/* HashBytes is the function that chooses the bucket to place the address in. */ static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data,
uint64_t hash_mul) { const uint64_t h = BROTLI_UNALIGNED_LOAD64LE(data) * hash_mul; /* The higher bits contain more mixture from the multiplication,
so we take our results from there. */ return (size_t)(h >> (64 - 15 - TAG_HASH_BITS));
}
typedefstruct HashLongestMatch { /* Number of hash buckets. */
size_t bucket_size_; /* Only block_size_ newest backward references are kept,
and the older are forgotten. */
size_t block_size_; /* Hash multiplier tuned to match length. */
uint64_t hash_mul_; /* Mask for accessing entries in a block (in a ring-buffer manner). */
uint32_t block_mask_;
int block_bits_; int num_last_distances_to_check_;
/* Shortcuts. */
HasherCommon* common_;
/* --- Dynamic size members --- */
/* Number of entries in a particular bucket. */
uint16_t* num_; /* uint16_t[bucket_size]; */
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
HashLongestMatch* 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 >= 3) { /* Prepare the hashes for three last bytes of the last write. Thesecouldnotbecalculatedbefore,sincetheyrequireknowledge
of both the previous and the current block. */
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
}
}
/* Try last distance first. */ for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) { const size_t backward = (size_t)distance_cache[i];
size_t prev_ix = (size_t)(cur_ix - backward); if (prev_ix >= cur_ix) { continue;
} if (BROTLI_PREDICT_FALSE(backward > max_backward)) { continue;
}
prev_ix &= ring_buffer_mask;
if (cur_ix_masked + best_len > ring_buffer_mask) { break;
} if (prev_ix + best_len > ring_buffer_mask ||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) { continue;
}
{ const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
&data[cur_ix_masked],
max_length); if (len >= 3 || (len == 2 && i < 2)) { /* Comparing for >= 2 does not change the semantics, but just saves for afewunnecessarybinarylogarithmsinbackwardreferencescore,
since we are not interested in such short matches. */
score_t score = BackwardReferenceScoreUsingLastDistance(len); if (best_score < score) { if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i); if (best_score < score) {
best_score = score;
best_len = len;
out->len = best_len;
out->distance = backward;
out->score = best_score;
}
}
}
}
} /* we require matches of len >4, so increase best_len to 3, so we can compare
* 4 bytes all the time. */ if (best_len < 3) {
best_len = 3;
}
{ const uint8_t tag = hash & TAG_HASH_MASK; const uint32_t first4 = BrotliUnalignedRead32(data + cur_ix_masked); const size_t max_length_m4 = max_length - 4; const size_t head = (num[key] + 1) & self->block_mask_;
uint64_t matches =
GetMatchingTagMask(self->block_size_ / 16, tag, tag_bucket, head); /* Mask off any matches from uninitialized tags. */
uint16_t n = 65535 - num[key];
uint64_t block_has_unused_slots = self->block_size_ > n;
uint64_t mask = (block_has_unused_slots << (n & (64 - 1))) - 1;
matches &= mask; for (; matches > 0; matches &= (matches - 1)) { const size_t rb_index =
(head + (size_t)BROTLI_TZCNT64(matches)) & self->block_mask_;
size_t prev_ix = bucket[rb_index];
uint32_t current4; const size_t backward = cur_ix - prev_ix; if (BROTLI_PREDICT_FALSE(backward > max_backward)) { break;
}
prev_ix &= ring_buffer_mask; if (cur_ix_masked + best_len > ring_buffer_mask) { break;
} if (prev_ix + best_len > ring_buffer_mask || /* compare 4 bytes ending at best_len + 1 */
BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) !=
BrotliUnalignedRead32(&data[prev_ix + best_len - 3])) { continue;
}
current4 = BrotliUnalignedRead32(data + prev_ix); if (first4 != current4) continue;
{ const size_t len = FindMatchLengthWithLimit(&data[prev_ix + 4],
&data[cur_ix_masked + 4],
max_length_m4) + 4; const score_t score = BackwardReferenceScore(len, backward); if (best_score < score) {
best_score = score;
best_len = len;
out->len = best_len;
out->distance = backward;
out->score = best_score;
}
}
}
bucket[num[key] & self->block_mask_] = (uint32_t)cur_ix;
tag_bucket[num[key] & self->block_mask_] = tag;
--num[key];
} if (min_score == out->score) {
SearchInStaticDictionary(dictionary,
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
max_distance, out, BROTLI_FALSE);
}
}
#undef HashLongestMatch
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.37Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-10-01)
¤
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.