Browse Source

Migrate deflater

pull/1683/head
James Jackson-South 5 years ago
parent
commit
b78582fb75
  1. 2
      src/ImageSharp/Compression/Zlib/Deflater.cs
  2. 41
      src/ImageSharp/Compression/Zlib/DeflaterEngine.cs
  3. 28
      src/ImageSharp/Compression/Zlib/DeflaterHuffman.cs
  4. 27
      src/ImageSharp/Compression/Zlib/DeflaterOutputStream.cs
  5. 31
      src/ImageSharp/Compression/Zlib/DeflaterPendingBuffer.cs

2
src/ImageSharp/Compression/Zlib/Deflater.cs

@ -222,7 +222,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
/// The number of compressed bytes added to the output, or 0 if either /// The number of compressed bytes added to the output, or 0 if either
/// <see cref="IsNeedingInput"/> or <see cref="IsFinished"/> returns true or length is zero. /// <see cref="IsNeedingInput"/> or <see cref="IsFinished"/> returns true or length is zero.
/// </returns> /// </returns>
public int Deflate(byte[] output, int offset, int length) public int Deflate(Span<byte> output, int offset, int length)
{ {
int origLength = length; int origLength = length;

41
src/ImageSharp/Compression/Zlib/DeflaterEngine.cs

@ -130,9 +130,9 @@ namespace SixLabors.ImageSharp.Compression.Zlib
/// This array contains the part of the uncompressed stream that /// This array contains the part of the uncompressed stream that
/// is of relevance. The current character is indexed by strstart. /// is of relevance. The current character is indexed by strstart.
/// </summary> /// </summary>
private IManagedByteBuffer windowMemoryOwner; private IMemoryOwner<byte> windowMemoryOwner;
private MemoryHandle windowMemoryHandle; private MemoryHandle windowMemoryHandle;
private readonly byte[] window; private readonly Memory<byte> window;
private readonly byte* pinnedWindowPointer; private readonly byte* pinnedWindowPointer;
private int maxChain; private int maxChain;
@ -153,19 +153,19 @@ namespace SixLabors.ImageSharp.Compression.Zlib
// Create pinned pointers to the various buffers to allow indexing // Create pinned pointers to the various buffers to allow indexing
// without bounds checks. // without bounds checks.
this.windowMemoryOwner = memoryAllocator.AllocateManagedByteBuffer(2 * DeflaterConstants.WSIZE); this.windowMemoryOwner = memoryAllocator.Allocate<byte>(2 * DeflaterConstants.WSIZE);
this.window = this.windowMemoryOwner.Array; this.window = this.windowMemoryOwner.Memory;
this.windowMemoryHandle = this.windowMemoryOwner.Memory.Pin(); this.windowMemoryHandle = this.window.Pin();
this.pinnedWindowPointer = (byte*)this.windowMemoryHandle.Pointer; this.pinnedWindowPointer = (byte*)this.windowMemoryHandle.Pointer;
this.headMemoryOwner = memoryAllocator.Allocate<short>(DeflaterConstants.HASH_SIZE); this.headMemoryOwner = memoryAllocator.Allocate<short>(DeflaterConstants.HASH_SIZE);
this.head = this.headMemoryOwner.Memory; this.head = this.headMemoryOwner.Memory;
this.headMemoryHandle = this.headMemoryOwner.Memory.Pin(); this.headMemoryHandle = this.head.Pin();
this.pinnedHeadPointer = (short*)this.headMemoryHandle.Pointer; this.pinnedHeadPointer = (short*)this.headMemoryHandle.Pointer;
this.prevMemoryOwner = memoryAllocator.Allocate<short>(DeflaterConstants.WSIZE); this.prevMemoryOwner = memoryAllocator.Allocate<short>(DeflaterConstants.WSIZE);
this.prev = this.prevMemoryOwner.Memory; this.prev = this.prevMemoryOwner.Memory;
this.prevMemoryHandle = this.prevMemoryOwner.Memory.Pin(); this.prevMemoryHandle = this.prev.Pin();
this.pinnedPrevPointer = (short*)this.prevMemoryHandle.Pointer; this.pinnedPrevPointer = (short*)this.prevMemoryHandle.Pointer;
// We start at index 1, to avoid an implementation deficiency, that // We start at index 1, to avoid an implementation deficiency, that
@ -303,7 +303,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
case DeflaterConstants.DEFLATE_STORED: case DeflaterConstants.DEFLATE_STORED:
if (this.strstart > this.blockStart) if (this.strstart > this.blockStart)
{ {
this.huffman.FlushStoredBlock(this.window, this.blockStart, this.strstart - this.blockStart, false); this.huffman.FlushStoredBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, false);
this.blockStart = this.strstart; this.blockStart = this.strstart;
} }
@ -313,7 +313,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
case DeflaterConstants.DEFLATE_FAST: case DeflaterConstants.DEFLATE_FAST:
if (this.strstart > this.blockStart) if (this.strstart > this.blockStart)
{ {
this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, false); this.huffman.FlushBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, false);
this.blockStart = this.strstart; this.blockStart = this.strstart;
} }
@ -327,7 +327,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
if (this.strstart > this.blockStart) if (this.strstart > this.blockStart)
{ {
this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, false); this.huffman.FlushBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, false);
this.blockStart = this.strstart; this.blockStart = this.strstart;
} }
@ -362,7 +362,10 @@ namespace SixLabors.ImageSharp.Compression.Zlib
more = this.inputEnd - this.inputOff; more = this.inputEnd - this.inputOff;
} }
Buffer.BlockCopy(this.inputBuf, this.inputOff, this.window, this.strstart + this.lookahead, more); Unsafe.CopyBlockUnaligned(
ref this.window.Span[this.strstart + this.lookahead],
ref this.inputBuf[this.inputOff],
unchecked((uint)more));
this.inputOff += more; this.inputOff += more;
this.lookahead += more; this.lookahead += more;
@ -426,7 +429,11 @@ namespace SixLabors.ImageSharp.Compression.Zlib
private void SlideWindow() private void SlideWindow()
{ {
Unsafe.CopyBlockUnaligned(ref this.window[0], ref this.window[DeflaterConstants.WSIZE], DeflaterConstants.WSIZE); Unsafe.CopyBlockUnaligned(
ref this.window.Span[0],
ref this.window.Span[DeflaterConstants.WSIZE],
DeflaterConstants.WSIZE);
this.matchStart -= DeflaterConstants.WSIZE; this.matchStart -= DeflaterConstants.WSIZE;
this.strstart -= DeflaterConstants.WSIZE; this.strstart -= DeflaterConstants.WSIZE;
this.blockStart -= DeflaterConstants.WSIZE; this.blockStart -= DeflaterConstants.WSIZE;
@ -663,7 +670,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
lastBlock = false; lastBlock = false;
} }
this.huffman.FlushStoredBlock(this.window, this.blockStart, storedLength, lastBlock); this.huffman.FlushStoredBlock(this.window.Span, this.blockStart, storedLength, lastBlock);
this.blockStart += storedLength; this.blockStart += storedLength;
return !(lastBlock || storedLength == 0); return !(lastBlock || storedLength == 0);
} }
@ -683,7 +690,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
if (this.lookahead == 0) if (this.lookahead == 0)
{ {
// We are flushing everything // We are flushing everything
this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, finish); this.huffman.FlushBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, finish);
this.blockStart = this.strstart; this.blockStart = this.strstart;
return false; return false;
} }
@ -743,7 +750,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
if (this.huffman.IsFull()) if (this.huffman.IsFull())
{ {
bool lastBlock = finish && (this.lookahead == 0); bool lastBlock = finish && (this.lookahead == 0);
this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, lastBlock); this.huffman.FlushBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, lastBlock);
this.blockStart = this.strstart; this.blockStart = this.strstart;
return !lastBlock; return !lastBlock;
} }
@ -771,7 +778,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
this.prevAvailable = false; this.prevAvailable = false;
// We are flushing everything // We are flushing everything
this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, finish); this.huffman.FlushBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, finish);
this.blockStart = this.strstart; this.blockStart = this.strstart;
return false; return false;
} }
@ -846,7 +853,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
} }
bool lastBlock = finish && (this.lookahead == 0) && !this.prevAvailable; bool lastBlock = finish && (this.lookahead == 0) && !this.prevAvailable;
this.huffman.FlushBlock(this.window, this.blockStart, len, lastBlock); this.huffman.FlushBlock(this.window.Span, this.blockStart, len, lastBlock);
this.blockStart += len; this.blockStart += len;
return !lastBlock; return !lastBlock;
} }

