From 3c3b9dd7ed61b4d8ec3e586fe0378d39c621daca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Holger=20B=C3=B6rchers?= Date: Sun, 14 Jun 2020 21:48:39 +0200 Subject: [PATCH] initial commit --- .idea/.idea.Benchmark/.idea/.gitignore | 13 +++ .idea/.idea.Benchmark/.idea/encodings.xml | 4 + .idea/.idea.Benchmark/.idea/indexLayout.xml | 8 ++ .idea/.idea.Benchmark/.idea/misc.xml | 6 + .idea/.idea.Benchmark/riderModule.iml | 19 ++++ .vscode/launch.json | 27 +++++ .vscode/tasks.json | 42 +++++++ Benchmark.csproj | 24 ++++ Benchmark.sln | 48 ++++++++ Identity.cs | 67 +++++++++++ IdentityParser.cs | 30 +++++ Program.cs | 13 +++ TestProject1/TestProject1.csproj | 19 ++++ TestProject1/UnitTest1.cs | 82 ++++++++++++++ TrailingNumberFromString.cs | 118 ++++++++++++++++++++ 15 files changed, 520 insertions(+) create mode 100644 .idea/.idea.Benchmark/.idea/.gitignore create mode 100644 .idea/.idea.Benchmark/.idea/encodings.xml create mode 100644 .idea/.idea.Benchmark/.idea/indexLayout.xml create mode 100644 .idea/.idea.Benchmark/.idea/misc.xml create mode 100644 .idea/.idea.Benchmark/riderModule.iml create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 Benchmark.csproj create mode 100644 Benchmark.sln create mode 100644 Identity.cs create mode 100644 IdentityParser.cs create mode 100644 Program.cs create mode 100644 TestProject1/TestProject1.csproj create mode 100644 TestProject1/UnitTest1.cs create mode 100644 TrailingNumberFromString.cs diff --git a/.idea/.idea.Benchmark/.idea/.gitignore b/.idea/.idea.Benchmark/.idea/.gitignore new file mode 100644 index 0000000..d7696ea --- /dev/null +++ b/.idea/.idea.Benchmark/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/.idea.Benchmark.iml +/projectSettingsUpdater.xml +/modules.xml +/contentModel.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/.idea.Benchmark/.idea/encodings.xml b/.idea/.idea.Benchmark/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/.idea.Benchmark/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.Benchmark/.idea/indexLayout.xml b/.idea/.idea.Benchmark/.idea/indexLayout.xml new file mode 100644 index 0000000..27ba142 --- /dev/null +++ b/.idea/.idea.Benchmark/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.Benchmark/.idea/misc.xml b/.idea/.idea.Benchmark/.idea/misc.xml new file mode 100644 index 0000000..28a804d --- /dev/null +++ b/.idea/.idea.Benchmark/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/.idea.Benchmark/riderModule.iml b/.idea/.idea.Benchmark/riderModule.iml new file mode 100644 index 0000000..2cac41e --- /dev/null +++ b/.idea/.idea.Benchmark/riderModule.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..0a08bc7 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,27 @@ +{ + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "version": "0.2.0", + "configurations": [ + { + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/bin/Debug/netcoreapp3.1/Benchmark.dll", + "args": [], + "cwd": "${workspaceFolder}", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "internalConsole", + "stopAtEntry": false + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processId": "${command:pickProcess}" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..3c8a7cc --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/Benchmark.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/Benchmark.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "${workspaceFolder}/Benchmark.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/Benchmark.csproj b/Benchmark.csproj new file mode 100644 index 0000000..b1a51fc --- /dev/null +++ b/Benchmark.csproj @@ -0,0 +1,24 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + + + + + + + + + + diff --git a/Benchmark.sln b/Benchmark.sln new file mode 100644 index 0000000..464144b --- /dev/null +++ b/Benchmark.sln @@ -0,0 +1,48 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmark", "Benchmark.csproj", "{994B1E75-4E3A-4A11-8363-FFB5FC759A5B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProject1", "TestProject1\TestProject1.csproj", "{C6BD6A51-7394-4CDD-962C-2C39AC2D846C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {994B1E75-4E3A-4A11-8363-FFB5FC759A5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {994B1E75-4E3A-4A11-8363-FFB5FC759A5B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {994B1E75-4E3A-4A11-8363-FFB5FC759A5B}.Debug|x64.ActiveCfg = Debug|Any CPU + {994B1E75-4E3A-4A11-8363-FFB5FC759A5B}.Debug|x64.Build.0 = Debug|Any CPU + {994B1E75-4E3A-4A11-8363-FFB5FC759A5B}.Debug|x86.ActiveCfg = Debug|Any CPU + {994B1E75-4E3A-4A11-8363-FFB5FC759A5B}.Debug|x86.Build.0 = Debug|Any CPU + {994B1E75-4E3A-4A11-8363-FFB5FC759A5B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {994B1E75-4E3A-4A11-8363-FFB5FC759A5B}.Release|Any CPU.Build.0 = Release|Any CPU + {994B1E75-4E3A-4A11-8363-FFB5FC759A5B}.Release|x64.ActiveCfg = Release|Any CPU + {994B1E75-4E3A-4A11-8363-FFB5FC759A5B}.Release|x64.Build.0 = Release|Any CPU + {994B1E75-4E3A-4A11-8363-FFB5FC759A5B}.Release|x86.ActiveCfg = Release|Any CPU + {994B1E75-4E3A-4A11-8363-FFB5FC759A5B}.Release|x86.Build.0 = Release|Any CPU + {C6BD6A51-7394-4CDD-962C-2C39AC2D846C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6BD6A51-7394-4CDD-962C-2C39AC2D846C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6BD6A51-7394-4CDD-962C-2C39AC2D846C}.Debug|x64.ActiveCfg = Debug|Any CPU + {C6BD6A51-7394-4CDD-962C-2C39AC2D846C}.Debug|x64.Build.0 = Debug|Any CPU + {C6BD6A51-7394-4CDD-962C-2C39AC2D846C}.Debug|x86.ActiveCfg = Debug|Any CPU + {C6BD6A51-7394-4CDD-962C-2C39AC2D846C}.Debug|x86.Build.0 = Debug|Any CPU + {C6BD6A51-7394-4CDD-962C-2C39AC2D846C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6BD6A51-7394-4CDD-962C-2C39AC2D846C}.Release|Any CPU.Build.0 = Release|Any CPU + {C6BD6A51-7394-4CDD-962C-2C39AC2D846C}.Release|x64.ActiveCfg = Release|Any CPU + {C6BD6A51-7394-4CDD-962C-2C39AC2D846C}.Release|x64.Build.0 = Release|Any CPU + {C6BD6A51-7394-4CDD-962C-2C39AC2D846C}.Release|x86.ActiveCfg = Release|Any CPU + {C6BD6A51-7394-4CDD-962C-2C39AC2D846C}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/Identity.cs b/Identity.cs new file mode 100644 index 0000000..ea9deb4 --- /dev/null +++ b/Identity.cs @@ -0,0 +1,67 @@ +using System.Linq; +using System.Runtime.CompilerServices; + +namespace Benchmark +{ + public readonly struct Identity + { + public Identity(string prefix, int index, int revision) + { + Prefix = prefix; + Index = index; + Revision = revision; + } + + public string Prefix { get; } + public int Index { get; } + public int Revision { get; } + + public static bool TryParse(string value, out Identity identity) + { + identity = default; + var position = value.Length; + if (!TryGetNumber(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; + identity = new Identity(prefix, index, revision); + return true; + } + + private static bool TryGetPrefix(in string identity, ref int lastPosition, out string prefix) + { + prefix = identity.Remove(lastPosition + 1); + if (prefix.Length <= 3) return false; + return !prefix.Any(character => character < 'A' || character > 'Z'); + } + + private static bool TryGetNumber(in 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 < '1' || current > '9') break; + revision += (current - '0') * IntegerPow(10, start - currentPosition - 1); + } + + if (exactLength != null && start - (currentPosition + 1) != exactLength) return false; + return revision != default; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int IntegerPow(int x, int y) + { + if (y == 0) return 1; + var result = x; + for (var i = 1; i < y; i++) + { + result *= x; + } + + return result; + } + } +} \ No newline at end of file diff --git a/IdentityParser.cs b/IdentityParser.cs new file mode 100644 index 0000000..e6ea687 --- /dev/null +++ b/IdentityParser.cs @@ -0,0 +1,30 @@ +using System; +using System.Text.RegularExpressions; +using BenchmarkDotNet.Attributes; + +namespace Benchmark +{ + [MemoryDiagnoser] + public class IdentityParser + { + private const string TestIdentity = "ABZ0000001-1"; + private readonly Regex _regex = new Regex(@"^(\w{3,})(\d{7})-(\d+)$", RegexOptions.Compiled); + + [Benchmark] + public Identity? Parse1() + { + var match = _regex.Match(TestIdentity); + if (!match.Success) return default; + var prefix = match.Groups[1].Value; + var index = int.Parse(match.Groups[2].Value); + var revision = int.Parse(match.Groups[2].Value); + return new Identity(prefix, index, revision); + } + + [Benchmark] + public Identity? Parse2() + { + return Identity.TryParse(TestIdentity, out var identity) ? identity : default(Identity?); + } + } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..9c7b0fe --- /dev/null +++ b/Program.cs @@ -0,0 +1,13 @@ +using BenchmarkDotNet.Running; + +namespace Benchmark +{ + public class Program + { + public static void Main(string[] args) + { + //var summary = BenchmarkRunner.Run(); + var summary = BenchmarkRunner.Run(); + } + } +} diff --git a/TestProject1/TestProject1.csproj b/TestProject1/TestProject1.csproj new file mode 100644 index 0000000..9c5a28e --- /dev/null +++ b/TestProject1/TestProject1.csproj @@ -0,0 +1,19 @@ + + + + netcoreapp3.1 + + false + + + + + + + + + + + + + diff --git a/TestProject1/UnitTest1.cs b/TestProject1/UnitTest1.cs new file mode 100644 index 0000000..692ccf1 --- /dev/null +++ b/TestProject1/UnitTest1.cs @@ -0,0 +1,82 @@ +using Benchmark; +using NUnit.Framework; + +namespace TestProject1 +{ + public class Tests + { + [SetUp] + public void Setup() + { + } + + [Test] + public void Test3() + { + var actual = new TrailingNumberFromString().GetTrailingNumberFromString3(); + Assert.AreEqual(1234, actual); + } + + [Test] + public void Test4() + { + var actual = new TrailingNumberFromString().GetTrailingNumberFromString4(); + Assert.AreEqual(1234, actual); + } + + [Test] + public void Test5() + { + var actual = new TrailingNumberFromString().GetTrailingNumberFromString5(); + Assert.AreEqual(1234, actual); + } + + [Test] + public void Test6() + { + var actual = new IdentityParser().Parse1(); + Assert.AreEqual("ABZ", actual?.Prefix); + Assert.AreEqual(1, actual?.Index); + Assert.AreEqual(1, actual?.Revision); + } + + [Test] + public void Test7() + { + var actual = new IdentityParser().Parse2(); + Assert.AreEqual("ABZ", actual?.Prefix); + Assert.AreEqual(1, actual?.Index); + Assert.AreEqual(1, actual?.Revision); + } + + [Test] + public void Test8() + { + Assert.IsTrue(Identity.TryParse("TOPFTP0000123-12", out var actual)); + Assert.AreEqual("TOPFTP", actual.Prefix); + Assert.AreEqual(123, actual.Index); + Assert.AreEqual(12, actual.Revision); + } + + [Test] + public void Test9() + { + Assert.IsTrue(Identity.TryParse("WPR0001023-12", out var actual)); + Assert.AreEqual("WPR", actual.Prefix); + Assert.AreEqual(1023, actual.Index); + Assert.AreEqual(12, actual.Revision); + } + + [Test] + public void Test10() + { + Assert.IsFalse(Identity.TryParse("WPR0001023+12", out _)); + Assert.IsFalse(Identity.TryParse("Peter", out _)); + Assert.IsFalse(Identity.TryParse("NCL1-1", out _)); + Assert.IsFalse(Identity.TryParse("NCL0000001-0", out _)); + 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 diff --git a/TrailingNumberFromString.cs b/TrailingNumberFromString.cs new file mode 100644 index 0000000..861d475 --- /dev/null +++ b/TrailingNumberFromString.cs @@ -0,0 +1,118 @@ +using System; +using System.Runtime.CompilerServices; +using System.Text.RegularExpressions; +using BenchmarkDotNet.Attributes; + +namespace Benchmark +{ + [MemoryDiagnoser] + public class TrailingNumberFromString + { + private readonly Regex _regex = new Regex(@"^\d$", RegexOptions.Compiled); + + [Benchmark] + public int? GetTrailingNumberFromString1() + { + const string foo = "Test1234"; + string sValue = null; + + for (var i = foo.Length - 1; i >= 0; i--) + { + var regex = new Regex(@"^\d$"); + + if (regex.IsMatch(foo[i].ToString())) + sValue = foo[i] + sValue; + else + break; + } + + if (sValue != null) + return Convert.ToInt32(sValue); + + return null; + } + + [Benchmark] + public int? GetTrailingNumberFromString2() + { + const string foo = "Test1234"; + string sValue = null; + + for (var i = foo.Length - 1; i >= 0; i--) + { + if (_regex.IsMatch(foo[i].ToString())) + sValue = foo[i] + sValue; + else + break; + } + if (sValue != null) + return Convert.ToInt32(sValue); + + return null; + } + + [Benchmark] + public int? GetTrailingNumberFromString3() + { + const string foo = "Test1234"; + var result = 0; + + for (var i = foo.Length - 1; i >= 0; i--) + { + if (foo[i] >= 48 && foo[i] <= 58) + { + var value = foo[i] - 48; + result += value * (int) Math.Pow(10, foo.Length - i - 1); + continue; + } + + break; + } + + return result; + } + + [Benchmark] + public int? GetTrailingNumberFromString4() + { + const string foo = "Test1234"; + var result = 0; + + for (var i = foo.Length - 1; i >= 0; i--) + { + if (foo[i] >= 48 && foo[i] <= 58) + { + var value = foo[i] - 48; + result += value * IntegerPow(10, foo.Length - i - 1); + continue; + } + + break; + } + + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int IntegerPow(int x, int y) + { + if (y == 0) return 1; + var result = x; + for (var i = 1; i < y; i++) + { + result *= x; + } + + return result; + } + + [Benchmark] + public int? GetTrailingNumberFromString5() + { + const string foo = "Test1234"; + var regex = new Regex(@"\d+$"); + var match = regex.Match(foo); + return match.Success && int.TryParse(match.Value, out var result) ? result : default(int?); + } + } +} \ No newline at end of file