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

Commit

Permalink
Add span-based Guid.{Try}Parse{Exact} methods (#14062)
Browse files Browse the repository at this point in the history
This commit does two things:
- Changes the existing Guid.{Try}Parse{Exact} methods to work in terms of spans rather than strings.
- Then adds new overloads that accept spans and that uses the same underlying span-based support.

Due to the first change, performance actually improves for several of the guid formats, in particular due to substring allocations that are no longer incurred.  For example, this program:
```C#
using System;
using System.Diagnostics;

class Program
{
    static void Main()
    {
        var sw = new Stopwatch();
        const int Iters = 1000000;

        Console.WriteLine("Pattern\tBytes\tTime");
        foreach (string pattern in new[] { "D", "B", "P", "N", "X" })
        {
            string input = Guid.NewGuid().ToString(pattern);
            Guid.Parse(input);

            long a = GC.GetAllocatedBytesForCurrentThread();
            sw.Restart();
            for (int i = 0; i < Iters; i++) Guid.Parse(input);
            sw.Stop();
            a = GC.GetAllocatedBytesForCurrentThread() - a;

            Console.WriteLine($"\"{pattern}\"\t{a / Iters}\t{(int)(sw.Elapsed.TotalMilliseconds / Iters * 1000000)}ns");
        }
    }
}
```
on my machine previously output:
```
Pattern Bytes   Time
"D"     0       218ns
"B"     0       217ns
"P"     0       210ns
"N"     168     388ns
"X"     744     765ns
```
and with this change outputs:
```
Pattern Bytes   Time
"D"     0       213ns
"B"     0       192ns
"P"     0       196ns
"N"     0       372ns
"X"     0       577ns
```
  • Loading branch information
stephentoub authored Sep 19, 2017
1 parent d8ad7fa commit fe537af
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 136 deletions.
48 changes: 40 additions & 8 deletions src/mscorlib/shared/System/Convert.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2276,7 +2276,13 @@ public static byte ToByte(String value, int fromBase)
throw new ArgumentException(SR.Arg_InvalidBase);
}
Contract.EndContractBlock();
int r = ParseNumbers.StringToInt(value, fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsUnsigned);

if (value == null)
{
return 0;
}

int r = ParseNumbers.StringToInt(value.AsReadOnlySpan(), fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsUnsigned);
if (r < Byte.MinValue || r > Byte.MaxValue)
ThrowByteOverflowException();
return (byte)r;
Expand All @@ -2294,7 +2300,13 @@ public static sbyte ToSByte(String value, int fromBase)
throw new ArgumentException(SR.Arg_InvalidBase);
}
Contract.EndContractBlock();
int r = ParseNumbers.StringToInt(value, fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsI1);

if (value == null)
{
return 0;
}

int r = ParseNumbers.StringToInt(value.AsReadOnlySpan(), fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsI1);
if (fromBase != 10 && r <= Byte.MaxValue)
return (sbyte)r;

Expand All @@ -2314,7 +2326,13 @@ public static short ToInt16(String value, int fromBase)
throw new ArgumentException(SR.Arg_InvalidBase);
}
Contract.EndContractBlock();
int r = ParseNumbers.StringToInt(value, fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsI2);

if (value == null)
{
return 0;
}

int r = ParseNumbers.StringToInt(value.AsReadOnlySpan(), fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsI2);
if (fromBase != 10 && r <= UInt16.MaxValue)
return (short)r;

Expand All @@ -2335,7 +2353,13 @@ public static ushort ToUInt16(String value, int fromBase)
throw new ArgumentException(SR.Arg_InvalidBase);
}
Contract.EndContractBlock();
int r = ParseNumbers.StringToInt(value, fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsUnsigned);

if (value == null)
{
return 0;
}

int r = ParseNumbers.StringToInt(value.AsReadOnlySpan(), fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsUnsigned);
if (r < UInt16.MinValue || r > UInt16.MaxValue)
ThrowUInt16OverflowException();
return (ushort)r;
Expand All @@ -2352,7 +2376,9 @@ public static int ToInt32(String value, int fromBase)
throw new ArgumentException(SR.Arg_InvalidBase);
}
Contract.EndContractBlock();
return ParseNumbers.StringToInt(value, fromBase, ParseNumbers.IsTight);
return value != null ?
ParseNumbers.StringToInt(value.AsReadOnlySpan(), fromBase, ParseNumbers.IsTight) :
0;
}

// Parses value in base fromBase. fromBase can only
Expand All @@ -2367,7 +2393,9 @@ public static uint ToUInt32(String value, int fromBase)
throw new ArgumentException(SR.Arg_InvalidBase);
}
Contract.EndContractBlock();
return (uint)ParseNumbers.StringToInt(value, fromBase, ParseNumbers.TreatAsUnsigned | ParseNumbers.IsTight);
return value != null ?
(uint)ParseNumbers.StringToInt(value.AsReadOnlySpan(), fromBase, ParseNumbers.TreatAsUnsigned | ParseNumbers.IsTight) :
0;
}

// Parses value in base fromBase. fromBase can only
Expand All @@ -2381,7 +2409,9 @@ public static long ToInt64(String value, int fromBase)
throw new ArgumentException(SR.Arg_InvalidBase);
}
Contract.EndContractBlock();
return ParseNumbers.StringToLong(value, fromBase, ParseNumbers.IsTight);
return value != null ?
ParseNumbers.StringToLong(value.AsReadOnlySpan(), fromBase, ParseNumbers.IsTight) :
0;
}

// Parses value in base fromBase. fromBase can only
Expand All @@ -2396,7 +2426,9 @@ public static ulong ToUInt64(String value, int fromBase)
throw new ArgumentException(SR.Arg_InvalidBase);
}
Contract.EndContractBlock();
return (ulong)ParseNumbers.StringToLong(value, fromBase, ParseNumbers.TreatAsUnsigned | ParseNumbers.IsTight);
return value != null ?
(ulong)ParseNumbers.StringToLong(value.AsReadOnlySpan(), fromBase, ParseNumbers.TreatAsUnsigned | ParseNumbers.IsTight) :
0;
}

// Convert the byte value to a string in base fromBase
Expand Down
Loading

0 comments on commit fe537af

Please sign in to comment.