示例#1
0
            public override unsafe void Initialize(HasherHandle handle, BrotliEncoderParams *params_)
            {
                HashToBinaryTree *self = Self(handle);

                self->window_mask_ = (1u << params_->lgwin) - 1u;
                self->invalid_pos_ = (uint)(0 - self->window_mask_);
            }
示例#2
0
            public override unsafe void StitchToPreviousBlock(HasherHandle handle, size_t num_bytes, size_t position,
                                                              byte *ringbuffer,
                                                              size_t ringbuffer_mask)
            {
                HashToBinaryTree *self = Self(handle);

                if (num_bytes >= HashTypeLength() - 1 &&
                    position >= MAX_TREE_COMP_LENGTH)
                {
                    /* Store the last `MAX_TREE_COMP_LENGTH - 1` positions in the hasher.
                     * These could not be calculated before, since they require knowledge
                     * of both the previous and the current block. */
                    size_t i_start = position - MAX_TREE_COMP_LENGTH + 1;
                    size_t i_end   = Math.Min(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, we have to make sure that we don't look further back
                         * from the start of the next block than the window size, otherwise we
                         * could access already overwritten areas of the ring-buffer. */
                        size_t max_backward =
                            self->window_mask_ - Math.Max(
                                BROTLI_WINDOW_GAP - 1,
                                position - i);

                        /* We know that i + MAX_TREE_COMP_LENGTH <= position + num_bytes, i.e. the
                         * end of the current block and that we have at least
                         * MAX_TREE_COMP_LENGTH tail in the ring-buffer. */
                        StoreAndFindMatches(self, ringbuffer, i, ringbuffer_mask,
                                            MAX_TREE_COMP_LENGTH, max_backward, null, null);
                    }
                }
            }
示例#3
0
            /* Stores the hash of the next 4 bytes and re-roots the binary tree at the
             * current sequence, without returning any matches.
             * REQUIRES: ix + MAX_TREE_COMP_LENGTH <= end-of-current-block */
            public override unsafe void Store(HasherHandle handle,
                                              byte *data, size_t mask, size_t ix)
            {
                HashToBinaryTree *self = Self(handle);
                /* Maximum distance is window size - 16, see section 9.1. of the spec. */
                size_t max_backward = self->window_mask_ - BROTLI_WINDOW_GAP + 1;

                StoreAndFindMatches(self, data, ix, mask, MAX_TREE_COMP_LENGTH,
                                    max_backward, null, null);
            }
示例#4
0
            public override unsafe void Prepare(HasherHandle handle, bool one_shot, size_t input_size, byte *data)
            {
                HashToBinaryTree *self = Self(handle);
                uint invalid_pos       = self->invalid_pos_;
                uint i;

                for (i = 0; i < BUCKET_SIZE; i++)
                {
                    self->buckets_[i] = invalid_pos;
                }
            }
示例#5
0
 private static unsafe size_t LeftChildIndex(HashToBinaryTree *self, size_t pos)
 {
     return(2 * (pos & self->window_mask_));
 }
示例#6
0
 private static unsafe uint *Forest(HashToBinaryTree *self)
 {
     return((uint *)(&self[1]));
 }
示例#7
0
            /* Stores the hash of the next 4 bytes and in a single tree-traversal, the
             * hash bucket's binary tree is searched for matches and is re-rooted at the
             * current position.
             *
             * If less than MAX_TREE_COMP_LENGTH data is available, the hash bucket of the
             * current position is searched for matches, but the state of the hash table
             * is not changed, since we can not know the final sorting order of the
             * current (incomplete) sequence.
             *
             * This function must be called with increasing cur_ix positions. */
            private static unsafe BackwardMatch *StoreAndFindMatches(
                HashToBinaryTree *self, byte *data,
                size_t cur_ix, size_t ring_buffer_mask, size_t max_length,
                size_t max_backward, size_t *best_len,
                BackwardMatch *matches)
            {
                size_t cur_ix_masked = cur_ix & ring_buffer_mask;
                size_t max_comp_len  =
                    Math.Min(max_length, MAX_TREE_COMP_LENGTH);
                bool should_reroot_tree =
                    max_length >= MAX_TREE_COMP_LENGTH;
                uint   key     = HashBytes(&data[cur_ix_masked]);
                uint * forest  = Forest(self);
                size_t prev_ix = self->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 = 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 = 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)
                {
                    self->buckets_[key] = (uint)cur_ix;
                }
                for (depth_remaining = MAX_TREE_SEARCH_DEPTH;; --depth_remaining)
                {
                    size_t backward       = cur_ix - prev_ix;
                    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;
                    }
                    {
                        size_t cur_len = Math.Min(best_len_left, best_len_right);
                        size_t len;
                        len = cur_len +
                              FindMatchLengthWithLimit(&data[cur_ix_masked + cur_len],
                                                       &data[prev_ix_masked + cur_len],
                                                       max_length - cur_len);
                        if (matches != null && len > *best_len)
                        {
                            *best_len = len;
                            InitBackwardMatch(matches++, backward, len);
                        }
                        if (len >= max_comp_len)
                        {
                            if (should_reroot_tree)
                            {
                                forest[node_left]  = forest[LeftChildIndex(self, prev_ix)];
                                forest[node_right] = forest[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] = (uint)prev_ix;
                            }
                            node_left = RightChildIndex(self, prev_ix);
                            prev_ix   = forest[node_left];
                        }
                        else
                        {
                            best_len_right = len;
                            if (should_reroot_tree)
                            {
                                forest[node_right] = (uint)prev_ix;
                            }
                            node_right = LeftChildIndex(self, prev_ix);
                            prev_ix    = forest[node_right];
                        }
                    }
                }
                return(matches);
            }