private static unsafe bool SearchInStaticDictionary( ushort *dictionary_hash, HasherHandle handle, byte *data, size_t max_length, size_t max_backward, HasherSearchResult *out_, bool shallow) { size_t key; size_t i; bool is_match_found = false; HasherCommon *self = GetHasherCommon(handle); if (self->dict_num_matches < (self->dict_num_lookups >> 7)) { return(false); } key = Hash14(data) << 1; for (i = 0; i < (shallow ? 1u : 2u); ++i, ++key) { size_t item = dictionary_hash[key]; self->dict_num_lookups++; if (item != 0) { bool item_matches = TestStaticDictionaryItem( item, data, max_length, max_backward, out_); if (item_matches) { self->dict_num_matches++; is_match_found = true; } } } return(is_match_found); }
public override unsafe void Initialize(HasherHandle handle, BrotliEncoderParams *params_) { HasherCommon * common = GetHasherCommon(handle); HashLongestMatch *self = Self(handle); self->hash_shift_ = 32 - common->params_.bucket_bits; self->bucket_size_ = (size_t)1 << common->params_.bucket_bits; self->block_size_ = (size_t)1 << common->params_.block_bits; self->block_mask_ = (uint)(self->block_size_ - 1); }
private static unsafe void HasherSetup(ref MemoryManager m, HasherHandle *handle, BrotliEncoderParams *params_, byte *data, size_t position, size_t input_size, bool is_last) { HasherHandle self = null; HasherCommon *common = null; bool one_shot = (position == 0 && is_last); if ((byte *)(*handle) == null) { size_t alloc_size; ChooseHasher(params_, ¶ms_->hasher); alloc_size = HasherSize(params_, one_shot, input_size); self = BrotliAllocate(ref m, alloc_size); *handle = self; common = GetHasherCommon(self); common->params_ = params_->hasher; Hasher h; if (kHashers.TryGetValue(params_->hasher.type, out h)) { h.Initialize(*handle, params_); } HasherReset(*handle); } self = *handle; common = GetHasherCommon(self); if (!common->is_prepared_) { Hasher h; if (kHashers.TryGetValue(params_->hasher.type, out h)) { h.Prepare(self, one_shot, input_size, data); } if (position == 0) { common->dict_num_lookups = 0; common->dict_num_matches = 0; } common->is_prepared_ = true; } }
/* Find a longest backward match of &data[cur_ix] up to the length of * max_length and stores the position cur_ix in the hash table. * * REQUIRES: FN(PrepareDistanceCache) must be invoked for current distance cache * values; if this method is invoked repeatedly with the same distance * cache values, it is enough to invoke FN(PrepareDistanceCache) once. * * Does not look for matches longer than max_length. * Does not look for matches further away than max_backward. * Writes the best match into |out|. * Returns true when match is found, otherwise false. */ public override unsafe bool FindLongestMatch(HasherHandle handle, ushort *dictionary_hash, byte *data, size_t ring_buffer_mask, int *distance_cache, size_t cur_ix, size_t max_length, size_t max_backward, HasherSearchResult *out_) { HasherCommon * common = GetHasherCommon(handle); HashLongestMatch *self = Self(handle); ushort * num = Num(self); uint * buckets = Buckets(self); size_t cur_ix_masked = cur_ix & ring_buffer_mask; bool is_match_found = false; /* Don't accept a short copy from far away. */ score_t best_score = out_->score; size_t best_len = out_->len; size_t i; out_->len = 0; out_->len_x_code = 0; /* Try last distance first. */ for (i = 0; i < (size_t)common->params_.num_last_distances_to_check; ++i) { size_t backward = (size_t)distance_cache[i]; size_t prev_ix = (size_t)(cur_ix - backward); if (prev_ix >= cur_ix) { continue; } if ((backward > max_backward)) { continue; } prev_ix &= ring_buffer_mask; if (cur_ix_masked + best_len > ring_buffer_mask || prev_ix + best_len > ring_buffer_mask || data[cur_ix_masked + best_len] != data[prev_ix + best_len]) { continue; } { 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 * a few unnecessary binary logarithms in backward reference score, * 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; is_match_found = true; } } } } } { uint key = HashBytes(&data[cur_ix_masked], self->hash_shift_); uint *bucket = &buckets[key << common->params_.block_bits]; size_t down = (num[key] > self->block_size_) ? (num[key] - self->block_size_) : 0; for (i = num[key]; i > down;) { size_t prev_ix = bucket[--i & self->block_mask_]; size_t backward = cur_ix - prev_ix; if ((backward > max_backward)) { break; } prev_ix &= ring_buffer_mask; if (cur_ix_masked + best_len > ring_buffer_mask || prev_ix + best_len > ring_buffer_mask || data[cur_ix_masked + best_len] != data[prev_ix + best_len]) { continue; } { size_t len = FindMatchLengthWithLimit(&data[prev_ix], &data[cur_ix_masked], max_length); if (len >= 4) { /* Comparing for >= 3 does not change the semantics, but just saves * for a few unnecessary binary logarithms in backward reference * score, since we are not interested in such short matches. */ 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; is_match_found = true; } } } } bucket[num[key] & self->block_mask_] = (uint)cur_ix; ++num[key]; } if (!is_match_found) { is_match_found = SearchInStaticDictionary(dictionary_hash, handle, &data[cur_ix_masked], max_length, max_backward, out_, false); } return(is_match_found); }