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); } } }