示例#1
0
        /* Maintains "ZopfliNode array invariant" and pushes node to the queue, if it
         * is eligible. */
        private static unsafe void EvaluateNode(
            size_t block_start, size_t pos, size_t max_backward_limit,
            int *starting_dist_cache, ZopfliCostModel *model,
            StartPosQueue *queue, ZopfliNode *nodes)
        {
            /* Save cost, because ComputeDistanceCache invalidates it. */
            float node_cost = nodes[pos].u.cost;

            nodes[pos].u.shortcut = ComputeDistanceShortcut(
                block_start, pos, max_backward_limit, nodes);
            if (node_cost <= ZopfliCostModelGetLiteralCosts(model, 0, pos))
            {
                PosData posdata;
                posdata.pos      = pos;
                posdata.cost     = node_cost;
                posdata.costdiff = node_cost -
                                   ZopfliCostModelGetLiteralCosts(model, 0, pos);
                ComputeDistanceCache(
                    pos, starting_dist_cache, nodes, posdata.distance_cache);
                StartPosQueuePush(queue, &posdata);
            }
        }
示例#2
0
        private static unsafe void StartPosQueuePush(StartPosQueue *self, PosData *posdata)
        {
            size_t   offset = ~(self->idx_++) & 7;
            size_t   len    = StartPosQueueSize(self);
            size_t   i;
            PosData *q = self->q_;

            q[offset] = *posdata;

            /* Restore the sorted order. In the list of |len| items at most |len - 1|
             * adjacent element comparisons / swaps are required. */
            for (i = 1; i < len; ++i)
            {
                if (q[offset & 7].costdiff > q[(offset + 1) & 7].costdiff)
                {
                    PosData tmp = q[offset & 7];
                    q[offset & 7]       = q[(offset + 1) & 7];
                    q[(offset + 1) & 7] = tmp;
                }
                ++offset;
            }
        }
示例#3
0
 private static unsafe void InitStartPosQueue(StartPosQueue *self)
 {
     self->idx_ = 0;
 }
