Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions src/Fastenshtein/AutoCompleteLevenshtein.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Fastenshtein
using System;

namespace Fastenshtein
{
/// <summary>
/// Measures the difference between two strings.
Expand All @@ -14,15 +16,26 @@ public static class AutoCompleteLevenshtein
/// <returns>0 exact match less a positive value, lower the value the best match</returns>
public static int Distance(string value1, string value2)
{
if (value1.Length == 0)
return Distance(value1.AsSpan(), value2.AsSpan());
}

/// <summary>
/// Compares the two spans of characters and returns a measure of their summarily with 0 being an exact match.
/// </summary>
/// <param name="value1">the incomplete value entered by the user</param>
/// <param name="value2">the value to compare value1 against</param>
/// <returns>0 exact match less a positive value, lower the value the best match</returns>
public static unsafe int Distance(ReadOnlySpan<char> value1, ReadOnlySpan<char> value2)
{
if (value1.IsEmpty)
{
return 0;
}

int[] costs = new int[value1.Length];
int* costs = stackalloc int[value1.Length];

// Add indexing for insertion to first row
for (int i = 0; i < costs.Length;)
for (int i = 0; i < value1.Length;)
{
costs[i] = ++i;
}
Expand Down Expand Up @@ -69,7 +82,7 @@ public static int Distance(string value1, string value2)
}
}

return costs[costs.Length - 1];
return costs[value1.Length - 1];
}
}
}
13 changes: 13 additions & 0 deletions src/Fastenshtein/Fastenshtein.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@
</None>
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.0' ">
<PackageReference Include="System.Memory" Version="4.4.0-preview1-25305-02" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="System.Memory" Version="4.5.5" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net452' ">
<PackageReference Include="System.Memory" Version="4.5.5" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
Expand All @@ -56,6 +68,7 @@
<PropertyGroup>
<IsAotCompatible Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">true</IsAotCompatible>
<Nullable Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net6.0'))">enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
Expand Down
20 changes: 16 additions & 4 deletions src/Fastenshtein/Levenshtein.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Fastenshtein
using System;

namespace Fastenshtein
{
/// <summary>
/// Measures the difference between two strings.
Expand All @@ -7,7 +9,7 @@
public partial class Levenshtein
{
/*
* WARRING this class is performance critical (Speed).
* WARNING this class is performance critical (Speed).
*/

private readonly string _storedValue;
Expand All @@ -30,19 +32,29 @@ public Levenshtein(string value)
public int StoredLength => _storedValue.Length;

/// <summary>
/// Compares a value to the stored value.
/// Compares a value to the stored value.
/// Not thread safe.
/// </summary>
/// <returns>Difference. 0 complete match.</returns>
public int DistanceFrom(string value)
{
return DistanceFrom(value.AsSpan());
}

/// <summary>
/// Compares a value to the stored value.
/// Not thread safe.
/// </summary>
/// <returns>Difference. 0 complete match.</returns>
public int DistanceFrom(ReadOnlySpan<char> value)
{
// copying to local variables allows JIT to remove bounds checks, as it understands they can not change
var costs = _costs;
var storedValue = _storedValue;

if (costs.Length == 0
// this will never be ture, however it allows the JIT to remove a bounds check
|| costs.Length != storedValue.Length)
|| costs.Length != storedValue.Length)
{
return value.Length;
}
Expand Down
23 changes: 18 additions & 5 deletions src/Fastenshtein/StaticLevenshtein.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Fastenshtein
using System;

namespace Fastenshtein
{
/// <summary>
/// Measures the difference between two strings.
Expand All @@ -7,21 +9,32 @@
public partial class Levenshtein
{
/// <summary>
/// Compares the two values to find the minimum Levenshtein distance.
/// Compares the two values to find the minimum Levenshtein distance.
/// Thread safe.
/// </summary>
/// <returns>Difference. 0 complete match.</returns>
public static int Distance(string value1, string value2)
{
return Distance(value1.AsSpan(), value2.AsSpan());
}

/// <summary>
/// Compares the two values to find the minimum Levenshtein distance.
/// Thread safe.
/// </summary>
/// <returns>Difference. 0 complete match.</returns>
public static unsafe int Distance(ReadOnlySpan<char> value1, ReadOnlySpan<char> value2)
{
if (value2.Length == 0)
{
return value1.Length;
}

int[] costs = new int[value2.Length];
int costsLength = value2.Length;
int* costs = stackalloc int[costsLength];

// Add indexing for insertion to first row
for (int i = 0; i < costs.Length;)
for (int i = 0; i < costsLength;)
{
costs[i] = ++i;
}
Expand Down Expand Up @@ -66,7 +79,7 @@ public static int Distance(string value1, string value2)
}
}

return costs[costs.Length - 1];
return costs[costsLength - 1];
}
}
}