Skip to content
23 changes: 15 additions & 8 deletions PolyShim/Net50/Convert.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// ReSharper disable PartialTypeWithSinglePart

using System;
using System.Buffers;
using System.Diagnostics.CodeAnalysis;

[ExcludeFromCodeCoverage]
Expand Down Expand Up @@ -48,17 +49,23 @@ static int GetHexValue(char c)
// https://learn.microsoft.com/dotnet/api/system.convert.tohexstring#system-convert-tohexstring(system-byte()-system-int32-system-int32)
public static string ToHexString(byte[] value, int startIndex, int length)
{
var c = new char[length * 2];
var chars = ArrayPool<char>.Shared.Rent(length * 2);
try
{
for (var i = 0; i < length; i++)
{
var b = value[startIndex + i] >> 4;
chars[i * 2] = (char)(55 + b + (((b - 10) >> 31) & -7));
b = value[startIndex + i] & 0xF;
chars[i * 2 + 1] = (char)(55 + b + (((b - 10) >> 31) & -7));
}

for (var i = 0; i < length; i++)
return new string(chars, 0, length * 2);
}
finally
{
var b = value[startIndex + i] >> 4;
c[i * 2] = (char)(55 + b + (((b - 10) >> 31) & -7));
b = value[startIndex + i] & 0xF;
c[i * 2 + 1] = (char)(55 + b + (((b - 10) >> 31) & -7));
ArrayPool<char>.Shared.Return(chars);
}

return new string(c);
}

// https://learn.microsoft.com/dotnet/api/system.convert.tohexstring#system-convert-tohexstring(system-byte())
Expand Down
30 changes: 19 additions & 11 deletions PolyShim/Net70/TextReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// ReSharper disable PartialTypeWithSinglePart

using System;
using System.Buffers;
using System.IO;
using System.Text;
using System.Threading;
Expand All @@ -30,21 +31,28 @@ internal static class MemberPolyfills_Net70_TextReader
public async Task<string> ReadToEndAsync(CancellationToken cancellationToken)
{
var result = new StringBuilder();
var buffer = new char[4096];

while (true)
var buffer = ArrayPool<char>.Shared.Rent(4096);
try
{
var charsRead = await reader
.ReadAsync(buffer, cancellationToken)
.ConfigureAwait(false);
while (true)
{
var charsRead = await reader
.ReadAsync(buffer, 0, buffer.Length)
.ConfigureAwait(false);

if (charsRead <= 0)
break;
if (charsRead <= 0)
break;

result.Append(buffer, 0, charsRead);
}
cancellationToken.ThrowIfCancellationRequested();
result.Append(buffer, 0, charsRead);
}

return result.ToString();
return result.ToString();
}
finally
{
ArrayPool<char>.Shared.Return(buffer);
}
}
#endif
}
Expand Down
19 changes: 15 additions & 4 deletions PolyShim/Net80/RandomNumberGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// ReSharper disable PartialTypeWithSinglePart

using System;
using System.Buffers;
using System.Text;
using System.Diagnostics.CodeAnalysis;
using System.Security.Cryptography;
Expand Down Expand Up @@ -46,11 +47,21 @@ public static void Shuffle<T>(Span<T> items)
// https://learn.microsoft.com/dotnet/api/system.security.cryptography.randomnumbergenerator.gethexstring#system-security-cryptography-randomnumbergenerator-gethexstring(system-int32-system-boolean)
public static string GetHexString(int stringLength, bool lowercase = false)
{
var bytes = new byte[(stringLength + 1) / 2];
RandomNumberGenerator.Fill(bytes);
var byteCount = (stringLength + 1) / 2;
var bytes = ArrayPool<byte>.Shared.Rent(byteCount);
try
{
RandomNumberGenerator.Fill(bytes.AsSpan(0, byteCount));

var hex = lowercase ? Convert.ToHexStringLower(bytes) : Convert.ToHexString(bytes);
return hex.Substring(0, stringLength);
var hex = lowercase
? Convert.ToHexStringLower(bytes, 0, byteCount)
: Convert.ToHexString(bytes, 0, byteCount);
return hex.Substring(0, stringLength);
}
finally
{
ArrayPool<byte>.Shared.Return(bytes, clearArray: true);
}
}

