diff --git a/ZstdNet.Benchmarks/ZstdNet.Benchmarks.csproj b/ZstdNet.Benchmarks/ZstdNet.Benchmarks.csproj index 99fb0d4..e7a0a1e 100644 --- a/ZstdNet.Benchmarks/ZstdNet.Benchmarks.csproj +++ b/ZstdNet.Benchmarks/ZstdNet.Benchmarks.csproj @@ -2,11 +2,11 @@ Exe - netcoreapp2.0 + netcoreapp3.1 - + diff --git a/ZstdNet.Tests/ZstdNet.Tests.csproj b/ZstdNet.Tests/ZstdNet.Tests.csproj index 6113542..f4764d3 100644 --- a/ZstdNet.Tests/ZstdNet.Tests.csproj +++ b/ZstdNet.Tests/ZstdNet.Tests.csproj @@ -6,9 +6,9 @@ - - - + + + diff --git a/ZstdNet/Compressor.cs b/ZstdNet/Compressor.cs index f348364..829f0c2 100644 --- a/ZstdNet/Compressor.cs +++ b/ZstdNet/Compressor.cs @@ -12,7 +12,6 @@ public Compressor() public Compressor(CompressionOptions options) { Options = options; - cctx = ExternMethods.ZSTD_createCCtx().EnsureZstdSuccess(); } @@ -35,14 +34,17 @@ private void Dispose(bool disposing) } public byte[] Wrap(byte[] src) - => Wrap(new ArraySegment(src)); + => Wrap(new ReadOnlySpan(src)); public byte[] Wrap(ArraySegment src) + => Wrap((ReadOnlySpan)src); + + public byte[] Wrap(ReadOnlySpan 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(dst)); if(dstCapacity == dstSize) return dst; @@ -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(src), dst, offset); + => Wrap(new ReadOnlySpan(src), dst, offset); public int Wrap(ArraySegment src, byte[] dst, int offset) + => Wrap((ReadOnlySpan)src, dst, offset); + + public int Wrap(ReadOnlySpan 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(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 src, Span 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; diff --git a/ZstdNet/Decompressor.cs b/ZstdNet/Decompressor.cs index 6875d44..b629fc6 100644 --- a/ZstdNet/Decompressor.cs +++ b/ZstdNet/Decompressor.cs @@ -37,16 +37,20 @@ public byte[] Unwrap(byte[] src, int maxDecompressedSize = int.MaxValue) => Unwrap(new ArraySegment(src), maxDecompressedSize); public byte[] Unwrap(ArraySegment src, int maxDecompressedSize = int.MaxValue) + => Unwrap((ReadOnlySpan)src, maxDecompressedSize); + + public byte[] Unwrap(ReadOnlySpan 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(dst), false); } catch(InsufficientMemoryException) { @@ -55,21 +59,19 @@ public byte[] Unwrap(ArraySegment 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(src)); + => GetDecompressedSize(new ReadOnlySpan(src)); public static ulong GetDecompressedSize(ArraySegment src) - { - using(var srcPtr = new ArraySegmentPtr(src)) - return GetDecompressedSize(srcPtr, src.Count); - } + => GetDecompressedSize((ReadOnlySpan)src); - private static ulong GetDecompressedSize(ArraySegmentPtr srcPtr, int count) + public static ulong GetDecompressedSize(ReadOnlySpan 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) @@ -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(src), dst, offset, bufferSizePrecheck); + => Unwrap(new ReadOnlySpan(src), dst, offset, bufferSizePrecheck); public int Unwrap(ArraySegment src, byte[] dst, int offset, bool bufferSizePrecheck = true) + => Unwrap((ReadOnlySpan)src, dst, offset, bufferSizePrecheck); + + public int Unwrap(ReadOnlySpan 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(dst, offset, dst.Length - offset), bufferSizePrecheck); + } + + public int Unwrap(ReadOnlySpan src, Span 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(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; diff --git a/ZstdNet/ExternMethods.cs b/ZstdNet/ExternMethods.cs index 9129b9a..9bf0042 100644 --- a/ZstdNet/ExternMethods.cs +++ b/ZstdNet/ExternMethods.cs @@ -60,7 +60,15 @@ 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 dst, size_t dstCapacity, ReadOnlySpan 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 dst, size_t dstCapacity, ReadOnlySpan 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); @@ -68,6 +76,10 @@ private static void SetWinDllDirectory() 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 dst, size_t dstCapacity, ReadOnlySpan 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); @@ -75,11 +87,19 @@ private static void SetWinDllDirectory() 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 dst, size_t dstCapacity, ReadOnlySpan 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 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); diff --git a/ZstdNet/ZstdNet.csproj b/ZstdNet/ZstdNet.csproj index 54c8f23..6179ada 100644 --- a/ZstdNet/ZstdNet.csproj +++ b/ZstdNet/ZstdNet.csproj @@ -1,7 +1,7 @@  1.3.3 - net45;netstandard2.0 + net45;netstandard2.0;netstandard2.1 ZstdNet ZstdNet SKB Kontur @@ -11,6 +11,7 @@ https://github.com/skbkontur/ZstdNet/blob/master/LICENSE https://github.com/skbkontur/ZstdNet zstd zstandard compression + 7.2 @@ -26,4 +27,7 @@ + + + \ No newline at end of file