initial commit

This commit is contained in:
Holger Börchers 2020-06-14 21:48:39 +02:00
parent 924d32929b
commit 3c3b9dd7ed
15 changed files with 520 additions and 0 deletions

13
.idea/.idea.Benchmark/.idea/.gitignore generated vendored Normal file
View File

@ -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/

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ContentModelUserStore">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

6
.idea/.idea.Benchmark/.idea/misc.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>

19
.idea/.idea.Benchmark/riderModule.iml generated Normal file
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="RIDER_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$USER_HOME$/.nuget/packages/microsoft.diagnostics.tracing.traceevent/2.0.49/lib/native/amd64" />
<content url="file://$USER_HOME$/.nuget/packages/microsoft.diagnostics.tracing.traceevent/2.0.49/lib/native/x86" />
<content url="file://$USER_HOME$/.nuget/packages/microsoft.diagnostics.tracing.traceevent/2.0.49/lib/netstandard1.6/Dia2Lib.dll" />
<content url="file://$USER_HOME$/.nuget/packages/microsoft.diagnostics.tracing.traceevent/2.0.49/lib/netstandard1.6/OSExtensions.dll" />
<content url="file://$USER_HOME$/.nuget/packages/microsoft.diagnostics.tracing.traceevent/2.0.49/lib/netstandard1.6/TraceReloggerLib.dll" />
<content url="file://$USER_HOME$/.nuget/packages/microsoft.net.test.sdk/16.4.0/build/netcoreapp2.1" />
<content url="file://$USER_HOME$/.nuget/packages/microsoft.testplatform.testhost/16.4.0/build/netcoreapp2.1/x64/testhost.dll" />
<content url="file://$USER_HOME$/.nuget/packages/microsoft.testplatform.testhost/16.4.0/build/netcoreapp2.1/x64/testhost.exe" />
<content url="file://$USER_HOME$/.nuget/packages/nunit3testadapter/3.15.1/build/netcoreapp2.0/NUnit3.TestAdapter.dll" />
<content url="file://$USER_HOME$/.nuget/packages/nunit3testadapter/3.15.1/build/netcoreapp2.0/NUnit3.TestAdapter.pdb" />
<content url="file://$USER_HOME$/.nuget/packages/nunit3testadapter/3.15.1/build/netcoreapp2.0/nunit.engine.api.dll" />
<content url="file://$USER_HOME$/.nuget/packages/nunit3testadapter/3.15.1/build/netcoreapp2.0/nunit.engine.dll" />
<content url="file://$MODULE_DIR$/../.." />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

27
.vscode/launch.json vendored Normal file
View File

@ -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}"
}
]
}

42
.vscode/tasks.json vendored Normal file
View File

@ -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"
}
]
}

24
Benchmark.csproj Normal file
View File

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
</ItemGroup>
<ItemGroup>
<Compile Remove="TestProject1\**" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="TestProject1\**" />
</ItemGroup>
<ItemGroup>
<None Remove="TestProject1\**" />
</ItemGroup>
</Project>

48
Benchmark.sln Normal file
View File

@ -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

67
Identity.cs Normal file
View File

@ -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;
}
}
}

30
IdentityParser.cs Normal file
View File

@ -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?);
}
}
}

13
Program.cs Normal file
View File

@ -0,0 +1,13 @@
using BenchmarkDotNet.Running;
namespace Benchmark
{
public class Program
{
public static void Main(string[] args)
{
//var summary = BenchmarkRunner.Run<TrailingNumberFromString>();
var summary = BenchmarkRunner.Run<IdentityParser>();
}
}
}

View File

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="nunit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Benchmark.csproj" />
</ItemGroup>
</Project>

82
TestProject1/UnitTest1.cs Normal file
View File

@ -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 _));
}
}
}

118
TrailingNumberFromString.cs Normal file
View File

@ -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?);
}
}
}