Skip to content

Commit

Permalink
Replace 2 allocations from string.ToCharArray() with ReadOnlySpan in …
Browse files Browse the repository at this point in the history
…System.Private.Xml library (dotnet#67002)

* Remove ToCharArray() used in BinHexDecoder

* Replace ToCharArray() used in XmlSerializationReader with Span

* Address feedback

* Remove not necessary check for null

* Remove OutOfMemoryException catch

Co-authored-by: Trayan Zapryanov <[email protected]>
  • Loading branch information
TrayanZapryanov and TrayanZapryanov authored Apr 8, 2022
1 parent 9cb6475 commit e6c8d42
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ internal override void SetNextOutputBuffer(Array buffer, int index, int count)
//
// Static methods
//
public static byte[] Decode(char[] chars!!, bool allowOddChars)
public static byte[] Decode(ReadOnlySpan<char> chars, bool allowOddChars)
{
int len = chars.Length;
if (len == 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -974,25 +974,24 @@ private SoapArrayInfo ParseArrayType(string value)
throw new ArgumentException(SR.Format(SR.XmlEmptyArrayType, CurrentTag()), nameof(value));
}

char[] chars = value.ToCharArray();
int charsLength = chars.Length;
int charsLength = value.Length;

SoapArrayInfo soapArrayInfo = default;

// Parse backwards to get length first, then optional dimensions, then qname.
int pos = charsLength - 1;

// Must end with ]
if (chars[pos] != ']')
if (value[pos] != ']')
{
throw new ArgumentException(SR.XmlInvalidArraySyntax, nameof(value));
}
pos--;

// Find [
while (pos != -1 && chars[pos] != '[')
while (pos != -1 && value[pos] != '[')
{
if (chars[pos] == ',')
if (value[pos] == ',')
throw new ArgumentException(SR.Format(SR.XmlInvalidArrayDimentions, CurrentTag()), nameof(value));
pos--;
}
Expand All @@ -1004,19 +1003,9 @@ private SoapArrayInfo ParseArrayType(string value)
int len = charsLength - pos - 2;
if (len > 0)
{
string lengthString = new string(chars, pos + 1, len);
try
{
soapArrayInfo.length = int.Parse(lengthString, CultureInfo.InvariantCulture);
}
catch (Exception e)
{
if (e is OutOfMemoryException)
{
throw;
}
throw new ArgumentException(SR.Format(SR.XmlInvalidArrayLength, lengthString), nameof(value));
}
ReadOnlySpan<char> lengthStringSpan = value.AsSpan(pos + 1, len);
if (!int.TryParse(lengthStringSpan, CultureInfo.InvariantCulture, out soapArrayInfo.length))
throw new ArgumentException(SR.Format(SR.XmlInvalidArrayLength, new string(lengthStringSpan)), nameof(value));
}
else
{
Expand All @@ -1026,14 +1015,14 @@ private SoapArrayInfo ParseArrayType(string value)
pos--;

soapArrayInfo.jaggedDimensions = 0;
while (pos != -1 && chars[pos] == ']')
while (pos != -1 && value[pos] == ']')
{
pos--;
if (pos < 0)
throw new ArgumentException(SR.XmlMismatchedArrayBrackets, nameof(value));
if (chars[pos] == ',')
if (value[pos] == ',')
throw new ArgumentException(SR.Format(SR.XmlInvalidArrayDimentions, CurrentTag()), nameof(value));
else if (chars[pos] != '[')
else if (value[pos] != '[')
throw new ArgumentException(SR.XmlInvalidArraySyntax, nameof(value));
pos--;
soapArrayInfo.jaggedDimensions++;
Expand All @@ -1042,7 +1031,7 @@ private SoapArrayInfo ParseArrayType(string value)
soapArrayInfo.dimensions = 1;

// everything else is qname - validation of qnames?
soapArrayInfo.qname = new string(chars, 0, pos + 1);
soapArrayInfo.qname = new string(value.AsSpan(0, pos + 1));
return soapArrayInfo;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ internal static byte[] FromBinHexString(string s)

internal static byte[] FromBinHexString(string s!!, bool allowOddCount)
{
return BinHexDecoder.Decode(s.ToCharArray(), allowOddCount);
return BinHexDecoder.Decode(s.AsSpan(), allowOddCount);
}

internal static string ToBinHexString(byte[] inArray!!)
Expand Down

0 comments on commit e6c8d42

Please sign in to comment.