From 6e43e64cb2d06669b697bc094f97ff36aa239656 Mon Sep 17 00:00:00 2001 From: Brant Burnett Date: Sun, 12 Feb 2023 08:03:27 -0500 Subject: [PATCH] Allow shorter compression output buffer lengths Motivation ---------- The current implementation requires that the compression output buffer have enough room for the maximum possible compressed block size, which is very unlikely to be required. Modifications ------------- Check the remaining output buffer size before outputting each fragment to the buffer. Add a benchmark for block compression. Results ------- An exception is only thrown if the output buffer is insufficient for the actual compressed size. --- Snappier.Benchmarks/BlockCompressHtml.cs | 33 ++++++++++++++++++++++++ Snappier/Internal/SnappyCompressor.cs | 8 +++--- 2 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 Snappier.Benchmarks/BlockCompressHtml.cs diff --git a/Snappier.Benchmarks/BlockCompressHtml.cs b/Snappier.Benchmarks/BlockCompressHtml.cs new file mode 100644 index 0000000..8749847 --- /dev/null +++ b/Snappier.Benchmarks/BlockCompressHtml.cs @@ -0,0 +1,33 @@ +using System; +using BenchmarkDotNet.Attributes; +using Snappier.Internal; + +namespace Snappier.Benchmarks +{ + public class BlockCompressHtml + { + private ReadOnlyMemory _input; + private Memory _output; + + [GlobalSetup] + public void LoadToMemory() + { + using var resource = + typeof(BlockCompressHtml).Assembly.GetManifestResourceStream("Snappier.Benchmarks.TestData.html"); + + byte[] input = new byte[65536]; // Just test the first 64KB + int inputLength = resource!.Read(input, 0, input.Length); + _input = input.AsMemory(0, inputLength); + + _output = new byte[65536]; + } + + [Benchmark] + public int Compress() + { + using var compressor = new SnappyCompressor(); + + return compressor.Compress(_input.Span, _output.Span); + } + } +} diff --git a/Snappier/Internal/SnappyCompressor.cs b/Snappier/Internal/SnappyCompressor.cs index 7dab9dd..45f5c13 100644 --- a/Snappier/Internal/SnappyCompressor.cs +++ b/Snappier/Internal/SnappyCompressor.cs @@ -11,10 +11,6 @@ internal class SnappyCompressor : IDisposable public int Compress(ReadOnlySpan input, Span output) { - if (output.Length < Helpers.MaxCompressedLength(input.Length)) - { - ThrowHelper.ThrowArgumentException("Insufficient output buffer", nameof(output)); - } if (_workingMemory == null) { ThrowHelper.ThrowObjectDisposedException(nameof(SnappyCompressor)); @@ -46,6 +42,10 @@ public int Compress(ReadOnlySpan input, Span output) try { int written = CompressFragment(fragment, scratch.AsSpan(), hashTable); + if (output.Length < written) + { + ThrowHelper.ThrowArgumentException("Insufficient output buffer", nameof(output)); + } scratch.AsSpan(0, written).CopyTo(output); output = output.Slice(written);