Skip to content

Commit 1faef6c

Browse files
committed
Add Reset() function
1 parent 2391fd3 commit 1faef6c

File tree

6 files changed

+145
-3
lines changed

6 files changed

+145
-3
lines changed

src/libraries/System.IO.Compression.ZStandard/ref/System.IO.Compression.ZStandard.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public ZstandardCompressionOptions(int quality) { }
1313
public ZstandardCompressionOptions(System.IO.Compression.CompressionLevel level) { }
1414
public ZstandardCompressionOptions(System.IO.Compression.ZstandardDictionary dictionary) { }
1515
public static int DefaultQuality { get { throw null; } }
16+
public static int DefaultWindow { get { throw null; } }
1617
public System.IO.Compression.ZstandardDictionary? Dictionary { get { throw null; } }
1718
public static int MaxQuality { get { throw null; } }
1819
public static int MinQuality { get { throw null; } }
@@ -23,9 +24,10 @@ public partial struct ZstandardDecoder : System.IDisposable
2324
private object _dummy;
2425
private int _dummyPrimitive;
2526
public ZstandardDecoder(System.IO.Compression.ZstandardDictionary dictionary) { throw null; }
26-
public readonly System.Buffers.OperationStatus Decompress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesConsumed, out int bytesWritten) { throw null; }
27+
public System.Buffers.OperationStatus Decompress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesConsumed, out int bytesWritten) { throw null; }
2728
public void Dispose() { }
2829
public static int GetMaxDecompressedLength(System.ReadOnlySpan<byte> data) { throw null; }
30+
public void Reset() { }
2931
public static bool TryDecompress(System.ReadOnlySpan<byte> source, System.IO.Compression.ZstandardDictionary dictionary, System.Span<byte> destination, out int bytesWritten) { throw null; }
3032
public static bool TryDecompress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten) { throw null; }
3133
}
@@ -42,10 +44,11 @@ public partial struct ZstandardEncoder : System.IDisposable
4244
private int _dummyPrimitive;
4345
public ZstandardEncoder(int quality, int window) { throw null; }
4446
public ZstandardEncoder(System.IO.Compression.ZstandardDictionary dictionary, int window) { throw null; }
45-
public readonly System.Buffers.OperationStatus Compress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesConsumed, out int bytesWritten, bool isFinalBlock) { throw null; }
47+
public System.Buffers.OperationStatus Compress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesConsumed, out int bytesWritten, bool isFinalBlock) { throw null; }
4648
public void Dispose() { }
47-
public readonly System.Buffers.OperationStatus Flush(System.Span<byte> destination, out int bytesWritten) { throw null; }
49+
public System.Buffers.OperationStatus Flush(System.Span<byte> destination, out int bytesWritten) { throw null; }
4850
public static int GetMaxCompressedLength(int inputSize) { throw null; }
51+
public void Reset() { }
4952
public static bool TryCompress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten) { throw null; }
5053
public static bool TryCompress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten, int quality, int window) { throw null; }
5154
public static bool TryCompress(System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten, System.IO.Compression.ZstandardDictionary dictionary, int window) { throw null; }

src/libraries/System.IO.Compression.ZStandard/src/System/IO/Compression/ZstandardCompressionOptions.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ public sealed class ZstandardCompressionOptions
1515
/// <summary>The maximum compression quality level.</summary>
1616
public static int MaxQuality => ZstandardUtils.Quality_Max;
1717

18+
/// <summary>The default window size to use for Zstandard compression.</summary>
19+
public static int DefaultWindow => ZstandardUtils.WindowBits_Default;
20+
1821
/// <summary>Initializes a new instance of the <see cref="ZstandardCompressionOptions"/> class.</summary>
1922
public ZstandardCompressionOptions()
2023
{

src/libraries/System.IO.Compression.ZStandard/src/System/IO/Compression/ZstandardDecoder.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,25 @@ public static bool TryDecompress(ReadOnlySpan<byte> source, ZstandardDictionary
207207
}
208208
}
209209

