Skip to content

Commit

Permalink
Span support
Browse files Browse the repository at this point in the history
closes #19
  • Loading branch information
dscheg committed Sep 20, 2020
1 parent e060093 commit d7a879e
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 52 deletions.
4 changes: 2 additions & 2 deletions ZstdNet.Benchmarks/ZstdNet.Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.10.11" />
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
</ItemGroup>

<ItemGroup>
Expand Down
6 changes: 3 additions & 3 deletions ZstdNet.Tests/ZstdNet.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="NUnit" Version="3.9.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.9.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
</ItemGroup>

<ItemGroup>
Expand Down
35 changes: 18 additions & 17 deletions ZstdNet/Compressor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ public Compressor()
public Compressor(CompressionOptions options)
{
Options = options;

cctx = ExternMethods.ZSTD_createCCtx().EnsureZstdSuccess();
}

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

public byte[] Wrap(byte[] src)
=> Wrap(new ArraySegment<byte>(src));
=> Wrap(new ReadOnlySpan<byte>(src));

public byte[] Wrap(ArraySegment<byte> src)
=> Wrap((ReadOnlySpan<byte>)src);

public byte[] Wrap(ReadOnlySpan<byte> src)
{
var dstCapacity = GetCompressBound(src.Count);
var dstCapacity = GetCompressBound(src.Length);
var dst = new byte[dstCapacity];

var dstSize = Wrap(src, dst, 0);
var dstSize = Wrap(src, new Span<byte>(dst));
if(dstCapacity == dstSize)
return dst;

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

public int Wrap(byte[] src, byte[] dst, int offset)
=> Wrap(new ArraySegment<byte>(src), dst, offset);
=> Wrap(new ReadOnlySpan<byte>(src), dst, offset);

public int Wrap(ArraySegment<byte> src, byte[] dst, int offset)
=> Wrap((ReadOnlySpan<byte>)src, dst, offset);

public int Wrap(ReadOnlySpan<byte> src, byte[] dst, int offset)
{
if(offset < 0 || offset >= dst.Length)
throw new ArgumentOutOfRangeException(nameof(offset));

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

size_t dstSize;
using(var srcPtr = new ArraySegmentPtr(src))
using(var dstPtr = new ArraySegmentPtr(dst, offset, dstCapacity))
{
if(Options.Cdict == IntPtr.Zero)
dstSize = ExternMethods.ZSTD_compressCCtx(cctx, dstPtr, (size_t)dstCapacity, srcPtr, (size_t)src.Count, Options.CompressionLevel);
else
dstSize = ExternMethods.ZSTD_compress_usingCDict(cctx, dstPtr, (size_t)dstCapacity, srcPtr, (size_t)src.Count, Options.Cdict);
}
public int Wrap(ReadOnlySpan<byte> src, Span<byte> dst)
{
var dstSize = Options.Cdict == IntPtr.Zero
? ExternMethods.ZSTD_compressCCtx(cctx, dst, (size_t)dst.Length, src, (size_t)src.Length, Options.CompressionLevel)
: ExternMethods.ZSTD_compress_usingCDict(cctx, dst, (size_t)dst.Length, src, (size_t)src.Length, Options.Cdict);

dstSize.EnsureZstdSuccess();
return (int)dstSize;
return (int)dstSize.EnsureZstdSuccess();
}

public readonly CompressionOptions Options;
Expand Down
58 changes: 29 additions & 29 deletions ZstdNet/Decompressor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,20 @@ public byte[] Unwrap(byte[] src, int maxDecompressedSize = int.MaxValue)
=> Unwrap(new ArraySegment<byte>(src), maxDecompressedSize);

public byte[] Unwrap(ArraySegment<byte> src, int maxDecompressedSize = int.MaxValue)
=> Unwrap((ReadOnlySpan<byte>)src, maxDecompressedSize);

public byte[] Unwrap(ReadOnlySpan<byte> src, int maxDecompressedSize = int.MaxValue)
{
var expectedDstSize = GetDecompressedSize(src);
if(expectedDstSize > (ulong)maxDecompressedSize)
throw new ArgumentOutOfRangeException($"Decompressed size is too big ({expectedDstSize} bytes > authorized {maxDecompressedSize} bytes)");

var dst = new byte[expectedDstSize];

int dstSize;
try
{
dstSize = Unwrap(src, dst, 0, false);
dstSize = Unwrap(src, new Span<byte>(dst), false);
}
catch(InsufficientMemoryException)
{
Expand All @@ -55,21 +59,19 @@ public byte[] Unwrap(ArraySegment<byte> src, int maxDecompressedSize = int.MaxVa

if((int)expectedDstSize != dstSize)
throw new ZstdException("Invalid decompressed size specified in the data");

return dst;
}

public static ulong GetDecompressedSize(byte[] src)
=> GetDecompressedSize(new ArraySegment<byte>(src));
=> GetDecompressedSize(new ReadOnlySpan<byte>(src));

public static ulong GetDecompressedSize(ArraySegment<byte> src)
{
using(var srcPtr = new ArraySegmentPtr(src))
return GetDecompressedSize(srcPtr, src.Count);
}
=> GetDecompressedSize((ReadOnlySpan<byte>)src);

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

public int Unwrap(byte[] src, byte[] dst, int offset, bool bufferSizePrecheck = true)
=> Unwrap(new ArraySegment<byte>(src), dst, offset, bufferSizePrecheck);
=> Unwrap(new ReadOnlySpan<byte>(src), dst, offset, bufferSizePrecheck);

public int Unwrap(ArraySegment<byte> src, byte[] dst, int offset, bool bufferSizePrecheck = true)
=> Unwrap((ReadOnlySpan<byte>)src, dst, offset, bufferSizePrecheck);

public int Unwrap(ReadOnlySpan<byte> src, byte[] dst, int offset, bool bufferSizePrecheck = true)
{
if(offset < 0 || offset > dst.Length)
throw new ArgumentOutOfRangeException(nameof(offset));

var dstCapacity = dst.Length - offset;
using(var srcPtr = new ArraySegmentPtr(src))
return Unwrap(src, new Span<byte>(dst, offset, dst.Length - offset), bufferSizePrecheck);
}

public int Unwrap(ReadOnlySpan<byte> src, Span<byte> dst, bool bufferSizePrecheck = true)
{
if(bufferSizePrecheck)
{
if(bufferSizePrecheck)
{
var expectedDstSize = GetDecompressedSize(srcPtr, src.Count);
if((int)expectedDstSize > dstCapacity)
throw new InsufficientMemoryException("Buffer size is less than specified decompressed data size");
}

size_t dstSize;
using(var dstPtr = new ArraySegmentPtr(new ArraySegment<byte>(dst, offset, dstCapacity)))
{
if(Options.Ddict == IntPtr.Zero)
dstSize = ExternMethods.ZSTD_decompressDCtx(dctx, dstPtr, (size_t) dstCapacity, srcPtr, (size_t) src.Count);
else
dstSize = ExternMethods.ZSTD_decompress_usingDDict(dctx, dstPtr, (size_t) dstCapacity, srcPtr, (size_t) src.Count, Options.Ddict);
}

dstSize.EnsureZstdSuccess();
return (int)dstSize;
var expectedDstSize = GetDecompressedSize(src);
if((int)expectedDstSize > dst.Length)
throw new InsufficientMemoryException("Buffer size is less than specified decompressed data size");
}

var dstSize = Options.Ddict == IntPtr.Zero
? ExternMethods.ZSTD_decompressDCtx(dctx, dst, (size_t)dst.Length, src, (size_t)src.Length)
: ExternMethods.ZSTD_decompress_usingDDict(dctx, dst, (size_t)dst.Length, src, (size_t)src.Length, Options.Ddict);

return (int)dstSize.EnsureZstdSuccess();
}

public readonly DecompressionOptions Options;
Expand Down
20 changes: 20 additions & 0 deletions ZstdNet/ExternMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,26 +60,46 @@ private static void SetWinDllDirectory()
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern size_t ZSTD_compressCCtx(IntPtr ctx, IntPtr dst, size_t dstCapacity, IntPtr src, size_t srcSize, int compressionLevel);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern size_t ZSTD_compressCCtx(IntPtr ctx, ref byte dst, size_t dstCapacity, ref byte src, size_t srcSize, int compressionLevel);
public static size_t ZSTD_compressCCtx(IntPtr ctx, Span<byte> dst, size_t dstCapacity, ReadOnlySpan<byte> src, size_t srcSize, int compressionLevel)
=> ZSTD_compressCCtx(ctx, ref MemoryMarshal.GetReference(dst), dstCapacity, ref MemoryMarshal.GetReference(src), srcSize, compressionLevel);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern size_t ZSTD_decompressDCtx(IntPtr ctx, IntPtr dst, size_t dstCapacity, IntPtr src, size_t srcSize);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern size_t ZSTD_decompressDCtx(IntPtr ctx, ref byte dst, size_t dstCapacity, ref byte src, size_t srcSize);
public static size_t ZSTD_decompressDCtx(IntPtr ctx, Span<byte> dst, size_t dstCapacity, ReadOnlySpan<byte> src, size_t srcSize)
=> ZSTD_decompressDCtx(ctx, ref MemoryMarshal.GetReference(dst), dstCapacity, ref MemoryMarshal.GetReference(src), srcSize);

[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr ZSTD_createCDict(byte[] dict, size_t dictSize, int compressionLevel);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern size_t ZSTD_freeCDict(IntPtr cdict);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern size_t ZSTD_compress_usingCDict(IntPtr cctx, IntPtr dst, size_t dstCapacity, IntPtr src, size_t srcSize, IntPtr cdict);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern size_t ZSTD_compress_usingCDict(IntPtr cctx, ref byte dst, size_t dstCapacity, ref byte src, size_t srcSize, IntPtr cdict);
public static size_t ZSTD_compress_usingCDict(IntPtr cctx, Span<byte> dst, size_t dstCapacity, ReadOnlySpan<byte> src, size_t srcSize, IntPtr cdict)
=> ZSTD_compress_usingCDict(cctx, ref MemoryMarshal.GetReference(dst), dstCapacity, ref MemoryMarshal.GetReference(src), srcSize, cdict);

[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr ZSTD_createDDict(byte[] dict, size_t dictSize);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern size_t ZSTD_freeDDict(IntPtr ddict);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern size_t ZSTD_decompress_usingDDict(IntPtr dctx, IntPtr dst, size_t dstCapacity, IntPtr src, size_t srcSize, IntPtr ddict);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern size_t ZSTD_decompress_usingDDict(IntPtr dctx, ref byte dst, size_t dstCapacity, ref byte src, size_t srcSize, IntPtr ddict);
public static size_t ZSTD_decompress_usingDDict(IntPtr dctx, Span<byte> dst, size_t dstCapacity, ReadOnlySpan<byte> src, size_t srcSize, IntPtr ddict)
=> ZSTD_decompress_usingDDict(dctx, ref MemoryMarshal.GetReference(dst), dstCapacity, ref MemoryMarshal.GetReference(src), srcSize, ddict);

[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern ulong ZSTD_getDecompressedSize(IntPtr src, size_t srcSize);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern ulong ZSTD_getFrameContentSize(IntPtr src, size_t srcSize);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern ulong ZSTD_getFrameContentSize(ref byte src, size_t srcSize);
public static ulong ZSTD_getFrameContentSize(ReadOnlySpan<byte> src, size_t srcSize)
=> ZSTD_getFrameContentSize(ref MemoryMarshal.GetReference(src), srcSize);

public const ulong ZSTD_CONTENTSIZE_UNKNOWN = unchecked(0UL - 1);
public const ulong ZSTD_CONTENTSIZE_ERROR = unchecked(0UL - 2);
Expand Down
6 changes: 5 additions & 1 deletion ZstdNet/ZstdNet.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Version>1.3.3</Version>
<TargetFrameworks>net45;netstandard2.0</TargetFrameworks>
<TargetFrameworks>net45;netstandard2.0;netstandard2.1</TargetFrameworks>
<Title>ZstdNet</Title>
<PackageId>ZstdNet</PackageId>
<Company>SKB Kontur</Company>
Expand All @@ -11,6 +11,7 @@
<PackageLicenseUrl>https://github.com/skbkontur/ZstdNet/blob/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/skbkontur/ZstdNet</PackageProjectUrl>
<PackageTags>zstd zstandard compression</PackageTags>
<LangVersion>7.2</LangVersion>
</PropertyGroup>
<ItemGroup>
<None Include="build\x64\libzstd.dll">
Expand All @@ -26,4 +27,7 @@
<None Include="build\**\*" Pack="true" PackagePath="build\" />
<None Include="..\LICENSE" Pack="true" PackagePath="lib\" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net45' OR '$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="System.Memory" Version="4.*" />
</ItemGroup>
</Project>

0 comments on commit d7a879e

Please sign in to comment.