示例#4
0
        /* Returns longest copy length. */
        private static unsafe size_t UpdateNodes(
            size_t num_bytes, size_t block_start, size_t pos,
            byte *ringbuffer, size_t ringbuffer_mask,
            BrotliEncoderParams *params_, size_t max_backward_limit,
            int *starting_dist_cache, size_t num_matches,
            BackwardMatch *matches, ZopfliCostModel *model,
            StartPosQueue *queue, ZopfliNode *nodes)
        {
            size_t cur_ix         = block_start + pos;
            size_t cur_ix_masked  = cur_ix & ringbuffer_mask;
            size_t max_distance   = Math.Min(cur_ix, max_backward_limit);
            size_t max_len        = num_bytes - pos;
            size_t max_zopfli_len = MaxZopfliLen(params_);
            size_t max_iters      = MaxZopfliCandidates(params_);
            size_t min_len;
            size_t result = 0;
            size_t k;

            EvaluateNode(block_start, pos, max_backward_limit, starting_dist_cache, model,
                         queue, nodes);

            {
                PosData *posdata  = StartPosQueueAt(queue, 0);
                float    min_cost = (posdata->cost + ZopfliCostModelGetMinCostCmd(model) +
                                     ZopfliCostModelGetLiteralCosts(model, posdata->pos, pos));
                min_len = ComputeMinimumCopyLength(min_cost, nodes, num_bytes, pos);
            }

            /* Go over the command starting positions in order of increasing cost
             * difference. */
            for (k = 0; k < max_iters && k < StartPosQueueSize(queue); ++k)
            {
                PosData *posdata        = StartPosQueueAt(queue, k);
                size_t   start          = posdata->pos;
                ushort   inscode        = GetInsertLengthCode(pos - start);
                float    start_costdiff = posdata->costdiff;
                float    base_cost      = start_costdiff + (float)GetInsertExtra(inscode) +
                                          ZopfliCostModelGetLiteralCosts(model, 0, pos);

                /* Look for last distance matches using the distance cache from this
                 * starting position. */
                size_t best_len = min_len - 1;
                size_t j        = 0;
                for (; j < BROTLI_NUM_DISTANCE_SHORT_CODES && best_len < max_len; ++j)
                {
                    size_t idx      = kDistanceCacheIndex[j];
                    size_t backward =
                        (size_t)(posdata->distance_cache[idx] + kDistanceCacheOffset[j]);
                    size_t prev_ix = cur_ix - backward;
                    if (prev_ix >= cur_ix)
                    {
                        continue;
                    }
                    if ((backward > max_distance))
                    {
                        continue;
                    }
                    prev_ix &= ringbuffer_mask;

                    if (cur_ix_masked + best_len > ringbuffer_mask ||
                        prev_ix + best_len > ringbuffer_mask ||
                        ringbuffer[cur_ix_masked + best_len] !=
                        ringbuffer[prev_ix + best_len])
                    {
                        continue;
                    }
                    {
                        size_t len =
                            FindMatchLengthWithLimit(&ringbuffer[prev_ix],
                                                     &ringbuffer[cur_ix_masked],
                                                     max_len);
                        float dist_cost = base_cost +
                                          ZopfliCostModelGetDistanceCost(model, j);
                        size_t l;
                        for (l = best_len + 1; l <= len; ++l)
                        {
                            ushort copycode = GetCopyLengthCode(l);
                            ushort cmdcode  =
                                CombineLengthCodes(inscode, copycode, j == 0);
                            float cost = (cmdcode < 128 ? base_cost : dist_cost) +
                                         (float)GetCopyExtra(copycode) +
                                         ZopfliCostModelGetCommandCost(model, cmdcode);
                            if (cost < nodes[pos + l].u.cost)
                            {
                                UpdateZopfliNode(nodes, pos, start, l, l, backward, j + 1, cost);
                                result = Math.Max(result, l);
                            }
                            best_len = l;
                        }
                    }
                }

                /* At higher iterations look only for new last distance matches, since
                 * looking only for new command start positions with the same distances
                 * does not help much. */
                if (k >= 2)
                {
                    continue;
                }

                {
                    /* Loop through all possible copy lengths at this position. */
                    size_t len = min_len;
                    for (j = 0; j < num_matches; ++j)
                    {
                        BackwardMatch match = matches[j];
                        size_t        dist  = match.distance;
                        bool          is_dictionary_match = (dist > max_distance);

                        /* We already tried all possible last distance matches, so we can use
                         * normal distance code here. */
                        size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1;
                        ushort dist_symbol;
                        uint   distextra;
                        uint   distnumextra;
                        float  dist_cost;
                        size_t max_match_len;
                        PrefixEncodeCopyDistance(dist_code, 0, 0, &dist_symbol, &distextra);
                        distnumextra = distextra >> 24;
                        dist_cost    = base_cost + (float)distnumextra +
                                       ZopfliCostModelGetDistanceCost(model, dist_symbol);

                        /* Try all copy lengths up until the maximum copy length corresponding
                         * to this distance. If the distance refers to the private static unsafe dictionary, or
                         * the maximum length is long enough, try only one maximum length. */
                        max_match_len = BackwardMatchLength(&match);
                        if (len < max_match_len &&
                            (is_dictionary_match || max_match_len > max_zopfli_len))
                        {
                            len = max_match_len;
                        }
                        for (; len <= max_match_len; ++len)
                        {
                            size_t len_code =
                                is_dictionary_match ? BackwardMatchLengthCode(&match) : len;
                            ushort copycode = GetCopyLengthCode(len_code);
                            ushort cmdcode  = CombineLengthCodes(inscode, copycode, false);
                            float  cost     = dist_cost + (float)GetCopyExtra(copycode) +
                                              ZopfliCostModelGetCommandCost(model, cmdcode);
                            if (cost < nodes[pos + len].u.cost)
                            {
                                UpdateZopfliNode(nodes, pos, start, len, len_code, dist, 0, cost);
                                result = Math.Max(result, len);
                            }
                        }
                    }
                }
            }
            return(result);
        }
示例#5
0
 private static unsafe PosData *StartPosQueueAt(StartPosQueue *self, size_t k)
 {
     return(&self->q_[(k - self->idx_) & 7]);
 }
示例#6
0
 private static unsafe size_t StartPosQueueSize(StartPosQueue *self)
 {
     return(Math.Min(self->idx_, 8));
 }