Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 55 additions & 63 deletions src/Common/src/System/Globalization/FormatProvider.Number.cs
Original file line number Diff line number Diff line change
Expand Up @@ -547,21 +547,17 @@ private static unsafe bool ParseNumber(ref char* str, NumberStyles options, ref
return false;
}

private static unsafe bool TrailingZeros(ReadOnlySpan<char> s, int index)
private static bool TrailingZeros(ReadOnlySpan<char> s, int index)
{
fixed (char* sPtr = &s.DangerousGetPinnableReference())
// For compatibility, we need to allow trailing zeros at the end of a number string
for (int i = index; i < s.Length; i++)
{
var span = new Span<char>(sPtr, s.Length);
// For compatibility, we need to allow trailing zeros at the end of a number string
for (int i = index; i < s.Length; i++)
if (s[i] != '\0')
{
if (span[i] != '\0')
{
return false;
}
return false;
}
return true;
}
return true;
}

internal static unsafe bool TryStringToNumber(ReadOnlySpan<char> str, NumberStyles options, ref NumberBuffer number, StringBuilder sb, NumberFormatInfo numfmt, bool parseDecimal)
Expand Down Expand Up @@ -638,72 +634,68 @@ internal static unsafe void Int32ToDecChars(char* buffer, ref int index, uint va

internal static unsafe char ParseFormatSpecifier(ReadOnlySpan<char> format, out int digits)
{
fixed (char* formatPtr = &format.DangerousGetPinnableReference())
char c = default;
if (format.Length > 0)
{
var formatSpan = new Span<char>(formatPtr, format.Length);
char c = default;
if (format.Length > 0)
// If the format begins with a symbol, see if it's a standard format
// with or without a specified number of digits.
c = format[0];
if ((uint)(c - 'A') <= 'Z' - 'A' ||
(uint)(c - 'a') <= 'z' - 'a')
{
// If the format begins with a symbol, see if it's a standard format
// with or without a specified number of digits.
c = formatSpan[0];
if ((uint)(c - 'A') <= 'Z' - 'A' ||
(uint)(c - 'a') <= 'z' - 'a')
// Fast path for sole symbol, e.g. "D"
if (format.Length == 1)
{
// Fast path for sole symbol, e.g. "D"
if (format.Length == 1)
{
digits = -1;
return c;
}
digits = -1;
return c;
}

if (format.Length == 2)
if (format.Length == 2)
{
// Fast path for symbol and single digit, e.g. "X4"
int d = format[1] - '0';
if ((uint)d < 10)
{
// Fast path for symbol and single digit, e.g. "X4"
int d = formatSpan[1] - '0';
if ((uint)d < 10)
{
digits = d;
return c;
}
digits = d;
return c;
}
else if (format.Length == 3)
}
else if (format.Length == 3)
{
// Fast path for symbol and double digit, e.g. "F12"
int d1 = format[1] - '0', d2 = format[2] - '0';
if ((uint)d1 < 10 && (uint)d2 < 10)
{
// Fast path for symbol and double digit, e.g. "F12"
int d1 = formatSpan[1] - '0', d2 = formatSpan[2] - '0';
if ((uint)d1 < 10 && (uint)d2 < 10)
{
digits = d1 * 10 + d2;
return c;
}
digits = d1 * 10 + d2;
return c;
}
}

// Fallback for symbol and any length digits. The digits value must be >= 0 && <= 99,
// but it can begin with any number of 0s, and thus we may need to check more than two
// digits. Further, for compat, we need to stop when we hit a null char.
int n = 0;
int i = 1;
while (i < format.Length && (((uint)formatSpan[i] - '0') < 10) && n < 10)
{
n = (n * 10) + formatSpan[i++] - '0';
}
// Fallback for symbol and any length digits. The digits value must be >= 0 && <= 99,
// but it can begin with any number of 0s, and thus we may need to check more than two
// digits. Further, for compat, we need to stop when we hit a null char.
int n = 0;
int i = 1;
while (i < format.Length && (((uint)format[i] - '0') < 10) && n < 10)
{
n = (n * 10) + format[i++] - '0';
}

// If we're at the end of the digits rather than having stopped because we hit something
// other than a digit or overflowed, return the standard format info.
if (i == format.Length || formatSpan[i] == '\0')
{
digits = n;
return c;
}
// If we're at the end of the digits rather than having stopped because we hit something
// other than a digit or overflowed, return the standard format info.
if (i == format.Length || format[i] == '\0')
{
digits = n;
return c;
}
}

// Default empty format to be "G"; custom format is signified with '\0'.
digits = -1;
return format.Length == 0 || c == '\0' ? // For compat, treat '\0' as the end of the specifier, even if the specifier extends beyond it.
'G' :
'\0';
}

// Default empty format to be "G"; custom format is signified with '\0'.
digits = -1;
return format.Length == 0 || c == '\0' ? // For compat, treat '\0' as the end of the specifier, even if the specifier extends beyond it.
'G' :
'\0';
}

internal static unsafe void NumberToString(ref ValueStringBuilder sb, ref NumberBuffer number, char format, int nMaxDigits, NumberFormatInfo info, bool isDecimal)
Expand Down
22 changes: 9 additions & 13 deletions src/Common/src/System/Memory/FixedBufferExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,17 @@ internal unsafe static bool FixedBufferEqualsString(this ReadOnlySpan<char> span
if (value == null || value.Length > span.Length)
return false;

fixed (char* spanPtr = &span.DangerousGetPinnableReference())
int i = 0;
for (; i < value.Length; i++)
{
var readWriteSpan = new Span<char>(spanPtr, span.Length);
int i = 0;
for (; i < value.Length; i++)
{
// Strings with embedded nulls can never match as the fixed buffer always null terminates.
if (value[i] == '\0' || value[i] != readWriteSpan[i])
return false;
}

// If we've maxed out the buffer or reached the
// null terminator, we're equal.
return i == span.Length || readWriteSpan[i] == '\0';
// Strings with embedded nulls can never match as the fixed buffer always null terminates.
if (value[i] == '\0' || value[i] != span[i])
return false;
}

// If we've maxed out the buffer or reached the
// null terminator, we're equal.
return i == span.Length || span[i] == '\0';
}
}
}
46 changes: 17 additions & 29 deletions src/System.IO.FileSystem/src/System/IO/PathHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,12 @@ internal unsafe static string CombineNoChecks(string first, string second)
private unsafe static string CombineNoChecksInternal(ReadOnlySpan<char> first, ReadOnlySpan<char> second)
{
Debug.Assert(first.Length > 0 && second.Length > 0, "should have dealt with empty paths");

bool hasSeparator = PathInternal.IsDirectorySeparator(first[first.Length - 1])
|| PathInternal.IsDirectorySeparator(second[0]);

fixed (char* f = &first.DangerousGetPinnableReference(), s = &second.DangerousGetPinnableReference())
{
var firstSpan = new Span<char>(f, first.Length);
var secondSpan = new Span<char>(s, second.Length);
bool hasSeparator = PathInternal.IsDirectorySeparator(firstSpan[first.Length - 1])
|| PathInternal.IsDirectorySeparator(secondSpan[0]);

return string.Create(
first.Length + second.Length + (hasSeparator ? 0 : 1),
(First: (IntPtr)f, FirstLength: first.Length, Second: (IntPtr)s, SecondLength: second.Length, HasSeparator: hasSeparator),
Expand All @@ -137,17 +136,14 @@ private unsafe static string CombineNoChecksInternal(ReadOnlySpan<char> first, R
private unsafe static string CombineNoChecksInternal(ReadOnlySpan<char> first, ReadOnlySpan<char> second, ReadOnlySpan<char> third)
{
Debug.Assert(first.Length > 0 && second.Length > 0 && third.Length > 0, "should have dealt with empty paths");
fixed (char* f = &first.DangerousGetPinnableReference(), s = &second.DangerousGetPinnableReference(), t = &third.DangerousGetPinnableReference())
{
var firstSpan = new Span<char>(f, first.Length);
var secondSpan = new Span<char>(s, second.Length);
var thirdSpan = new Span<char>(t, third.Length);

bool firstHasSeparator = PathInternal.IsDirectorySeparator(firstSpan[first.Length - 1])
|| PathInternal.IsDirectorySeparator(secondSpan[0]);
bool thirdHasSeparator = PathInternal.IsDirectorySeparator(secondSpan[second.Length - 1])
|| PathInternal.IsDirectorySeparator(thirdSpan[0]);
bool firstHasSeparator = PathInternal.IsDirectorySeparator(first[first.Length - 1])
|| PathInternal.IsDirectorySeparator(second[0]);
bool thirdHasSeparator = PathInternal.IsDirectorySeparator(second[second.Length - 1])
|| PathInternal.IsDirectorySeparator(third[0]);

fixed (char* f = &first.DangerousGetPinnableReference(), s = &second.DangerousGetPinnableReference(), t = &third.DangerousGetPinnableReference())
{
return string.Create(
first.Length + second.Length + third.Length + (firstHasSeparator ? 0 : 1) + (thirdHasSeparator ? 0 : 1),
(First: (IntPtr)f, FirstLength: first.Length, Second: (IntPtr)s, SecondLength: second.Length,
Expand All @@ -171,30 +167,22 @@ private unsafe static string CombineNoChecksInternal(ReadOnlySpan<char> first, R
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe bool IsDotOrDotDot(ReadOnlySpan<char> fileName)
{
fixed (char* fileNamePtr = &fileName.DangerousGetPinnableReference())
{
var fileNameSpan = new Span<char>(fileNamePtr, fileName.Length);
return !(fileName.Length > 2
|| fileNameSpan[0] != '.'
|| (fileName.Length == 2 && fileNameSpan[1] != '.'));
}
return !(fileName.Length > 2
|| fileName[0] != '.'
|| (fileName.Length == 2 && fileName[1] != '.'));
}

public static unsafe ReadOnlySpan<char> GetDirectoryNameNoChecks(ReadOnlySpan<char> path)
public static ReadOnlySpan<char> GetDirectoryNameNoChecks(ReadOnlySpan<char> path)
{
if (path.Length == 0)
return ReadOnlySpan<char>.Empty;

int root = PathInternal.GetRootLength(path);
int i = path.Length;
fixed (char* pathPtr = &path.DangerousGetPinnableReference())
if (i > root)
{
var pathSpan = new Span<char>(pathPtr, path.Length);
if (i > root)
{
while (i > root && !PathInternal.IsDirectorySeparator(pathSpan[--i])) ;
return pathSpan.Slice(0, i);
}
while (i > root && !PathInternal.IsDirectorySeparator(path[--i])) ;
return path.Slice(0, i);
}

return ReadOnlySpan<char>.Empty;
Expand Down
12 changes: 4 additions & 8 deletions src/System.Private.Xml/src/System/Xml/Core/XmlTextReaderImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3212,20 +3212,16 @@ private void SetupEncoding(Encoding encoding)
}
}

private unsafe void EatPreamble()
private void EatPreamble()
{
ReadOnlySpan<byte> preamble = _ps.encoding.Preamble;
int preambleLen = preamble.Length;
int i;
fixed (byte* preamblePtr = &preamble.DangerousGetPinnableReference())
for (i = 0; i < preambleLen && i < _ps.bytesUsed; i++)
{
var preambleSpan = new Span<byte>(preamblePtr, preambleLen);
for (i = 0; i < preambleLen && i < _ps.bytesUsed; i++)
if (_ps.bytes[i] != preamble[i])
{
if (_ps.bytes[i] != preambleSpan[i])
{
break;
}
break;
}
}
if (i == preambleLen)
Expand Down
16 changes: 6 additions & 10 deletions src/System.Runtime.Extensions/src/System/IO/StreamReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,7 @@ private void DetectEncoding()
// there is no match. If there is no match, every byte read previously will be available
// for further consumption. If there is a match, we will compress the buffer for the
// leading preamble bytes
private unsafe bool IsPreamble()
private bool IsPreamble()
{
if (!_checkPreamble)
{
Expand All @@ -571,17 +571,13 @@ private unsafe bool IsPreamble()
Debug.Assert(_bytePos <= preamble.Length, "_compressPreamble was called with the current bytePos greater than the preamble buffer length. Are two threads using this StreamReader at the same time?");
int len = (_byteLen >= (preamble.Length)) ? (preamble.Length - _bytePos) : (_byteLen - _bytePos);

fixed (byte* preamblePtr = &preamble.DangerousGetPinnableReference())
for (int i = 0; i < len; i++, _bytePos++)
{
var preambleSpan = new Span<byte>(preamblePtr, preamble.Length);
for (int i = 0; i < len; i++, _bytePos++)
if (_byteBuffer[_bytePos] != preamble[_bytePos])
{
if (_byteBuffer[_bytePos] != preambleSpan[_bytePos])
{
_bytePos = 0;
_checkPreamble = false;
break;
}
_bytePos = 0;
_checkPreamble = false;
break;
}
}

Expand Down
8 changes: 2 additions & 6 deletions src/System.Runtime.Extensions/src/System/IO/StreamWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -375,13 +375,9 @@ private unsafe void WriteCore(ReadOnlySpan<char> buffer, bool autoFlush)
{
// For very short buffers and when we don't need to worry about running out of space
// in the char buffer, just copy the chars individually.
fixed (char* bufferPtr = &buffer.DangerousGetPinnableReference())
for (int i = 0; i < buffer.Length; i++)
{
Span<char> bufferSpan = new Span<char>(bufferPtr, buffer.Length);
for (int i = 0; i < buffer.Length; i++)
{
_charBuffer[_charPos++] = bufferSpan[i];
}
_charBuffer[_charPos++] = buffer[i];
}
}
else
Expand Down
Loading