Skip to content
This repository has been archived by the owner on Aug 2, 2023. It is now read-only.

Commit

Permalink
Use safe stackalloc where possible
Browse files Browse the repository at this point in the history
  • Loading branch information
VSadov committed Sep 6, 2017
1 parent 27d23e5 commit 330a409
Show file tree
Hide file tree
Showing 11 changed files with 102 additions and 160 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,7 @@ public static bool TryWrite(Span<byte> output, Sha256 hash, string keyType, stri
int written, consumed, totalWritten = 0;
bytesWritten = 0;

Span<byte> buffer;
unsafe
{
var pBuffer = stackalloc byte[AuthenticationHeaderBufferSize];
buffer = new Span<byte>(pBuffer, AuthenticationHeaderBufferSize);
}
Span<byte> buffer = stackalloc byte[AuthenticationHeaderBufferSize];

s_type.CopyTo(buffer);
totalWritten += s_type.Length;
Expand Down
5 changes: 2 additions & 3 deletions src/System.Azure.Experimental/System/Azure/Key.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@
namespace System.Azure.Authentication
{
public static class Key {
public unsafe static byte[] ComputeKeyBytes(string key)
public static byte[] ComputeKeyBytes(string key)
{
const int bufferLength = 128;

byte* pBuffer = stackalloc byte[bufferLength];
int written, consumed;
var buffer = new Span<byte>(pBuffer, bufferLength);
Span<byte> buffer = stackalloc byte[bufferLength];
if (Utf16.ToUtf8(key.AsReadOnlySpan().AsBytes(), buffer, out consumed, out written) != OperationStatus.Done)
{
throw new NotImplementedException("need to resize buffer");
Expand Down
28 changes: 7 additions & 21 deletions src/System.Buffers.Experimental/System/Buffers/BufferExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,10 @@ public static class BufferExtensions
public static void Pipe(this Transformation transformation, ReadOnlyBytes source, IOutput destination)
{
int afterMergeSlice = 0;
ReadOnlySpan<byte> remainder;
Span<byte> stackSpan;

unsafe
{
byte* stackBytes = stackalloc byte[stackLength];
stackSpan = new Span<byte>(stackBytes, stackLength);
}
// make 'remainder' formally stack-referring or we won't be able to reference stack data later
ReadOnlySpan<byte> remainder = stackalloc byte[0];
Span<byte> stackSpan = stackalloc byte[stackLength];

var poisition = Position.First;
while (source.TryGet(ref poisition, out var sourceBuffer, true))
Expand Down Expand Up @@ -325,21 +321,11 @@ internal static int IndexOfStraddling(this ReadOnlySpan<byte> first, IReadOnlyBu
// this check is a small optimization: if the first byte from the value does not exist in the bytesToSearchAgain, there is no reason to combine
if (bytesToSearchAgain.IndexOf(value[0]) != -1)
{
Span<byte> combined;
var combinedBufferLength = value.Length << 1;
if (combinedBufferLength < 128)
{
unsafe
{
byte* temp = stackalloc byte[combinedBufferLength];
combined = new Span<byte>(temp, combinedBufferLength);
}
}
else
{
// TODO (pri 3): I think this could be eliminated by chunking values
combined = new byte[combinedBufferLength];
}
Span<byte> combined = combinedBufferLength < 128 ?
stackalloc byte[combinedBufferLength] :
// TODO (pri 3): I think this could be eliminated by chunking values
combined = new byte[combinedBufferLength];

bytesToSearchAgain.CopyTo(combined);
int combinedLength = bytesToSearchAgain.Length + rest.CopyTo(combined.Slice(bytesToSearchAgain.Length));
Expand Down
50 changes: 16 additions & 34 deletions src/System.Buffers.Experimental/System/Buffers/BytesReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,21 +246,11 @@ int IndexOfStraddling(ReadOnlySpan<byte> value)

if (bytesToSearchAgain.IndexOf(value[0]) != -1)
{
Span<byte> tempSpan;
var tempLen = value.Length << 1;
if (tempLen < 128)
{
unsafe
{
byte* temp = stackalloc byte[tempLen];
tempSpan = new Span<byte>(temp, tempLen);
}
}
else
{
// TODO (pri 3): I think this could be imporved by chunking values
tempSpan = new byte[tempLen];
}
var tempSpan = tempLen < 128 ?
(Span<byte>)stackalloc byte[tempLen] :
// TODO (pri 3): I think this could be imporved by chunking values
new byte[tempLen];

bytesToSearchAgain.CopyTo(tempSpan);
rest.CopyTo(tempSpan.Slice(bytesToSearchAgain.Length));
Expand Down Expand Up @@ -305,17 +295,13 @@ public bool TryParseBoolean(out bool value)
}
}

unsafe
{
byte* temp = stackalloc byte[15];
var tempSpan = new Span<byte>(temp, 15);
var copied = CopyTo(tempSpan);
Span<byte> tempSpan = stackalloc byte[15];
var copied = CopyTo(tempSpan);

if (PrimitiveParser.TryParseBoolean(tempSpan.Slice(0, copied), out value, out consumed, _symbolTable))
{
Advance(consumed);
return true;
}
if (PrimitiveParser.TryParseBoolean(tempSpan.Slice(0, copied), out value, out consumed, _symbolTable))
{
Advance(consumed);
return true;
}

return false;
Expand All @@ -334,17 +320,13 @@ public bool TryParseUInt64(out ulong value)
}
}

unsafe
{
byte* temp = stackalloc byte[32];
var tempSpan = new Span<byte>(temp, 32);
var copied = CopyTo(tempSpan);
Span<byte> tempSpan = stackalloc byte[32];
var copied = CopyTo(tempSpan);

if (PrimitiveParser.TryParseUInt64(tempSpan.Slice(0, copied), out value, out consumed, 'G', _symbolTable))
{
Advance(consumed);
return true;
}
if (PrimitiveParser.TryParseUInt64(tempSpan.Slice(0, copied), out value, out consumed, 'G', _symbolTable))
{
Advance(consumed);
return true;
}

return false;
Expand Down
10 changes: 4 additions & 6 deletions src/System.IO.Pipelines.Extensions/ReadWriteExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,16 @@ public static T ReadLittleEndian<[Primitive]T>(this ReadableBuffer buffer) where
return value;
}

private static unsafe T ReadMultiBig<[Primitive]T>(ReadableBuffer buffer, int len) where T : struct
private static T ReadMultiBig<[Primitive]T>(ReadableBuffer buffer, int len) where T : struct
{
byte* local = stackalloc byte[len];
var localSpan = new Span<byte>(local, len);
Span<byte> localSpan = stackalloc byte[len];
buffer.Slice(0, len).CopyTo(localSpan);
return localSpan.ReadBigEndian<T>();
}

private static unsafe T ReadMultiLittle<[Primitive]T>(ReadableBuffer buffer, int len) where T : struct
private static T ReadMultiLittle<[Primitive]T>(ReadableBuffer buffer, int len) where T : struct
{
byte* local = stackalloc byte[len];
var localSpan = new Span<byte>(local, len);
Span<byte> localSpan = stackalloc byte[len];
buffer.Slice(0, len).CopyTo(localSpan);
return localSpan.ReadLittleEndian<T>();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,24 +203,22 @@ public unsafe static string GetAsciiString(this ReadableBuffer buffer)
/// Decodes the utf8 encoded bytes in the <see cref="ReadableBuffer"/> into a <see cref="string"/>
/// </summary>
/// <param name="buffer">The buffer to decode</param>
public static unsafe string GetUtf8String(this ReadableBuffer buffer)
public static string GetUtf8String(this ReadableBuffer buffer)
{
if (buffer.IsEmpty)
{
return null;
}

ReadOnlySpan<byte> textSpan;
ReadOnlySpan<byte> textSpan = stackalloc byte[0];

if (buffer.IsSingleSpan)
{
textSpan = buffer.First.Span;
}
else if (buffer.Length < 128) // REVIEW: What's a good number
{
var data = stackalloc byte[128];
var destination = new Span<byte>(data, 128);

Span<byte> destination = stackalloc byte[128];
buffer.CopyTo(destination);

// We are able to cast because buffer.Length < 128
Expand Down
122 changes: 62 additions & 60 deletions src/System.Text.Formatting/System/Text/Parsing/SequenceParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,39 +37,43 @@ public static bool TryParseUInt64<T>(this T bufferSequence, out ulong value, out
}

// Combine the first, the second, and potentially more segments into a stack allocated buffer
ReadOnlySpan<byte> combinedSpan;
unsafe
// make 'combinedSpan' formally stack-referring or we won't be able to reference stack data later
ReadOnlySpan<byte> combinedSpan = stackalloc byte[0];

if (first.Length < StackBufferSize)
{
if (first.Length < StackBufferSize) {
var data = stackalloc byte[StackBufferSize];
var destination = new Span<byte>(data, StackBufferSize);

first.CopyTo(destination);
var free = destination.Slice(first.Length);

if (second.Length > free.Length) second = second.Slice(0, free.Length);
second.CopyTo(free);
free = free.Slice(second.Length);

ReadOnlyBuffer<byte> next;
while (free.Length > 0) {
if (bufferSequence.TryGet(ref position, out next)) {
if (next.Length > free.Length) next = next.Slice(0, free.Length);
next.CopyTo(free);
free = free.Slice(next.Length);
}
else {
break;
}
Span<byte> destination = stackalloc byte[StackBufferSize];

first.CopyTo(destination);
var free = destination.Slice(first.Length);

if (second.Length > free.Length) second = second.Slice(0, free.Length);
second.CopyTo(free);
free = free.Slice(second.Length);

ReadOnlyBuffer<byte> next;
while (free.Length > 0)
{
if (bufferSequence.TryGet(ref position, out next))
{
if (next.Length > free.Length) next = next.Slice(0, free.Length);
next.CopyTo(free);
free = free.Slice(next.Length);
}
else
{
break;
}
}

combinedSpan = destination.Slice(0, StackBufferSize - free.Length);
combinedSpan = destination.Slice(0, StackBufferSize - free.Length);

// if the stack allocated buffer parsed succesfully (and for uint it should always do), then return success.
if (PrimitiveParser.InvariantUtf8.TryParseUInt64(combinedSpan, out value, out consumed)) {
if(consumed < combinedSpan.Length || combinedSpan.Length < StackBufferSize) {
return true;
}
// if the stack allocated buffer parsed succesfully (and for uint it should always do), then return success.
if (PrimitiveParser.InvariantUtf8.TryParseUInt64(combinedSpan, out value, out consumed))
{
if (consumed < combinedSpan.Length || combinedSpan.Length < StackBufferSize)
{
return true;
}
}
}
Expand Down Expand Up @@ -110,39 +114,37 @@ public static bool TryParseUInt32<T>(this T bufferSequence, out uint value, out
}

// Combine the first, the second, and potentially more segments into a stack allocated buffer
ReadOnlySpan<byte> combinedSpan;
unsafe
{
if (first.Length < StackBufferSize) {
var data = stackalloc byte[StackBufferSize];
var destination = new Span<byte>(data, StackBufferSize);

first.CopyTo(destination);
var free = destination.Slice(first.Length);

if (second.Length > free.Length) second = second.Slice(0, free.Length);
second.CopyTo(free);
free = free.Slice(second.Length);

ReadOnlyBuffer<byte> next;
while (free.Length > 0) {
if (bufferSequence.TryGet(ref position, out next)) {
if (next.Length > free.Length) next = next.Slice(0, free.Length);
next.CopyTo(free);
free = free.Slice(next.Length);
}
else {
break;
}
// make 'combinedSpan' formally stack-referring or we won't be able to reference stack data later
ReadOnlySpan<byte> combinedSpan = stackalloc byte[0];
if (first.Length < StackBufferSize) {

Span<byte> destination = stackalloc byte[StackBufferSize];

first.CopyTo(destination);
var free = destination.Slice(first.Length);

if (second.Length > free.Length) second = second.Slice(0, free.Length);
second.CopyTo(free);
free = free.Slice(second.Length);

ReadOnlyBuffer<byte> next;
while (free.Length > 0) {
if (bufferSequence.TryGet(ref position, out next)) {
if (next.Length > free.Length) next = next.Slice(0, free.Length);
next.CopyTo(free);
free = free.Slice(next.Length);
}
else {
break;
}
}

combinedSpan = destination.Slice(0, StackBufferSize - free.Length);
combinedSpan = destination.Slice(0, StackBufferSize - free.Length);

// if the stack allocated buffer parsed succesfully (and for uint it should always do), then return success.
if (PrimitiveParser.InvariantUtf8.TryParseUInt32(combinedSpan, out value, out consumed)) {
if(consumed < combinedSpan.Length || combinedSpan.Length < StackBufferSize) {
return true;
}
// if the stack allocated buffer parsed succesfully (and for uint it should always do), then return success.
if (PrimitiveParser.InvariantUtf8.TryParseUInt32(combinedSpan, out value, out consumed)) {
if(consumed < combinedSpan.Length || combinedSpan.Length < StackBufferSize) {
return true;
}
}
}
Expand All @@ -156,4 +158,4 @@ public static bool TryParseUInt32<T>(this T bufferSequence, out uint value, out
return true;
}
}
}
}
10 changes: 4 additions & 6 deletions src/System.Text.Http.Parser/HttpUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,22 +67,20 @@ private static string[] CreateMethodNames()
return methodNames;
}

private unsafe static ulong GetAsciiStringAsLong(string str)
private static ulong GetAsciiStringAsLong(string str)
{
Debug.Assert(str.Length == 8, "String must be exactly 8 (ASCII) characters long.");

var buffer = stackalloc byte[8];
Span<byte> span = new Span<byte>(buffer, 8);
Span<byte> span = stackalloc byte[8];
Encoders.Utf16.ToUtf8(str.AsReadOnlySpan().AsBytes(), span, out int consumed, out int written);
return span.Read<ulong>();
}

private unsafe static uint GetAsciiStringAsInt(string str)
private static uint GetAsciiStringAsInt(string str)
{
Debug.Assert(str.Length == 4, "String must be exactly 4 (ASCII) characters long.");

var buffer = stackalloc byte[4];
Span<byte> span = new Span<byte>(buffer, 4);
Span<byte> span = stackalloc byte[4];
Encoders.Utf16.ToUtf8(str.AsReadOnlySpan().AsBytes(), span, out int consumed, out int written);
return span.Read<uint>();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,7 @@ private static bool TryFormatNumber(double value, bool isSingle, Span<byte> buff
return false;
}

Span<byte> temp;
unsafe
{
var buf = stackalloc byte[needed];
temp = new Span<byte>(buf, needed);
}
Span<byte> temp = stackalloc byte[needed];

status = Encoders.Utf16.ToUtf8(utf16Bytes, temp, out int consumed, out written);
if (status != Buffers.OperationStatus.Done)
Expand Down
Loading

0 comments on commit 330a409

Please sign in to comment.