Exemple #1
0
        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);
        }
Exemple #2
0
            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);
            }
Exemple #3
0
        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_, &params_->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;
            }
        }
Exemple #4
0
            /* 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);
            }