Skip to content

Commit d7a879e

Browse files
committed
Span support
closes #19
1 parent e060093 commit d7a879e

File tree

6 files changed

+77
-52
lines changed

6 files changed

+77
-52
lines changed

ZstdNet.Benchmarks/ZstdNet.Benchmarks.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>netcoreapp2.0</TargetFramework>
5+
<TargetFramework>netcoreapp3.1</TargetFramework>
66
</PropertyGroup>
77

88
<ItemGroup>
9-
<PackageReference Include="BenchmarkDotNet" Version="0.10.11" />
9+
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
1010
</ItemGroup>
1111

1212
<ItemGroup>

ZstdNet.Tests/ZstdNet.Tests.csproj

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
</PropertyGroup>
77

88
<ItemGroup>
9-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
10-
<PackageReference Include="NUnit" Version="3.9.0" />
11-
<PackageReference Include="NUnit3TestAdapter" Version="3.9.0" />
9+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
10+
<PackageReference Include="NUnit" Version="3.12.0" />
11+
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
1212
</ItemGroup>
1313

1414
<ItemGroup>

ZstdNet/Compressor.cs

+18-17
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ public Compressor()
1212
public Compressor(CompressionOptions options)
1313
{
1414
Options = options;
15-
1615
cctx = ExternMethods.ZSTD_createCCtx().EnsureZstdSuccess();
1716
}
1817

@@ -35,14 +34,17 @@ private void Dispose(bool disposing)
3534
}
3635

3736
public byte[] Wrap(byte[] src)
38-
=> Wrap(new ArraySegment<byte>(src));
37+
=> Wrap(new ReadOnlySpan<byte>(src));
3938

