protected override (MetaBlock, BrotliGlobalState) Transform(MetaBlock.Compressed original, BrotliGlobalState state, BrotliCompressionParameters parameters) { var builder = new CompressedMetaBlockBuilder(original, state) { LiteralCtxMap = ContextMapBuilder.Literals.Simple, DistanceCtxMap = ContextMapBuilder.Distances.Simple }; foreach (var category in Categories.LID) { builder.BlockTypes[category].Reset(); } builder.UseSameLiteralContextMode(LiteralContextMode.UTF8); var tracker = new MetaBlockSizeTracker(state); tracker.Test(builder, parameters); foreach (var category in Categories.LID) { TestBlockSplits(builder, parameters, tracker, category); } tracker.Test(original); return(tracker.Smallest ?? throw new InvalidOperationException("Transformation did not generate any meta-blocks.")); }
protected override (MetaBlock, BrotliGlobalState) Transform(MetaBlock.Compressed original, BrotliGlobalState state, BrotliCompressionParameters parameters) { var builder = new CompressedMetaBlockBuilder(original, state); var tracker = new MetaBlockSizeTracker(state); tracker.Test(builder, parameters); var blocker = new Blocker(parameters.DistanceCodePicker); parameters = new BrotliCompressionParameters.Builder(parameters) { DistanceCodePicker = blocker.Pick }.Build(); foreach (var code in DistanceCode.Last.Codes.Except(new DistanceCode[] { DistanceCode.Zero })) { var prev = tracker.SmallestSize; blocker.BlockedCodes.Add(code); tracker.Test(builder, parameters); if (tracker.SmallestSize < prev) { Debug.WriteLine("Blocking code " + code + " reduced size (" + prev + " > " + tracker.SmallestSize + "), keeping it..."); } else { Debug.WriteLine("Blocking code " + code + " did not improve the size, continuing..."); blocker.BlockedCodes.Remove(code); } } Debug.WriteLine("Final blocked codes: " + string.Join(", ", blocker.BlockedCodes)); return(tracker.Smallest ?? throw new InvalidOperationException("Transformation did not generate any meta-blocks.")); }
protected override (MetaBlock, BrotliGlobalState) Transform(MetaBlock.Compressed original, BrotliGlobalState state, BrotliCompressionParameters parameters) { var builder = new CompressedMetaBlockBuilder(original, state); var tracker = new MetaBlockSizeTracker(state); for (byte postfixBitCount = 0; postfixBitCount <= DistanceParameters.MaxPostfixBitCount; postfixBitCount++) { for (byte directCodeBits = 0; directCodeBits <= DistanceParameters.MaxDirectCodeBits; directCodeBits++) { builder.DistanceParameters = new DistanceParameters(postfixBitCount, directCodeBits); tracker.Test(builder, parameters, debugText: "[PostfixBitCount = " + postfixBitCount + ", DirectCodeBits = " + directCodeBits + "]"); } } return(tracker.Smallest ?? throw new InvalidOperationException("Transformation did not generate any meta-blocks.")); }
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); } } }