// https://learn.microsoft.com/dotnet/api/system.security.cryptography.randomnumbergenerator.getstring
Expand Down
20 changes: 14 additions & 6 deletions PolyShim/NetCore10/Stream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// ReSharper disable InconsistentNaming
// ReSharper disable PartialTypeWithSinglePart

using System.Buffers;
using System.IO;
using System.Diagnostics.CodeAnalysis;

Expand All @@ -16,14 +17,21 @@ internal static class MemberPolyfills_NetCore10_Stream
// https://learn.microsoft.com/dotnet/api/system.io.stream.copyto#system-io-stream-copyto(system-io-stream-system-int32)
public void CopyTo(Stream destination, int bufferSize)
{
var buffer = new byte[bufferSize];
while (true)
var buffer = ArrayPool<byte>.Shared.Rent(bufferSize);
try
{
var bytesRead = source.Read(buffer, 0, buffer.Length);
if (bytesRead <= 0)
break;
while (true)
{
var bytesRead = source.Read(buffer, 0, buffer.Length);
if (bytesRead <= 0)
break;

destination.Write(buffer, 0, bytesRead);
destination.Write(buffer, 0, bytesRead);
}
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}
}

Expand Down
51 changes: 33 additions & 18 deletions PolyShim/NetCore20/File.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// ReSharper disable InconsistentNaming
// ReSharper disable PartialTypeWithSinglePart

using System.Buffers;
using System.Collections.Generic;
using System.IO;
using System.Text;
Expand Down Expand Up @@ -130,43 +131,57 @@ public static async Task<string[]> ReadAllLinesAsync(string path, Encoding encod
// https://learn.microsoft.com/dotnet/api/system.io.file.readalltextasync#system-io-file-readalltextasync(system-string-system-threading-cancellationtoken)
public static async Task<string> ReadAllTextAsync(string path, CancellationToken cancellationToken = default)
{
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true);
const int bufferSize = 4096;
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize, true);
using var reader = new StreamReader(stream);

var content = new StringBuilder();
var buffer = new char[4096];
var buffer = ArrayPool<char>.Shared.Rent(bufferSize);
try
{
cancellationToken.ThrowIfCancellationRequested();

cancellationToken.ThrowIfCancellationRequested();
int charsRead;
while ((charsRead = await reader.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0)
{
cancellationToken.ThrowIfCancellationRequested();
content.Append(buffer, 0, charsRead);
}

int charsRead;
while ((charsRead = await reader.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0)
return content.ToString();
}
finally
{
cancellationToken.ThrowIfCancellationRequested();
content.Append(buffer, 0, charsRead);
ArrayPool<char>.Shared.Return(buffer);
}

return content.ToString();
}

// https://learn.microsoft.com/dotnet/api/system.io.file.readalltextasync#system-io-file-readalltextasync(system-string-system-text-encoding-system-threading-cancellationtoken)
public static async Task<string> ReadAllTextAsync(string path, Encoding encoding, CancellationToken cancellationToken = default)
{
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true);
const int bufferSize = 4096;
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize, true);
using var reader = new StreamReader(stream, encoding);

var content = new StringBuilder();
var buffer = new char[4096];
var buffer = ArrayPool<char>.Shared.Rent(bufferSize);
try
{
cancellationToken.ThrowIfCancellationRequested();

cancellationToken.ThrowIfCancellationRequested();
int charsRead;
while ((charsRead = await reader.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0)
{
cancellationToken.ThrowIfCancellationRequested();
content.Append(buffer, 0, charsRead);
}

int charsRead;
while ((charsRead = await reader.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0)
return content.ToString();
}
finally
{
cancellationToken.ThrowIfCancellationRequested();
content.Append(buffer, 0, charsRead);
ArrayPool<char>.Shared.Return(buffer);
}

return content.ToString();
}

// https://learn.microsoft.com/dotnet/api/system.io.file.writeallbytesasync#system-io-file-writeallbytesasync(system-string-system-byte()-system-threading-cancellationtoken)
Expand Down
Loading