28
src/ImageSharp/Compression/Zlib/DeflaterHuffman.cs

@ -41,11 +41,11 @@ namespace SixLabors.ImageSharp.Compression.Zlib
private Tree blTree; private Tree blTree;
// Buffer for distances // Buffer for distances
private readonly IMemoryOwner<short> distanceManagedBuffer; private readonly IMemoryOwner<short> distanceMemoryOwner;
private readonly short* pinnedDistanceBuffer; private readonly short* pinnedDistanceBuffer;
private MemoryHandle distanceBufferHandle; private MemoryHandle distanceBufferHandle;
private readonly IMemoryOwner<short> literalManagedBuffer; private readonly IMemoryOwner<short> literalMemoryOwner;
private readonly short* pinnedLiteralBuffer; private readonly short* pinnedLiteralBuffer;
private MemoryHandle literalBufferHandle; private MemoryHandle literalBufferHandle;
@ -65,12 +65,12 @@ namespace SixLabors.ImageSharp.Compression.Zlib
this.distTree = new Tree(memoryAllocator, DistanceNumber, 1, 15); this.distTree = new Tree(memoryAllocator, DistanceNumber, 1, 15);
this.blTree = new Tree(memoryAllocator, BitLengthNumber, 4, 7); this.blTree = new Tree(memoryAllocator, BitLengthNumber, 4, 7);
this.distanceManagedBuffer = memoryAllocator.Allocate<short>(BufferSize); this.distanceMemoryOwner = memoryAllocator.Allocate<short>(BufferSize);
this.distanceBufferHandle = this.distanceManagedBuffer.Memory.Pin(); this.distanceBufferHandle = this.distanceMemoryOwner.Memory.Pin();
this.pinnedDistanceBuffer = (short*)this.distanceBufferHandle.Pointer; this.pinnedDistanceBuffer = (short*)this.distanceBufferHandle.Pointer;
this.literalManagedBuffer = memoryAllocator.Allocate<short>(BufferSize); this.literalMemoryOwner = memoryAllocator.Allocate<short>(BufferSize);
this.literalBufferHandle = this.literalManagedBuffer.Memory.Pin(); this.literalBufferHandle = this.literalMemoryOwner.Memory.Pin();
this.pinnedLiteralBuffer = (short*)this.literalBufferHandle.Pointer; this.pinnedLiteralBuffer = (short*)this.literalBufferHandle.Pointer;
} }
@ -239,7 +239,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
/// <param name="storedLength">Count of bytes to write</param> /// <param name="storedLength">Count of bytes to write</param>
/// <param name="lastBlock">True if this is the last block</param> /// <param name="lastBlock">True if this is the last block</param>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock) public void FlushStoredBlock(ReadOnlySpan<byte> stored, int storedOffset, int storedLength, bool lastBlock)
{ {
this.Pending.WriteBits((DeflaterConstants.STORED_BLOCK << 1) + (lastBlock ? 1 : 0), 3); this.Pending.WriteBits((DeflaterConstants.STORED_BLOCK << 1) + (lastBlock ? 1 : 0), 3);
this.Pending.AlignToByte(); this.Pending.AlignToByte();
@ -256,7 +256,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
/// <param name="storedOffset">Index of first byte to flush</param> /// <param name="storedOffset">Index of first byte to flush</param>
/// <param name="storedLength">Count of bytes to flush</param> /// <param name="storedLength">Count of bytes to flush</param>
/// <param name="lastBlock">True if this is the last block</param> /// <param name="lastBlock">True if this is the last block</param>
public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock) public void FlushBlock(ReadOnlySpan<byte> stored, int storedOffset, int storedLength, bool lastBlock)
{ {
this.literalTree.Frequencies[EofSymbol]++; this.literalTree.Frequencies[EofSymbol]++;
@ -286,13 +286,13 @@ namespace SixLabors.ImageSharp.Compression.Zlib
+ this.extraBits; + this.extraBits;
int static_len = this.extraBits; int static_len = this.extraBits;
ref byte staticLLengthRef = ref MemoryMarshal.GetReference<byte>(StaticLLength); ref byte staticLLengthRef = ref MemoryMarshal.GetReference(StaticLLength);
for (int i = 0; i < LiteralNumber; i++) for (int i = 0; i < LiteralNumber; i++)
{ {
static_len += this.literalTree.Frequencies[i] * Unsafe.Add(ref staticLLengthRef, i); static_len += this.literalTree.Frequencies[i] * Unsafe.Add(ref staticLLengthRef, i);
} }
ref byte staticDLengthRef = ref MemoryMarshal.GetReference<byte>(StaticDLength); ref byte staticDLengthRef = ref MemoryMarshal.GetReference(StaticDLength);
for (int i = 0; i < DistanceNumber; i++) for (int i = 0; i < DistanceNumber; i++)
{ {
static_len += this.distTree.Frequencies[i] * Unsafe.Add(ref staticDLengthRef, i); static_len += this.distTree.Frequencies[i] * Unsafe.Add(ref staticDLengthRef, i);
@ -419,9 +419,9 @@ namespace SixLabors.ImageSharp.Compression.Zlib
{ {
this.Pending.Dispose(); this.Pending.Dispose();
this.distanceBufferHandle.Dispose(); this.distanceBufferHandle.Dispose();
this.distanceManagedBuffer.Dispose(); this.distanceMemoryOwner.Dispose();
this.literalBufferHandle.Dispose(); this.literalBufferHandle.Dispose();
this.literalManagedBuffer.Dispose(); this.literalMemoryOwner.Dispose();
this.literalTree.Dispose(); this.literalTree.Dispose();
this.blTree.Dispose(); this.blTree.Dispose();
@ -484,7 +484,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
private IMemoryOwner<short> frequenciesMemoryOwner; private IMemoryOwner<short> frequenciesMemoryOwner;
private MemoryHandle frequenciesMemoryHandle; private MemoryHandle frequenciesMemoryHandle;
private IManagedByteBuffer lengthsMemoryOwner; private IMemoryOwner<byte> lengthsMemoryOwner;
private MemoryHandle lengthsMemoryHandle; private MemoryHandle lengthsMemoryHandle;
public Tree(MemoryAllocator memoryAllocator, int elements, int minCodes, int maxLength) public Tree(MemoryAllocator memoryAllocator, int elements, int minCodes, int maxLength)
@ -498,7 +498,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
this.frequenciesMemoryHandle = this.frequenciesMemoryOwner.Memory.Pin(); this.frequenciesMemoryHandle = this.frequenciesMemoryOwner.Memory.Pin();
this.Frequencies = (short*)this.frequenciesMemoryHandle.Pointer; this.Frequencies = (short*)this.frequenciesMemoryHandle.Pointer;
this.lengthsMemoryOwner = memoryAllocator.AllocateManagedByteBuffer(elements); this.lengthsMemoryOwner = memoryAllocator.Allocate<byte>(elements);
this.lengthsMemoryHandle = this.lengthsMemoryOwner.Memory.Pin(); this.lengthsMemoryHandle = this.lengthsMemoryOwner.Memory.Pin();
this.Length = (byte*)this.lengthsMemoryHandle.Pointer; this.Length = (byte*)this.lengthsMemoryHandle.Pointer;

27
src/ImageSharp/Compression/Zlib/DeflaterOutputStream.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers;
using System.IO; using System.IO;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
@ -14,8 +15,8 @@ namespace SixLabors.ImageSharp.Compression.Zlib
internal sealed class DeflaterOutputStream : Stream internal sealed class DeflaterOutputStream : Stream
{ {
private const int BufferLength = 512; private const int BufferLength = 512;
private IManagedByteBuffer memoryOwner; private IMemoryOwner<byte> memoryOwner;
private readonly byte[] buffer; private readonly Memory<byte> buffer;
private Deflater deflater; private Deflater deflater;
private readonly Stream rawStream; private readonly Stream rawStream;
private bool isDisposed; private bool isDisposed;
@ -29,8 +30,8 @@ namespace SixLabors.ImageSharp.Compression.Zlib
public DeflaterOutputStream(MemoryAllocator memoryAllocator, Stream rawStream, int compressionLevel) public DeflaterOutputStream(MemoryAllocator memoryAllocator, Stream rawStream, int compressionLevel)
{ {
this.rawStream = rawStream; this.rawStream = rawStream;
this.memoryOwner = memoryAllocator.AllocateManagedByteBuffer(BufferLength); this.memoryOwner = memoryAllocator.Allocate<byte>(BufferLength);
this.buffer = this.memoryOwner.Array; this.buffer = this.memoryOwner.Memory;
this.deflater = new Deflater(memoryAllocator, compressionLevel); this.deflater = new Deflater(memoryAllocator, compressionLevel);
} }
@ -49,15 +50,9 @@ namespace SixLabors.ImageSharp.Compression.Zlib
/// <inheritdoc/> /// <inheritdoc/>
public override long Position public override long Position
{ {
get get => this.rawStream.Position;
{
return this.rawStream.Position;
}
set set => throw new NotSupportedException();
{
throw new NotSupportedException();
}
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -93,14 +88,14 @@ namespace SixLabors.ImageSharp.Compression.Zlib
{ {
while (flushing || !this.deflater.IsNeedingInput) while (flushing || !this.deflater.IsNeedingInput)
{ {
int deflateCount = this.deflater.Deflate(this.buffer, 0, BufferLength); int deflateCount = this.deflater.Deflate(this.buffer.Span, 0, BufferLength);
if (deflateCount <= 0) if (deflateCount <= 0)
{ {
break; break;
} }
this.rawStream.Write(this.buffer, 0, deflateCount); this.rawStream.Write(this.buffer.Span.Slice(0, deflateCount));
} }
if (!this.deflater.IsNeedingInput) if (!this.deflater.IsNeedingInput)
@ -114,13 +109,13 @@ namespace SixLabors.ImageSharp.Compression.Zlib
this.deflater.Finish(); this.deflater.Finish();
while (!this.deflater.IsFinished) while (!this.deflater.IsFinished)
{ {
int len = this.deflater.Deflate(this.buffer, 0, BufferLength); int len = this.deflater.Deflate(this.buffer.Span, 0, BufferLength);
if (len <= 0) if (len <= 0)
{ {
break; break;
} }
this.rawStream.Write(this.buffer, 0, len); this.rawStream.Write(this.buffer.Span.Slice(0, len));
} }
if (!this.deflater.IsFinished) if (!this.deflater.IsFinished)

31
src/ImageSharp/Compression/Zlib/DeflaterPendingBuffer.cs

@ -4,6 +4,7 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Compression.Zlib namespace SixLabors.ImageSharp.Compression.Zlib
@ -13,9 +14,9 @@ namespace SixLabors.ImageSharp.Compression.Zlib
/// </summary> /// </summary>
internal sealed unsafe class DeflaterPendingBuffer : IDisposable internal sealed unsafe class DeflaterPendingBuffer : IDisposable
{ {
private readonly byte[] buffer; private readonly Memory<byte> buffer;
private readonly byte* pinnedBuffer; private readonly byte* pinnedBuffer;
private IManagedByteBuffer bufferMemoryOwner; private IMemoryOwner<byte> bufferMemoryOwner;
private MemoryHandle bufferMemoryHandle; private MemoryHandle bufferMemoryHandle;
private int start; private int start;
@ -29,9 +30,9 @@ namespace SixLabors.ImageSharp.Compression.Zlib
/// <param name="memoryAllocator">The memory allocator to use for buffer allocations.</param> /// <param name="memoryAllocator">The memory allocator to use for buffer allocations.</param>
public DeflaterPendingBuffer(MemoryAllocator memoryAllocator) public DeflaterPendingBuffer(MemoryAllocator memoryAllocator)
{ {
this.bufferMemoryOwner = memoryAllocator.AllocateManagedByteBuffer(DeflaterConstants.PENDING_BUF_SIZE); this.bufferMemoryOwner = memoryAllocator.Allocate<byte>(DeflaterConstants.PENDING_BUF_SIZE);
this.buffer = this.bufferMemoryOwner.Array; this.buffer = this.bufferMemoryOwner.Memory;
this.bufferMemoryHandle = this.bufferMemoryOwner.Memory.Pin(); this.bufferMemoryHandle = this.buffer.Pin();
this.pinnedBuffer = (byte*)this.bufferMemoryHandle.Pointer; this.pinnedBuffer = (byte*)this.bufferMemoryHandle.Pointer;
} }
@ -70,9 +71,13 @@ namespace SixLabors.ImageSharp.Compression.Zlib
/// <param name="offset">The offset of first byte to write.</param> /// <param name="offset">The offset of first byte to write.</param>
/// <param name="length">The number of bytes to write.</param> /// <param name="length">The number of bytes to write.</param>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void WriteBlock(byte[] block, int offset, int length) public void WriteBlock(ReadOnlySpan<byte> block, int offset, int length)
{ {
Unsafe.CopyBlockUnaligned(ref this.buffer[this.end], ref block[offset], unchecked((uint)length)); Unsafe.CopyBlockUnaligned(
ref this.buffer.Span[this.end],
ref MemoryMarshal.GetReference(block.Slice(offset)),
unchecked((uint)length));
this.end += length; this.end += length;
} }
@ -136,7 +141,7 @@ namespace SixLabors.ImageSharp.Compression.Zlib
/// <param name="offset">The offset into output array.</param> /// <param name="offset">The offset into output array.</param>
/// <param name="length">The maximum number of bytes to store.</param> /// <param name="length">The maximum number of bytes to store.</param>
/// <returns>The number of bytes flushed.</returns> /// <returns>The number of bytes flushed.</returns>
public int Flush(byte[] output, int offset, int length) public int Flush(Span<byte> output, int offset, int length)
{ {
if (this.BitCount >= 8) if (this.BitCount >= 8)
{ {
@ -149,13 +154,19 @@ namespace SixLabors.ImageSharp.Compression.Zlib
{ {
length = this.end - this.start; length = this.end - this.start;
Unsafe.CopyBlockUnaligned(ref output[offset], ref this.buffer[this.start], unchecked((uint)length)); Unsafe.CopyBlockUnaligned(
ref output[offset],
ref this.buffer.Span[this.start],
unchecked((uint)length));
this.start = 0; this.start = 0;
this.end = 0; this.end = 0;
} }
else else
{ {
Unsafe.CopyBlockUnaligned(ref output[offset], ref this.buffer[this.start], unchecked((uint)length)); Unsafe.CopyBlockUnaligned(
ref output[offset],
ref this.buffer.Span[this.start],
unchecked((uint)length));
this.start += length; this.start += length;
} }

Loading…
Cancel
Save