diff --git a/Benchmark.csproj b/Benchmark.csproj
index b1a51fc..0bbc819 100644
--- a/Benchmark.csproj
+++ b/Benchmark.csproj
@@ -7,6 +7,7 @@
+
diff --git a/Identity.cs b/Identity.cs
index 81e950b..9abebb4 100644
--- a/Identity.cs
+++ b/Identity.cs
@@ -1,4 +1,4 @@
-using System.Linq;
+using System;
using System.Runtime.CompilerServices;
namespace Benchmark
@@ -20,29 +20,74 @@ namespace Benchmark
{
identity = default;
var position = value.Length;
- if (!TryGetNumber(value, null, ref position, out var revision)) return false;
+ if (!TryGetNumberOld(ref value, null, ref position, out var revision)) return false;
if (value[position] != '-') return false;
- if (!TryGetNumber(value, 7, ref position, out var index)) return false;
- if (!TryGetPrefix(value, ref position, out var prefix)) return false;
+ if (!TryGetNumberOld(ref value, 7, ref position, out var index)) return false;
+ if (!TryGetPrefixOld(ref value, ref position, out var prefix)) return false;
+ identity = new Identity(prefix, index, revision);
+ return true; }
+
+ public static bool TryParse(Span value, out Identity identity)
+ {
+ identity = default;
+ var position = value.Length;
+ if (!TryGetNumber(ref value, null, ref position, out var revision)) return false;
+ if (value[position] != '-') return false;
+ if (!TryGetNumber(ref value, 7, ref position, out var index)) return false;
+ if (!TryGetPrefix(ref value, ref position, out var prefix)) return false;
identity = new Identity(prefix, index, revision);
return true;
}
- private static bool TryGetPrefix(in string identity, ref int lastPosition, out string prefix)
+
+ private static bool TryGetPrefixOld(ref string identity, ref int lastPosition, out string prefix)
{
- prefix = identity.Remove(lastPosition + 1);
+ prefix = identity[(lastPosition + 1)..];
if (prefix.Length < 3) return false;
- return !prefix.Any(character => character < 'A' || character > 'Z');
+ for (int i = 0; i < prefix.Length; i++)
+ {
+ if (prefix[i] < 'A' || prefix[i] > 'Z') return false;
+ }
+ return true;
}
- private static bool TryGetNumber(in string identity, int? exactLength, ref int currentPosition, out int revision)
+ private static bool TryGetPrefix(ref Span identity, ref int lastPosition, out string prefix)
+ {
+ var span = identity[(lastPosition + 1)..];
+ prefix = span.ToString();
+ if (span.Length < 3) return false;
+ for (int i = 0; i < span.Length; i++)
+ {
+ if (span[i] < 'A' || span[i] > 'Z') return false;
+ }
+
+ return true;
+ }
+
+ private static bool TryGetNumberOld(ref string identity, int? exactLength, ref int currentPosition, out int revision)
{
revision = 0;
var start = currentPosition;
for (currentPosition = start - 1; currentPosition >= 0; currentPosition--)
{
var current = identity[currentPosition];
- if(current == '0') continue;
+ if (current == '0') continue;
+ if (current < '1' || current > '9') break;
+ revision += (current - '0') * IntegerPow(10, start - currentPosition - 1);
+ }
+
+ if (exactLength != null && start - (currentPosition + 1) != exactLength) return false;
+ return revision != default;
+ }
+
+ private static bool TryGetNumber(ref Span identity, int? exactLength, ref int currentPosition, out int revision)
+ {
+ revision = 0;
+ var start = currentPosition;
+ for (currentPosition = start - 1; currentPosition >= 0; currentPosition--)
+ {
+ var current = identity[currentPosition];
+ if (current == '0') continue;
if (current < '1' || current > '9') break;
revision += (current - '0') * IntegerPow(10, start - currentPosition - 1);
}
diff --git a/IdentityParser.cs b/IdentityParser.cs
index 9ae6a19..8fb0e2a 100644
--- a/IdentityParser.cs
+++ b/IdentityParser.cs
@@ -1,16 +1,29 @@
-using System.Text.RegularExpressions;
+using System;
+using System.Text.RegularExpressions;
using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Jobs;
namespace Benchmark
{
[MemoryDiagnoser]
+ //[SimpleJob(RuntimeMoniker.Net472, baseline: true)]
+ [SimpleJob(RuntimeMoniker.NetCoreApp31)]
+ [SimpleJob(RuntimeMoniker.NetCoreApp50)]
public class IdentityParser
{
private const string TestIdentity = "ABZ0000001-1";
+ private char[] TestIdentityChars;
+
private readonly Regex _regex = new Regex(@"^(\w{3,})(\d{7})-(\d+)$", RegexOptions.Compiled);
+ [GlobalSetup]
+ public void GlobalSetup()
+ {
+ TestIdentityChars = TestIdentity.ToCharArray();
+ }
+
[Benchmark]
- public Identity? Parse1()
+ public Identity? ParseWithRegex()
{
var match = _regex.Match(TestIdentity);
if (!match.Success) return default;
@@ -21,9 +34,15 @@ namespace Benchmark
}
[Benchmark]
- public Identity? Parse2()
+ public Identity? ParseWithoutRegex()
{
return Identity.TryParse(TestIdentity, out var identity) ? identity : default(Identity?);
}
+
+ [Benchmark]
+ public Identity? ParseWithSpanT()
+ {
+ return Identity.TryParse(TestIdentityChars, out var identity) ? identity : default(Identity?);
+ }
}
}
\ No newline at end of file
diff --git a/TestProject1/TestProject1.csproj b/TestProject1/TestProject1.csproj
index cb90b17..ee6543b 100644
--- a/TestProject1/TestProject1.csproj
+++ b/TestProject1/TestProject1.csproj
@@ -8,11 +8,11 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/TestProject1/UnitTest1.cs b/TestProject1/UnitTest1.cs
index 3f6ea76..21b15f6 100644
--- a/TestProject1/UnitTest1.cs
+++ b/TestProject1/UnitTest1.cs
@@ -11,46 +11,46 @@ namespace TestProject1
}
[Test]
- public void Test3()
+ public void Test03()
{
var actual = new TrailingNumberFromString().GetTrailingNumberFromString3();
Assert.AreEqual(1234, actual);
}
[Test]
- public void Test4()
+ public void Test04()
{
var actual = new TrailingNumberFromString().GetTrailingNumberFromString4();
Assert.AreEqual(1234, actual);
}
[Test]
- public void Test5()
+ public void Test05()
{
var actual = new TrailingNumberFromString().GetTrailingNumberFromString5();
Assert.AreEqual(1234, actual);
}
[Test]
- public void Test6()
+ public void Test06()
{
- var actual = new IdentityParser().Parse1();
+ var actual = new IdentityParser().ParseWithoutRegex();
Assert.AreEqual("ABZ", actual?.Prefix);
Assert.AreEqual(1, actual?.Index);
Assert.AreEqual(1, actual?.Revision);
}
[Test]
- public void Test7()
+ public void Test07()
{
- var actual = new IdentityParser().Parse2();
+ var actual = new IdentityParser().ParseWithRegex();
Assert.AreEqual("ABZ", actual?.Prefix);
Assert.AreEqual(1, actual?.Index);
Assert.AreEqual(1, actual?.Revision);
}
[Test]
- public void Test8()
+ public void Test08()
{
Assert.IsTrue(Identity.TryParse("TOPFTP0000123-12", out var actual));
Assert.AreEqual("TOPFTP", actual.Prefix);
@@ -59,7 +59,7 @@ namespace TestProject1
}
[Test]
- public void Test9()
+ public void Test09()
{
Assert.IsTrue(Identity.TryParse("WPR1000023-12", out var actual));
Assert.AreEqual("WPR", actual.Prefix);
@@ -77,6 +77,6 @@ namespace TestProject1
Assert.IsFalse(Identity.TryParse("NCL0000000-1", out _));
Assert.IsFalse(Identity.TryParse("Nc0000001-1", out _));
Assert.IsFalse(Identity.TryParse("0000001-1", out _));
- }
+ }
}
}
\ No newline at end of file