Don't allocate arrays when copying streams (#1510)

- Use the array pool
- Use Span to copy native memory
- Fixes #1509
This commit is contained in:
Matthew Leibowitz 2020-09-26 19:06:36 +02:00 коммит произвёл GitHub
Родитель 2019706296
Коммит 61b71d6e48
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 52 добавлений и 20 удалений

Просмотреть файл

@ -1,8 +1,5 @@
using System;
using System.Buffers;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace SkiaSharp
{
@ -90,18 +87,25 @@ namespace SkiaSharp
private IntPtr OnReadManagedStream (IntPtr buffer, IntPtr size)
{
byte[] managedBuffer;
using (var reader = new BinaryReader (stream, Encoding.UTF8, true)) {
managedBuffer = reader.ReadBytes ((int)size);
}
var result = managedBuffer.Length;
if (buffer != IntPtr.Zero) {
Marshal.Copy (managedBuffer, 0, buffer, result);
}
if (!stream.CanSeek && (int)size > 0 && result <= (int)size) {
if (buffer == IntPtr.Zero)
throw new ArgumentNullException (nameof (buffer));
if ((int)size < 0)
throw new ArgumentOutOfRangeException (nameof (size));
if (size == IntPtr.Zero)
return IntPtr.Zero;
using var managedBuffer = Utils.RentArray<byte> ((int)size);
var len = stream.Read (managedBuffer.Array, 0, managedBuffer.Length);
var src = managedBuffer.Span.Slice (0, len);
var dst = buffer.AsSpan (managedBuffer.Length);
src.CopyTo (dst);
if (!stream.CanSeek && (int)size > 0 && len <= (int)size)
isAsEnd = true;
}
return (IntPtr)result;
return (IntPtr)len;
}
protected override IntPtr OnRead (IntPtr buffer, IntPtr size)

Двоичный файл не отображается.

Просмотреть файл

@ -17,7 +17,7 @@
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PackageCertificateKeyFile>..\..\..\AppStoreCertificates\SkiaSharpSample_TemporaryKey.pfx</PackageCertificateKeyFile>
<PackageCertificateThumbprint>D3578B78019FED6AEE572B23C1723D44951E0BF9</PackageCertificateThumbprint>
<PackageCertificateThumbprint>5FC604ABEDFB78C8B4E57214FEB937949F44ABE4</PackageCertificateThumbprint>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

Просмотреть файл

@ -17,7 +17,7 @@
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PackageCertificateKeyFile>..\..\..\AppStoreCertificates\SkiaSharpSample_TemporaryKey.pfx</PackageCertificateKeyFile>
<PackageCertificateThumbprint>D3578B78019FED6AEE572B23C1723D44951E0BF9</PackageCertificateThumbprint>
<PackageCertificateThumbprint>5FC604ABEDFB78C8B4E57214FEB937949F44ABE4</PackageCertificateThumbprint>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

Просмотреть файл

@ -17,7 +17,7 @@
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PackageCertificateKeyFile>..\..\..\AppStoreCertificates\SkiaSharpSample_TemporaryKey.pfx</PackageCertificateKeyFile>
<PackageCertificateThumbprint>D3578B78019FED6AEE572B23C1723D44951E0BF9</PackageCertificateThumbprint>
<PackageCertificateThumbprint>5FC604ABEDFB78C8B4E57214FEB937949F44ABE4</PackageCertificateThumbprint>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

Просмотреть файл

@ -17,7 +17,7 @@
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PackageCertificateKeyFile>..\..\..\AppStoreCertificates\SkiaSharpSample_TemporaryKey.pfx</PackageCertificateKeyFile>
<PackageCertificateThumbprint>D3578B78019FED6AEE572B23C1723D44951E0BF9</PackageCertificateThumbprint>
<PackageCertificateThumbprint>5FC604ABEDFB78C8B4E57214FEB937949F44ABE4</PackageCertificateThumbprint>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

Просмотреть файл

@ -17,7 +17,7 @@
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PackageCertificateKeyFile>..\..\..\AppStoreCertificates\SkiaSharpSample_TemporaryKey.pfx</PackageCertificateKeyFile>
<PackageCertificateThumbprint>D3578B78019FED6AEE572B23C1723D44951E0BF9</PackageCertificateThumbprint>
<PackageCertificateThumbprint>5FC604ABEDFB78C8B4E57214FEB937949F44ABE4</PackageCertificateThumbprint>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

Просмотреть файл

@ -17,7 +17,7 @@
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PackageCertificateKeyFile>..\..\..\AppStoreCertificates\SkiaSharpSample_TemporaryKey.pfx</PackageCertificateKeyFile>
<PackageCertificateThumbprint>D3578B78019FED6AEE572B23C1723D44951E0BF9</PackageCertificateThumbprint>
<PackageCertificateThumbprint>5FC604ABEDFB78C8B4E57214FEB937949F44ABE4</PackageCertificateThumbprint>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

Просмотреть файл

@ -124,6 +124,34 @@ namespace SkiaSharp.Tests
}
}
[SkippableTheory]
[InlineData(1024, 0, 0, 0)]
[InlineData(1024, 1, 1, 1)]
[InlineData(1024, 10, 10, 10)]
[InlineData(1024, 100, 100, 100)]
[InlineData(1024, 1000, 1000, 1000)]
[InlineData(1024, 10000, 1024, 1024)]
public void ReadIsCorrect(int dataSize, int readSize, int finalPos, int expectedReadSize)
{
var data = new byte[dataSize];
for (var i = 0; i < data.Length; i++)
{
data[i] = (byte)(i % byte.MaxValue);
}
var stream = new MemoryStream(data);
var managedStream = new SKManagedStream(stream);
var buffer = new byte[dataSize * 2];
var actualReadSize = managedStream.Read(buffer, readSize);
Assert.Equal(expectedReadSize, actualReadSize);
Assert.Equal(finalPos, managedStream.Position);
Assert.Equal(data.Take(readSize), buffer.Take(actualReadSize));
Assert.All(buffer.Skip(actualReadSize), i => Assert.Equal(0, i));
}
[SkippableFact]
public void ManagedStreamReadsChunkCorrectly()
{