StringComparisonCompiler 1.0.0
dotnet add package StringComparisonCompiler --version 1.0.0
NuGet\Install-Package StringComparisonCompiler -Version 1.0.0
<PackageReference Include="StringComparisonCompiler" Version="1.0.0" />
<PackageVersion Include="StringComparisonCompiler" Version="1.0.0" />
<PackageReference Include="StringComparisonCompiler" />
paket add StringComparisonCompiler --version 1.0.0
#r "nuget: StringComparisonCompiler, 1.0.0"
#:package StringComparisonCompiler@1.0.0
#addin nuget:?package=StringComparisonCompiler&version=1.0.0
#tool nuget:?package=StringComparisonCompiler&version=1.0.0
About
StringComparisonCompiler is an optimizing compiler for string comparison. This replaces if/while comparisons, which can be performantly slow, with an dynamically compiled unrolled comparison. Case insensitive compares are exceptionally more performant.
The slow pattern:
while (inputString) {
case "foo": ...
case "bar": ...
case "baz": ...
}
The code StringComparisonCompiler generates (returns matching index, or -1):
if (s.Length != 3) {
return -1;
}
switch (s[0]) {
case 'f': {
return (s[1] == 'o' && s[2] == 'o')
? (0)
: (-1);
break;
}
case 'b': {
switch (s[1]) {
case 'a': {
switch (s[2]) {
case 'r': {
return 1;
break;
}
case 'z': {
return 2;
break;
}
}
break;
}
}
break;
}
}
return -1;
Usage
Basic usage with array input returning found index:
var arr = new[] { "foo", "bar", "baz" };
var compiled = StringComparisonCompiler.Compile(arr);
Assert.AreEqual(0, compiled("foo"));
Assert.AreEqual(1, compiled("bar"));
Assert.AreEqual(2, compiled("baz"));
Assert.AreEqual(-1, compiled("Not found"));
CompileSpan can be called to compile a function that accepts ReadOnlySpan<char> but note that there is a performance
penalty for using ReadOnlySpan<char> due non-removable index checks (theory).
Case insensitivity can be set by passing Compile a StringComparison.
Enums can also be used and returned. The System.ComponentModel.Description attribute can be used to map the enum entry
to a different input.
public enum Foobar {
Default,
[Description("Renamed Entry")]
Foo,
Bar,
Baz,
}
public void Test()
{
var compiled = StringComparisonCompiler<Foobar>.Compile();
Assert.AreEqual(Foobar.Default, compiled("Default"));
Assert.AreEqual(Foobar.Foo, compiled("Renamed Entry"));
Assert.AreEqual(Foobar.Bar, compiled("Bar"));
Assert.AreEqual(Foobar.Baz, compiled("Baz"));
Assert.AreEqual(Foobar.Default, compiled("Foo"));
Assert.AreEqual(Foobar.Default, compiled("Foobar"));
Assert.AreEqual(Foobar.Default, compiled("Not a realy entry!"));
}
Future development
Compile time code generation would be better for non-dynamic inputs such as enums, as it doesn't consume runtime CPU.
Linq Expressions sadly does not allow for "unsafe" code, which makes the performs of ReadOnlySpan<char> extremely poor, and prevents folding long single path runs in strings down to short, int, long comparisons. It's very possible even when it's not a folded path, that doing larger comparisons are better even if they don't merge paths.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 is compatible. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Framework | net471 is compatible. net472 was computed. net48 was computed. net481 was computed. |
-
.NETFramework 4.7.1
- System.Memory (>= 4.5.4)
-
net5.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 561 | 9/19/2021 |