210+
/// <summary>Resets the decoder session, allowing reuse for the next decompression operation.</summary>
211+
/// <exception cref="ObjectDisposedException">The decoder has been disposed.</exception>
212+
/// <exception cref="IOException">Failed to reset the decoder session.</exception>
213+
public void Reset()
214+
{
215+
EnsureNotDisposed();
216+
217+
if (_context is null)
218+
return;
219+
220+
nuint result = Interop.Zstd.ZSTD_DCtx_reset(_context, Interop.Zstd.ZstdResetDirective.ZSTD_reset_session_only);
221+
if (Interop.Zstd.ZSTD_isError(result) != 0)
222+
{
223+
throw new IOException(string.Format(SR.ZstandardDecoder_DecompressError, ZstandardUtils.GetErrorMessage(result)));
224+
}
225+
226+
_finished = false;
227+
}
228+
210229
/// <summary>Releases all resources used by the <see cref="ZstandardDecoder"/>.</summary>
211230
public void Dispose()
212231
{

src/libraries/System.IO.Compression.ZStandard/src/System/IO/Compression/ZstandardEncoder.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,23 @@ public static bool TryCompress(ReadOnlySpan<byte> source, Span<byte> destination
251251
return encoder.Compress(source, destination, out _, out bytesWritten, isFinalBlock: true) == OperationStatus.Done;
252252
}
253253

254+
/// <summary>Resets the encoder session, allowing reuse for the next compression operation.</summary>
255+
/// <exception cref="ObjectDisposedException">The encoder has been disposed.</exception>
256+
/// <exception cref="IOException">Failed to reset the encoder session.</exception>
257+
public void Reset()
258+
{
259+
EnsureNotDisposed();
260+
261+
if (_context is null)
262+
return;
263+
264+
nuint result = Interop.Zstd.ZSTD_CCtx_reset(_context, Interop.Zstd.ZstdResetDirective.ZSTD_reset_session_only);
265+
if (ZstandardUtils.IsError(result))
266+
{
267+
throw new IOException(string.Format(SR.ZstandardEncoder_CompressError, ZstandardUtils.GetErrorMessage(result)));
268+
}
269+
}
270+
254271
/// <summary>Releases all resources used by the <see cref="ZstandardEncoder"/>.</summary>
255272
public void Dispose()
256273
{

src/libraries/System.IO.Compression.ZStandard/tests/ZStandardDecoderTests.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,56 @@ public void Dispose_CanBeCalledMultipleTimes()
2626
decoder.Dispose();
2727
}
2828

29+
[Fact]
30+
public void Reset_AfterDispose_ThrowsObjectDisposedException()
31+
{
32+
var decoder = new ZstandardDecoder();
33+
decoder.Dispose();
34+
35+
Assert.Throws<ObjectDisposedException>(() => decoder.Reset());
36+
}
37+
38+
[Theory]
39+
[InlineData(true)]
40+
[InlineData(false)]
41+
public void Reset_AllowsReuseForMultipleDecompressions(bool useDictionary)
42+
{
43+
byte[] dictionaryData = CreateSampleDictionary();
44+
using ZstandardDictionary dictionary = ZstandardDictionary.Create(dictionaryData);
45+
46+
// First compress some data to have something to decompress
47+
byte[] input = CreateTestData();
48+
byte[] compressed = new byte[ZstandardEncoder.GetMaxCompressedLength(input.Length)];
49+
bool compressResult = useDictionary
50+
? ZstandardEncoder.TryCompress(input, compressed, out int compressedLength, dictionary, ZstandardCompressionOptions.DefaultWindow)
51+
: ZstandardEncoder.TryCompress(input, compressed, out compressedLength);
52+
Assert.True(compressResult);
53+
54+
// Resize compressed to actual length
55+
Array.Resize(ref compressed, compressedLength);
56+
57+
using var decoder = useDictionary
58+
? new ZstandardDecoder(dictionary)
59+
: new ZstandardDecoder();
60+
byte[] output1 = new byte[input.Length];
61+
byte[] output2 = new byte[input.Length];
62+
63+
// First decompression
64+
OperationStatus result1 = decoder.Decompress(compressed, output1, out int consumed1, out int written1);
65+
Assert.Equal(OperationStatus.Done, result1);
66+
Assert.Equal(compressed.Length, consumed1);
67+
Assert.Equal(input.Length, written1);
68+
Assert.Equal(input, output1);
69+
70+
// Reset and decompress again
71+
decoder.Reset();
72+
OperationStatus result2 = decoder.Decompress(compressed, output2, out int consumed2, out int written2);
73+
Assert.Equal(OperationStatus.Done, result2);
74+
Assert.Equal(compressed.Length, consumed2);
75+
Assert.Equal(input.Length, written2);
76+
Assert.Equal(input, output2);
77+
}
78+
2979
[Fact]
3080
public void GetMaxDecompressedLength_WithEmptyData_ReturnsZero()
3181
{
@@ -192,5 +242,16 @@ public void RoundTrip_SuccessfullyCompressesAndDecompresses(int quality, bool us
192242
}
193243

194244
private static byte[] CreateSampleDictionary() => ZstandardTestUtils.CreateSampleDictionary();
245+
246+
private static byte[] CreateTestData()
247+
{
248+
// Create some test data that compresses well
249+
byte[] data = new byte[1000];
250+
for (int i = 0; i < data.Length; i++)
251+
{
252+
data[i] = (byte)(i % 10); // Repeating pattern
253+
}
254+
return data;
255+
}
195256
}
196257
}

