protected override (MetaBlock, BrotliGlobalState) Transform(MetaBlock.Compressed original, BrotliGlobalState state, BrotliCompressionParameters parameters)
        {
            if (original.Data.InsertCopyCommands.Count <= 1 || original.Data.BlockSwitchCommands[Category.InsertCopy].Count > 0)
            {
                return(original, state);
            }

            var builder    = new CompressedMetaBlockBuilder(original, state);
            var icBlocks   = builder.BlockTypes[Category.InsertCopy];
            var icCommands = builder.GetTotalBlockLength(Category.InsertCopy);

            icBlocks.SetInitialLength(icCommands / 2)
            .AddFinalBlock(1);

            return(builder.Build(parameters));
        }
        protected override (MetaBlock, BrotliGlobalState) Transform(MetaBlock.Compressed original, BrotliGlobalState state, BrotliCompressionParameters parameters)
        {
            var builder = new CompressedMetaBlockBuilder(original, state);

            var literals      = new List <Literal>(builder.GetTotalBlockLength(Category.Literal));
            var lengthCodes   = new List <InsertCopyLengthCode>(builder.GetTotalBlockLength(Category.InsertCopy));
            var distanceCodes = new List <DistanceCode>(builder.GetTotalBlockLength(Category.Distance));

            var distanceFreq       = new FrequencyList <DistanceCode>();
            var validDistanceCodes = new List <DistanceCode>(5);

            foreach (var command in original.Data.InsertCopyCommands)
            {
                literals.AddRange(command.Literals);
                state.OutputLiterals(command.Literals);

                if (command.CopyDistance == DistanceInfo.EndsAfterLiterals)
                {
                    lengthCodes.Add(command.Lengths.MakeCode(ImplicitDistanceCodeZero.PreferEnabled));
                    break;
                }

                if (!command.CopyDistance.FindCodes(original.Header.DistanceParameters, state, validDistanceCodes))
                {
                    lengthCodes.Add(command.Lengths.MakeCode(ImplicitDistanceCodeZero.ForceEnabled));
                }
                else
                {
                    DistanceCode distanceCode;

                    if (command.CopyDistance == DistanceInfo.ExplicitCodeZero)
                    {
                        distanceCode = DistanceCode.Zero;
                    }
                    else
                    {
                        distanceCode = validDistanceCodes.Count > 1 ? parameters.DistanceCodePicker(validDistanceCodes, distanceFreq) : validDistanceCodes[0];
                    }

                    distanceFreq.Add(distanceCode);
                    distanceCodes.Add(distanceCode);
                    lengthCodes.Add(command.Lengths.MakeCode(ImplicitDistanceCodeZero.Disable));
                }
            }

            var origLitCtxMap = builder.LiteralCtxMap;

            if (origLitCtxMap.TreeCount == 1)
            {
                Split(builder, Category.Literal, literals, 512, 400.0);

                builder.UseSameLiteralContextMode(LiteralContextMode.UTF8);
                builder.LiteralCtxMap = new ContextMapBuilder.Literals(builder).RepeatFirstBlockType(true).Build();
            }
            else
            {
                var literalContextMap  = Enumerable.Range(0, origLitCtxMap.ContextsPerBlockType).Select(index => origLitCtxMap.DetermineTreeID(0, index)).ToArray();
                var literalContextMode = builder.LiteralContextModes[0];

                var literalBuffer = RingBufferFast <byte> .From(0, 0);

                Split(builder, Category.Literal, literals, 512, 400.0, new BlockSplitter <Literal> .ContextInfo(literalContextMap, literal => {
                    literalBuffer.Push(literal.Value);
                    return(literalContextMode.DetermineContextID(literalBuffer.Front, literalBuffer.Back));
                }));

                builder.UseSameLiteralContextMode(literalContextMode);
                builder.LiteralCtxMap = new ContextMapBuilder.Literals(builder).Set(0, literalContextMap).RepeatFirstBlockType(true).Build();
            }

            Split(builder, Category.InsertCopy, lengthCodes, 1024, 500.0);
            Split(builder, Category.Distance, distanceCodes, 512, 100.0);

            builder.DistanceCtxMap = new ContextMapBuilder.Distances(builder).RepeatFirstBlockType(true).Build();

            return(builder.Build(parameters));
        }
        private void TestBlockSplits(CompressedMetaBlockBuilder builder, BrotliCompressionParameters parameters, MetaBlockSizeTracker tracker, Category category)
        {
            int totalBlockLength = builder.GetTotalBlockLength(category);

            if (totalBlockLength == 0)
            {
                return;
            }

            int step      = Math.Max(1, (int)Math.Floor(Math.Log(totalBlockLength, 1.15)));
            int stepTwice = step * 2;

            if (totalBlockLength < stepTwice)
            {
                return;
            }

            var lengths = new List <int> {
                totalBlockLength
            };
            var queue = new Queue <int>();

            queue.Enqueue(0);

            while (queue.TryDequeue(out int leftIndex))
            {
                if (lengths[leftIndex] < stepTwice)
                {
                    continue;
                }

                int rightIndex = leftIndex + 1;

                lengths.Insert(rightIndex, lengths[leftIndex] - step);
                lengths[leftIndex] = step;

                ApplyBlockSplit(builder.BlockTypes[category], lengths);
                PrepareContextMap(builder, category, lengths.Count);
                tracker.Test(builder, parameters);

                while (lengths[leftIndex] + step < lengths[rightIndex] && lengths[rightIndex] >= stepTwice)
                {
                    lengths[leftIndex]  += step;
                    lengths[rightIndex] -= step;

                    ApplyBlockSplit(builder.BlockTypes[category], lengths);
                    PrepareContextMap(builder, category, lengths.Count);
                    tracker.Test(builder, parameters);
                }

                var smallest = tracker.Smallest;

                if (smallest == null)
                {
                    return;
                }

                var mb   = smallest.Value.Item1;
                int prev = lengths.Count;

                lengths.Clear();
                lengths.Add(mb.Header.BlockTypes[category].InitialLength);
                lengths.AddRange(mb.Data.BlockSwitchCommands[category].Select(command => command.Length));

                var finalLength = totalBlockLength - lengths.Sum();

                if (finalLength > 0)
                {
                    lengths.Add(totalBlockLength - lengths.Sum());
                }

                if (lengths.Count >= prev)
                {
                    queue.Enqueue(leftIndex);
                    queue.Enqueue(rightIndex);
                }
            }
        }