4039
public byte[] Wrap(ArraySegment<byte> src)
40+
=> Wrap((ReadOnlySpan<byte>)src);
41+
42+
public byte[] Wrap(ReadOnlySpan<byte> src)
4143
{
42-
var dstCapacity = GetCompressBound(src.Count);
44+
var dstCapacity = GetCompressBound(src.Length);
4345
var dst = new byte[dstCapacity];
4446

45-
var dstSize = Wrap(src, dst, 0);
47+
var dstSize = Wrap(src, new Span<byte>(dst));
4648
if(dstCapacity == dstSize)
4749
return dst;
4850

@@ -55,27 +57,26 @@ public static int GetCompressBound(int size)
5557
=> (int)ExternMethods.ZSTD_compressBound((size_t)size);
5658

5759
public int Wrap(byte[] src, byte[] dst, int offset)
58-
=> Wrap(new ArraySegment<byte>(src), dst, offset);
60+
=> Wrap(new ReadOnlySpan<byte>(src), dst, offset);
5961

6062
public int Wrap(ArraySegment<byte> src, byte[] dst, int offset)
63+
=> Wrap((ReadOnlySpan<byte>)src, dst, offset);
64+
65+
public int Wrap(ReadOnlySpan<byte> src, byte[] dst, int offset)
6166
{
6267
if(offset < 0 || offset >= dst.Length)
6368
throw new ArgumentOutOfRangeException(nameof(offset));
6469

65-
var dstCapacity = dst.Length - offset;
70+
return Wrap(src, new Span<byte>(dst, offset, dst.Length - offset));
71+
}
6672

67-
size_t dstSize;
68-
using(var srcPtr = new ArraySegmentPtr(src))
69-
using(var dstPtr = new ArraySegmentPtr(dst, offset, dstCapacity))
70-
{
71-
if(Options.Cdict == IntPtr.Zero)
72-
dstSize = ExternMethods.ZSTD_compressCCtx(cctx, dstPtr, (size_t)dstCapacity, srcPtr, (size_t)src.Count, Options.CompressionLevel);
73-
else
74-
dstSize = ExternMethods.ZSTD_compress_usingCDict(cctx, dstPtr, (size_t)dstCapacity, srcPtr, (size_t)src.Count, Options.Cdict);
75-
}
73+
public int Wrap(ReadOnlySpan<byte> src, Span<byte> dst)
74+
{
75+
var dstSize = Options.Cdict == IntPtr.Zero
76+
? ExternMethods.ZSTD_compressCCtx(cctx, dst, (size_t)dst.Length, src, (size_t)src.Length, Options.CompressionLevel)
77+
: ExternMethods.ZSTD_compress_usingCDict(cctx, dst, (size_t)dst.Length, src, (size_t)src.Length, Options.Cdict);
7678

77-
dstSize.EnsureZstdSuccess();
78-
return (int)dstSize;
79+
return (int)dstSize.EnsureZstdSuccess();
7980
}
8081

8182
public readonly CompressionOptions Options;

ZstdNet/Decompressor.cs

+29-29
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,20 @@ public byte[] Unwrap(byte[] src, int maxDecompressedSize = int.MaxValue)
3737
=> Unwrap(new ArraySegment<byte>(src), maxDecompressedSize);
3838

3939
public byte[] Unwrap(ArraySegment<byte> src, int maxDecompressedSize = int.MaxValue)
40+
=> Unwrap((ReadOnlySpan<byte>)src, maxDecompressedSize);
41+
42+
public byte[] Unwrap(ReadOnlySpan<byte> src, int maxDecompressedSize = int.MaxValue)
4043
{
4144
var expectedDstSize = GetDecompressedSize(src);
4245
if(expectedDstSize > (ulong)maxDecompressedSize)
4346
throw new ArgumentOutOfRangeException($"Decompressed size is too big ({expectedDstSize} bytes > authorized {maxDecompressedSize} bytes)");
47+
4448
var dst = new byte[expectedDstSize];
4549

4650
int dstSize;
4751
try
4852
{
49-
dstSize = Unwrap(src, dst, 0, false);
53+
dstSize = Unwrap(src, new Span<byte>(dst), false);
5054
}
5155
catch(InsufficientMemoryException)
5256
{
@@ -55,21 +59,19 @@ public byte[] Unwrap(ArraySegment<byte> src, int maxDecompressedSize = int.MaxVa
5559

5660
if((int)expectedDstSize != dstSize)
5761
throw new ZstdException("Invalid decompressed size specified in the data");
62+
5863
return dst;
5964
}
6065

6166
public static ulong GetDecompressedSize(byte[] src)
62-
=> GetDecompressedSize(new ArraySegment<byte>(src));
67+
=> GetDecompressedSize(new ReadOnlySpan<byte>(src));
6368

6469
public static ulong GetDecompressedSize(ArraySegment<byte> src)
65-
{
66-
using(var srcPtr = new ArraySegmentPtr(src))
67-
return GetDecompressedSize(srcPtr, src.Count);
68-
}
70+
=> GetDecompressedSize((ReadOnlySpan<byte>)src);
6971

70-
private static ulong GetDecompressedSize(ArraySegmentPtr srcPtr, int count)
72+
public static ulong GetDecompressedSize(ReadOnlySpan<byte> src)
7173
{
72-
var size = ExternMethods.ZSTD_getFrameContentSize(srcPtr, (size_t)count);
74+
var size = ExternMethods.ZSTD_getFrameContentSize(src, (size_t)src.Length);
7375
if(size == ExternMethods.ZSTD_CONTENTSIZE_UNKNOWN)
7476
throw new ZstdException("Decompressed size cannot be determined");
7577
if(size == ExternMethods.ZSTD_CONTENTSIZE_ERROR)
@@ -78,35 +80,33 @@ private static ulong GetDecompressedSize(ArraySegmentPtr srcPtr, int count)
7880
}
7981

8082
public int Unwrap(byte[] src, byte[] dst, int offset, bool bufferSizePrecheck = true)
81-
=> Unwrap(new ArraySegment<byte>(src), dst, offset, bufferSizePrecheck);
83+
=> Unwrap(new ReadOnlySpan<byte>(src), dst, offset, bufferSizePrecheck);
8284

8385
public int Unwrap(ArraySegment<byte> src, byte[] dst, int offset, bool bufferSizePrecheck = true)
86+
=> Unwrap((ReadOnlySpan<byte>)src, dst, offset, bufferSizePrecheck);
87+
88+
public int Unwrap(ReadOnlySpan<byte> src, byte[] dst, int offset, bool bufferSizePrecheck = true)
8489
{
8590
if(offset < 0 || offset > dst.Length)
8691
throw new ArgumentOutOfRangeException(nameof(offset));
8792

88-
var dstCapacity = dst.Length - offset;
89-
using(var srcPtr = new ArraySegmentPtr(src))
93+
return Unwrap(src, new Span<byte>(dst, offset, dst.Length - offset), bufferSizePrecheck);
94+
}
95+
96+
public int Unwrap(ReadOnlySpan<byte> src, Span<byte> dst, bool bufferSizePrecheck = true)
97+
{
98+
if(bufferSizePrecheck)
9099
{
91-
if(bufferSizePrecheck)
92-
{
93-
var expectedDstSize = GetDecompressedSize(srcPtr, src.Count);
94-
if((int)expectedDstSize > dstCapacity)
95-
throw new InsufficientMemoryException("Buffer size is less than specified decompressed data size");
96-
}
97-
98-
size_t dstSize;
99-
using(var dstPtr = new ArraySegmentPtr(new ArraySegment<byte>(dst, offset, dstCapacity)))
100-
{
101-
if(Options.Ddict == IntPtr.Zero)
102-
dstSize = ExternMethods.ZSTD_decompressDCtx(dctx, dstPtr, (size_t) dstCapacity, srcPtr, (size_t) src.Count);
103-
else
104-
dstSize = ExternMethods.ZSTD_decompress_usingDDict(dctx, dstPtr, (size_t) dstCapacity, srcPtr, (size_t) src.Count, Options.Ddict);
105-
}
106-
107-
dstSize.EnsureZstdSuccess();
108-
return (int)dstSize;
100+
var expectedDstSize = GetDecompressedSize(src);
101+
if((int)expectedDstSize > dst.Length)
102+
throw new InsufficientMemoryException("Buffer size is less than specified decompressed data size");
109103
}
104+
105+
var dstSize = Options.Ddict == IntPtr.Zero
106+
? ExternMethods.ZSTD_decompressDCtx(dctx, dst, (size_t)dst.Length, src, (size_t)src.Length)
107+
: ExternMethods.ZSTD_decompress_usingDDict(dctx, dst, (size_t)dst.Length, src, (size_t)src.Length, Options.Ddict);
108+
109+
return (int)dstSize.EnsureZstdSuccess();
110110
}
111111

112112
public readonly DecompressionOptions Options;

ZstdNet/ExternMethods.cs

+20
Original file line numberDiff line numberDiff line change
@@ -60,26 +60,46 @@ private static void SetWinDllDirectory()
6060
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
6161
public static extern size_t ZSTD_compressCCtx(IntPtr ctx, IntPtr dst, size_t dstCapacity, IntPtr src, size_t srcSize, int compressionLevel);
6262
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
63+
public static extern size_t ZSTD_compressCCtx(IntPtr ctx, ref byte dst, size_t dstCapacity, ref byte src, size_t srcSize, int compressionLevel);
64+
public static size_t ZSTD_compressCCtx(IntPtr ctx, Span<byte> dst, size_t dstCapacity, ReadOnlySpan<byte> src, size_t srcSize, int compressionLevel)
65+
=> ZSTD_compressCCtx(ctx, ref MemoryMarshal.GetReference(dst), dstCapacity, ref MemoryMarshal.GetReference(src), srcSize, compressionLevel);
66+
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
6367
public static extern size_t ZSTD_decompressDCtx(IntPtr ctx, IntPtr dst, size_t dstCapacity, IntPtr src, size_t srcSize);
68+
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
69+
public static extern size_t ZSTD_decompressDCtx(IntPtr ctx, ref byte dst, size_t dstCapacity, ref byte src, size_t srcSize);
70+
public static size_t ZSTD_decompressDCtx(IntPtr ctx, Span<byte> dst, size_t dstCapacity, ReadOnlySpan<byte> src, size_t srcSize)
71+
=> ZSTD_decompressDCtx(ctx, ref MemoryMarshal.GetReference(dst), dstCapacity, ref MemoryMarshal.GetReference(src), srcSize);
6472

6573
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
6674
public static extern IntPtr ZSTD_createCDict(byte[] dict, size_t dictSize, int compressionLevel);
6775
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
6876
public static extern size_t ZSTD_freeCDict(IntPtr cdict);
6977
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
7078
public static extern size_t ZSTD_compress_usingCDict(IntPtr cctx, IntPtr dst, size_t dstCapacity, IntPtr src, size_t srcSize, IntPtr cdict);
79+
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
80+
public static extern size_t ZSTD_compress_usingCDict(IntPtr cctx, ref byte dst, size_t dstCapacity, ref byte src, size_t srcSize, IntPtr cdict);
81+
public static size_t ZSTD_compress_usingCDict(IntPtr cctx, Span<byte> dst, size_t dstCapacity, ReadOnlySpan<byte> src, size_t srcSize, IntPtr cdict)
82+
=> ZSTD_compress_usingCDict(cctx, ref MemoryMarshal.GetReference(dst), dstCapacity, ref MemoryMarshal.GetReference(src), srcSize, cdict);
7183

7284
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
7385
public static extern IntPtr ZSTD_createDDict(byte[] dict, size_t dictSize);
7486
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
7587
public static extern size_t ZSTD_freeDDict(IntPtr ddict);
7688
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
7789
public static extern size_t ZSTD_decompress_usingDDict(IntPtr dctx, IntPtr dst, size_t dstCapacity, IntPtr src, size_t srcSize, IntPtr ddict);
90+
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
91+
public static extern size_t ZSTD_decompress_usingDDict(IntPtr dctx, ref byte dst, size_t dstCapacity, ref byte src, size_t srcSize, IntPtr ddict);
92+
public static size_t ZSTD_decompress_usingDDict(IntPtr dctx, Span<byte> dst, size_t dstCapacity, ReadOnlySpan<byte> src, size_t srcSize, IntPtr ddict)
93+
=> ZSTD_decompress_usingDDict(dctx, ref MemoryMarshal.GetReference(dst), dstCapacity, ref MemoryMarshal.GetReference(src), srcSize, ddict);
7894

7995
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
8096
public static extern ulong ZSTD_getDecompressedSize(IntPtr src, size_t srcSize);
8197
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
8298
public static extern ulong ZSTD_getFrameContentSize(IntPtr src, size_t srcSize);
99+
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
100+
public static extern ulong ZSTD_getFrameContentSize(ref byte src, size_t srcSize);
101+
public static ulong ZSTD_getFrameContentSize(ReadOnlySpan<byte> src, size_t srcSize)
102+
=> ZSTD_getFrameContentSize(ref MemoryMarshal.GetReference(src), srcSize);
83103

84104
public const ulong ZSTD_CONTENTSIZE_UNKNOWN = unchecked(0UL - 1);
85105
public const ulong ZSTD_CONTENTSIZE_ERROR = unchecked(0UL - 2);

ZstdNet/ZstdNet.csproj

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<Version>1.3.3</Version>
4-
<TargetFrameworks>net45;netstandard2.0</TargetFrameworks>
4+
<TargetFrameworks>net45;netstandard2.0;netstandard2.1</TargetFrameworks>
55
<Title>ZstdNet</Title>
66
<PackageId>ZstdNet</PackageId>
77
<Company>SKB Kontur</Company>
@@ -11,6 +11,7 @@
1111
<PackageLicenseUrl>https://github.com/skbkontur/ZstdNet/blob/master/LICENSE</PackageLicenseUrl>
1212
<PackageProjectUrl>https://github.com/skbkontur/ZstdNet</PackageProjectUrl>
1313
<PackageTags>zstd zstandard compression</PackageTags>
14+
<LangVersion>7.2</LangVersion>
1415
</PropertyGroup>
1516
<ItemGroup>
1617
<None Include="build\x64\libzstd.dll">
@@ -26,4 +27,7 @@
2627
<None Include="build\**\*" Pack="true" PackagePath="build\" />
2728
<None Include="..\LICENSE" Pack="true" PackagePath="lib\" />
2829
</ItemGroup>
30+
<ItemGroup Condition="'$(TargetFramework)' == 'net45' OR '$(TargetFramework)' == 'netstandard2.0'">
31+
<PackageReference Include="System.Memory" Version="4.*" />
32+
</ItemGroup>
2933
</Project>

0 commit comments

Comments
 (0)