src/libraries/System.IO.Compression.ZStandard/tests/ZStandardEncoderTests.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,45 @@ public void Dispose_CanBeCalledMultipleTimes()
204204
encoder.Dispose();
205205
}
206206

207+
[Fact]
208+
public void Reset_AfterDispose_ThrowsObjectDisposedException()
209+
{
210+
var encoder = new ZstandardEncoder(ValidQuality, ValidWindow);
211+
encoder.Dispose();
212+
213+
Assert.Throws<ObjectDisposedException>(() => encoder.Reset());
214+
}
215+
216+
[Theory]
217+
[InlineData(true)]
218+
[InlineData(false)]
219+
public void Reset_AllowsReuseForMultipleCompressions(bool useDictionary)
220+
{
221+
using ZstandardDictionary dictionary = ZstandardDictionary.Create(ZstandardTestUtils.CreateSampleDictionary(), ValidQuality);
222+
using var encoder = useDictionary
223+
? new ZstandardEncoder(dictionary, ValidWindow)
224+
: new ZstandardEncoder(ValidQuality, ValidWindow);
225+
226+
byte[] input = CreateTestData();
227+
byte[] output1 = new byte[ZstandardEncoder.GetMaxCompressedLength(input.Length)];
228+
byte[] output2 = new byte[ZstandardEncoder.GetMaxCompressedLength(input.Length)];
229+
230+
// First compression
231+
OperationStatus result1 = encoder.Compress(input, output1, out int consumed1, out int written1, isFinalBlock: true);
232+
Assert.Equal(OperationStatus.Done, result1);
233+
Assert.Equal(input.Length, consumed1);
234+
Assert.True(written1 > 0);
235+
236+
// Reset and compress again
237+
encoder.Reset();
238+
OperationStatus result2 = encoder.Compress(input, output2, out int consumed2, out int written2, isFinalBlock: true);
239+
Assert.Equal(OperationStatus.Done, result2);
240+
Assert.Equal(input.Length, consumed2);
241+
Assert.True(written2 > 0);
242+
243+
Assert.Equal(output1, output2);
244+
}
245+
207246
private static byte[] CreateTestData()
208247
{
209248
// Create some test data that compresses well

0 commit comments

Comments
 (0)