Skip to content

Commit 96ab868

Browse files
ladeakcaptainsafia
authored andcommitted
Removing unsafe code in BufferExtensions (#57417)
1 parent 597e3b1 commit 96ab868

File tree

2 files changed

+45
-40
lines changed

2 files changed

+45
-40
lines changed

src/Servers/Kestrel/Core/test/PipelineExtensionTests.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System;
54
using System.Buffers;
65
using System.Globalization;
76
using System.IO.Pipelines;
87
using System.Text;
9-
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
10-
using Xunit;
118

129
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests;
1310

@@ -51,6 +48,25 @@ public void WritesNumericToAscii(ulong number)
5148
AssertExtensions.Equal(expected, reader.Buffer.Slice(0, numAsStr.Length).ToArray());
5249
}
5350

51+
[Fact]
52+
public void WritesNumericToAsciiFastPath()
53+
{
54+
for (ulong number = 0; number < 1000; number++)
55+
{
56+
var writerBuffer = _pipe.Writer;
57+
var writer = new BufferWriter<PipeWriter>(writerBuffer);
58+
writer.WriteNumeric(number);
59+
writer.Commit();
60+
writerBuffer.FlushAsync().GetAwaiter().GetResult();
61+
62+
var readResult = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
63+
var numAsStr = number.ToString(CultureInfo.InvariantCulture);
64+
var expected = Encoding.ASCII.GetBytes(numAsStr);
65+
AssertExtensions.Equal(expected, readResult.Buffer.Slice(0, numAsStr.Length).ToArray());
66+
_pipe.Reader.AdvanceTo(readResult.Buffer.End);
67+
}
68+
}
69+
5470
[Theory]
5571
[InlineData(1)]
5672
[InlineData(_ulongMaxValueLength / 2)]

src/Shared/ServerInfrastructure/BufferExtensions.cs

Lines changed: 26 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -129,52 +129,41 @@ internal static void WriteAscii(ref this BufferWriter<PipeWriter> buffer, string
129129
}
130130

131131
[MethodImpl(MethodImplOptions.AggressiveInlining)]
132-
internal static unsafe void WriteNumeric(ref this BufferWriter<PipeWriter> buffer, ulong number)
132+
internal static void WriteNumeric(ref this BufferWriter<PipeWriter> bufferWriter, ulong number)
133133
{
134134
const byte AsciiDigitStart = (byte)'0';
135135

136-
var span = buffer.Span;
137-
var bytesLeftInBlock = span.Length;
136+
var buffer = bufferWriter.Span;
138137

139138
// Fast path, try copying to the available memory directly
140-
var simpleWrite = true;
141-
fixed (byte* output = span)
139+
if (number < 10 && buffer.Length >= 1)
142140
{
143-
var start = output;
144-
if (number < 10 && bytesLeftInBlock >= 1)
145-
{
146-
*(start) = (byte)(((uint)number) + AsciiDigitStart);
147-
buffer.Advance(1);
148-
}
149-
else if (number < 100 && bytesLeftInBlock >= 2)
150-
{
151-
var val = (uint)number;
152-
var tens = (byte)((val * 205u) >> 11); // div10, valid to 1028
153-
154-
*(start) = (byte)(tens + AsciiDigitStart);
155-
*(start + 1) = (byte)(val - (tens * 10) + AsciiDigitStart);
156-
buffer.Advance(2);
157-
}
158-
else if (number < 1000 && bytesLeftInBlock >= 3)
159-
{
160-
var val = (uint)number;
161-
var digit0 = (byte)((val * 41u) >> 12); // div100, valid to 1098
162-
var digits01 = (byte)((val * 205u) >> 11); // div10, valid to 1028
163-
164-
*(start) = (byte)(digit0 + AsciiDigitStart);
165-
*(start + 1) = (byte)(digits01 - (digit0 * 10) + AsciiDigitStart);
166-
*(start + 2) = (byte)(val - (digits01 * 10) + AsciiDigitStart);
167-
buffer.Advance(3);
168-
}
169-
else
170-
{
171-
simpleWrite = false;
172-
}
141+
buffer[0] = (byte)(((uint)number) + AsciiDigitStart);
142+
bufferWriter.Advance(1);
173143
}
144+
else if (number < 100 && buffer.Length >= 2)
145+
{
146+
var val = (uint)number;
147+
var tens = (uint)(byte)((val * 205u) >> 11); // div10, valid to 1028
174148

175-
if (!simpleWrite)
149+
buffer[0] = (byte)(tens + AsciiDigitStart);
150+
buffer[1] = (byte)(val - (tens * 10) + AsciiDigitStart);
151+
bufferWriter.Advance(2);
152+
}
153+
else if (number < 1000 && buffer.Length >= 3)
154+
{
155+
var val = (uint)number;
156+
var digit0 = (uint)(byte)((val * 41u) >> 12); // div100, valid to 1098
157+
var digits01 = (uint)(byte)((val * 205u) >> 11); // div10, valid to 1028
158+
159+
buffer[0] = (byte)(digit0 + AsciiDigitStart);
160+
buffer[1] = (byte)(digits01 - (digit0 * 10) + AsciiDigitStart);
161+
buffer[2] = (byte)(val - (digits01 * 10) + AsciiDigitStart);
162+
bufferWriter.Advance(3);
163+
}
164+
else
176165
{
177-
WriteNumericMultiWrite(ref buffer, number);
166+
WriteNumericMultiWrite(ref bufferWriter, number);
178167
}
179168
}
180169

0 commit comments

Comments
 (0)