From 05c931180ad8fce6ae2abc1a3d3e4ebfe26772a6 Mon Sep 17 00:00:00 2001 From: Verner Fortelius Date: Sat, 24 Feb 2024 23:26:26 +0200 Subject: [PATCH] memory usage improvements - add console app for testinng allocations - reduce allocations in various places - some refactoring and cleanup - bump version --- ConsoleTester/.config/dotnet-tools.json | 12 + ConsoleTester/ConsoleTester.csproj | 13 + ConsoleTester/Program.cs | 29 + .../BenchmarkFuzzySearch.cs | 30 +- .../FuzzySearchNet.Benchmark.csproj | 2 +- FuzzySearchNet.Benchmark/Program.cs | 69 +- FuzzySearchNet.Benchmark/packages.lock.json | 1092 +++-------------- .../FuzzySearchNet.Tests.csproj | 14 +- .../FuzzySearchSubstitutionsOnlyTests.cs | 28 + FuzzySearchNet.Tests/packages.lock.json | 499 +------- FuzzySearchNet.sln | 8 +- FuzzySearchNet/FuzzySearchNet.csproj | 6 +- FuzzySearchNet/src/CandidateMatch.cs | 12 - FuzzySearchNet/src/FuzzySearchLevenshtein.cs | 176 +-- FuzzySearchNet/src/MatchResultValue.cs | 12 + FuzzySearchNet/src/Utils.cs | 103 +- README.md | 5 + 17 files changed, 450 insertions(+), 1660 deletions(-) create mode 100644 ConsoleTester/.config/dotnet-tools.json create mode 100644 ConsoleTester/ConsoleTester.csproj create mode 100644 ConsoleTester/Program.cs create mode 100644 FuzzySearchNet/src/MatchResultValue.cs diff --git a/ConsoleTester/.config/dotnet-tools.json b/ConsoleTester/.config/dotnet-tools.json new file mode 100644 index 0000000..f4a5dda --- /dev/null +++ b/ConsoleTester/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-counters": { + "version": "8.0.452401", + "commands": [ + "dotnet-counters" + ] + } + } +} \ No newline at end of file diff --git a/ConsoleTester/ConsoleTester.csproj b/ConsoleTester/ConsoleTester.csproj new file mode 100644 index 0000000..98b02f5 --- /dev/null +++ b/ConsoleTester/ConsoleTester.csproj @@ -0,0 +1,13 @@ + + + + Exe + net6.0 + enable + enable + + + + + + diff --git a/ConsoleTester/Program.cs b/ConsoleTester/Program.cs new file mode 100644 index 0000000..ec36998 --- /dev/null +++ b/ConsoleTester/Program.cs @@ -0,0 +1,29 @@ +using System.Text; +using FuzzySearchNet; + +// Console.WriteLine("Press enter to begin"); +// Console.ReadLine(); + +//const string term = "foo"; +const string term2 = "fooo--foo-----fo"; +const string text = "foo-----fo--foo-f--fooo--foo-----fo--foo-f--fooo--foo-----fo--foo-f--fooo--foo-----fo--foo-f--fooo--foo-----fo--foo-f--fooo--foo-----fo--foo-f--fooo--foo-----fo--foo-f--fooo--foo-----fo--foo-f--fooo--foo-----fo--foo-f--fooo--"; + +var count = 100000; + +var stream = new MemoryStream(Encoding.UTF8.GetBytes(text)); + +Console.WriteLine($"Running fuzzy search with count {count}"); +for (int i = 0; i < count; i++) +{ + + await foreach (var _ in FuzzySearch.FindLevenshteinAsync(term2, stream, new FuzzySearchOptions(3), leaveOpen: true)) + { + + } + stream.Position = 0; +} + +// for (int i = 0; i < count; i++) +// { +// _ = FuzzySearch.FindLevenshtein(term2, text, new FuzzySearchOptions(3)).ToList(); +// } \ No newline at end of file diff --git a/FuzzySearchNet.Benchmark/BenchmarkFuzzySearch.cs b/FuzzySearchNet.Benchmark/BenchmarkFuzzySearch.cs index 9f36fcf..0fd571f 100644 --- a/FuzzySearchNet.Benchmark/BenchmarkFuzzySearch.cs +++ b/FuzzySearchNet.Benchmark/BenchmarkFuzzySearch.cs @@ -1,4 +1,5 @@ -using BenchmarkDotNet.Attributes; +using System.Text; +using BenchmarkDotNet.Attributes; namespace FuzzySearchNet.Benchmark; @@ -8,15 +9,20 @@ public class BenchmarkFuzzySearch private const string term2 = "fooo--foo-----fo"; private const string text = "foo-----fo--foo-f--fooo--foo-----fo--foo-f--fooo--foo-----fo--foo-f--fooo--foo-----fo--foo-f--fooo--foo-----fo--foo-f--fooo--foo-----fo--foo-f--fooo--foo-----fo--foo-f--fooo--foo-----fo--foo-f--fooo--foo-----fo--foo-f--fooo--"; - //[Benchmark] - //public void SubstitutionOnlyBufferingShort() => FuzzySearch.FindSubstitutionsOnlyBuffering(term, text, 1); + public static readonly MemoryStream textStream = new MemoryStream(Encoding.UTF8.GetBytes(text)); - //[Benchmark] - //public void SubstitutionOnlyBufferingLong() => FuzzySearch.FindSubstitutionsOnlyBuffering(term2, text, 1); + [Benchmark] + public void SubstitutionOnlyShort() => FuzzySearch.FindSubstitutionsOnly(term, text, 1); + + [Benchmark] + public void SubstitutionOnlyLong() => FuzzySearch.FindSubstitutionsOnly(term2, text, 1); + [Benchmark] + public void SubstitutionOnlyShor_3_distance() => FuzzySearch.FindSubstitutionsOnly(term, text, 3); + + [Benchmark] + public void SubstitutionOnlyLong_3_distance() => FuzzySearch.FindSubstitutionsOnly(term2, text, 3); - //[Benchmark] - //public void SubstitutionOnlyBufferingLong3distance() => FuzzySearch.FindSubstitutionsOnlyBuffering(term2, text, 3); [Benchmark] @@ -24,4 +30,14 @@ public void LevenshteinLong() { _ = FuzzySearch.FindLevenshtein(term2, text, new FuzzySearchOptions(3)).ToList(); } + + [Benchmark] + public async Task LevenshteinLongAsync() + { + var stream = new MemoryStream(Encoding.UTF8.GetBytes(text)); // this is not ideal, but the effect of doing this here is basically within the stddev of the benchmark + await foreach (var _ in FuzzySearch.FindLevenshteinAsync(term2, stream, new FuzzySearchOptions(3))) + { + + } + } } \ No newline at end of file diff --git a/FuzzySearchNet.Benchmark/FuzzySearchNet.Benchmark.csproj b/FuzzySearchNet.Benchmark/FuzzySearchNet.Benchmark.csproj index 9882736..1974ae0 100644 --- a/FuzzySearchNet.Benchmark/FuzzySearchNet.Benchmark.csproj +++ b/FuzzySearchNet.Benchmark/FuzzySearchNet.Benchmark.csproj @@ -13,7 +13,7 @@ - + diff --git a/FuzzySearchNet.Benchmark/Program.cs b/FuzzySearchNet.Benchmark/Program.cs index b7e8f89..eb14634 100644 --- a/FuzzySearchNet.Benchmark/Program.cs +++ b/FuzzySearchNet.Benchmark/Program.cs @@ -1,71 +1,4 @@ using BenchmarkDotNet.Running; using FuzzySearchNet.Benchmark; -var summary = BenchmarkRunner.Run(); - - - -/* - * - - - -| Method | Mean | Error | StdDev | -|----------------- |---------:|----------:|----------:| -| SubstitutionOnly | 4.564 us | 0.0905 us | 0.2551 us | - - - - - - -| Method | Mean | Error | StdDev | -|----------------- |---------:|---------:|---------:| -| SubstitutionOnly | 18.98 us | 0.373 us | 0.510 us | - - - - - - - - -| Method | Mean | Error | StdDev | -|--------------------------------------- |----------:|----------:|----------:| -| SubstitutionOnlyBufferingShort | 3.704 us | 0.0740 us | 0.0909 us | -| SubstitutionOnlyBufferingLong | 2.818 us | 0.0292 us | 0.0244 us | -| SubstitutionOnlyBufferingLong3distance | 4.396 us | 0.0501 us | 0.0492 us | - - - -| Method | Mean | Error | StdDev | -|--------------------------------------- |---------:|----------:|----------:| -| SubstitutionOnlyBufferingShort | 2.628 us | 0.0389 us | 0.0570 us | -| SubstitutionOnlyBufferingLong | 2.031 us | 0.0404 us | 0.0580 us | -| SubstitutionOnlyBufferingLong3distance | 2.808 us | 0.0548 us | 0.0988 us | - - -| Method | Mean | Error | StdDev | Median | -|--------------------------------------- |---------:|----------:|----------:|---------:| -| SubstitutionOnlyBufferingShort | 2.434 us | 0.0264 us | 0.0220 us | 2.438 us | -| SubstitutionOnlyBufferingLong | 1.843 us | 0.0366 us | 0.0740 us | 1.810 us | -| SubstitutionOnlyBufferingLong3distance | 2.471 us | 0.0494 us | 0.1105 us | 2.468 us | - - - -| Method | Mean | Error | StdDev | Median | -|--------------------------------------- |---------:|----------:|----------:|---------:| -| SubstitutionOnlyBufferingShort | 2.582 us | 0.0515 us | 0.1233 us | 2.543 us | -| SubstitutionOnlyBufferingLong | 2.053 us | 0.0407 us | 0.0743 us | 2.019 us | -| SubstitutionOnlyBufferingLong3distance | 2.819 us | 0.0559 us | 0.1285 us | 2.782 us | - -| Method | Mean | Error | StdDev | Median | -|--------------------------------------- |---------:|----------:|----------:|---------:| -| SubstitutionOnlyBufferingShort | 2.690 us | 0.0536 us | 0.1539 us | 2.720 us | -| SubstitutionOnlyBufferingLong | 2.042 us | 0.0405 us | 0.1074 us | 2.001 us | -| SubstitutionOnlyBufferingLong3distance | 2.824 us | 0.0563 us | 0.1412 us | 2.754 us | - - - - -*/ \ No newline at end of file +_ = BenchmarkRunner.Run(); diff --git a/FuzzySearchNet.Benchmark/packages.lock.json b/FuzzySearchNet.Benchmark/packages.lock.json index 6906f74..a8ad1f7 100644 --- a/FuzzySearchNet.Benchmark/packages.lock.json +++ b/FuzzySearchNet.Benchmark/packages.lock.json @@ -4,1071 +4,253 @@ "net6.0": { "BenchmarkDotNet": { "type": "Direct", - "requested": "[0.13.1, )", - "resolved": "0.13.1", - "contentHash": "LWR6kL3MWc4ByzSrqi6nccbO4UT5pySiB5h9L2LSHoqVdHySTbtLYYulz3atWhPyhtIQIMz6kQjvuBjFM03zkA==", - "dependencies": { - "BenchmarkDotNet.Annotations": "0.13.1", - "CommandLineParser": "2.4.3", - "Iced": "1.8.0", - "Microsoft.CodeAnalysis.CSharp": "2.10.0", - "Microsoft.Diagnostics.NETCore.Client": "0.2.61701", - "Microsoft.Diagnostics.Runtime": "1.1.126102", - "Microsoft.Diagnostics.Tracing.TraceEvent": "2.0.61", - "Microsoft.DotNet.PlatformAbstractions": "2.1.0", - "Microsoft.Win32.Registry": "4.5.0", - "Perfolizer": "0.2.1", - "System.Management": "4.5.0", - "System.Reflection.Emit": "4.3.0", - "System.Reflection.Emit.Lightweight": "4.3.0", - "System.Threading.Tasks.Extensions": "4.5.2", - "System.ValueTuple": "4.5.0" + "requested": "[0.13.10, )", + "resolved": "0.13.10", + "contentHash": "p/LrTtR5TlwhZIvy2hG9VzTFWEDPS90r3QP9Q9pL4/B1iXzC/JNrpYyCWW3Xeg4vuiq/qV8hvJkJmT1sj+5LSw==", + "dependencies": { + "BenchmarkDotNet.Annotations": "0.13.10", + "CommandLineParser": "2.9.1", + "Gee.External.Capstone": "2.3.0", + "Iced": "1.17.0", + "Microsoft.CodeAnalysis.CSharp": "4.1.0", + "Microsoft.Diagnostics.Runtime": "2.2.332302", + "Microsoft.Diagnostics.Tracing.TraceEvent": "3.0.2", + "Microsoft.DotNet.PlatformAbstractions": "3.1.6", + "Perfolizer": "[0.2.1]", + "System.Management": "5.0.0" } }, "BenchmarkDotNet.Annotations": { "type": "Transitive", - "resolved": "0.13.1", - "contentHash": "OvHMw/GYfdrrJAM28zOXQ94kdv1s0s92ZrbkH+/79I557ONPEH/urMF8iNKuYYgLsziC4isw233L3GKq6Twe/A==" + "resolved": "0.13.10", + "contentHash": "abYKp+P5NBuam7q0w7AFgOYF3nqAvKBw6MLq96Kjk1WdaRDNpgBc6uCgOP4pVIH/g0IF9d4ubnFLBwiJuIAHMw==" }, "CommandLineParser": { "type": "Transitive", - "resolved": "2.4.3", - "contentHash": "U2FC9Y8NyIxxU6MpFFdWWu1xwiqz/61v/Doou7kmVjpeIEMLWyiNNkzNlSE84kyJ0O1LKApuEj5z48Ow0Hi4OQ==" + "resolved": "2.9.1", + "contentHash": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==" }, - "Iced": { - "type": "Transitive", - "resolved": "1.8.0", - "contentHash": "KQqoTZg3wf+eqG8ztGqlz9TozC/Dw/jnN82JkIRGZXTg/by0aPiQIMGb+b7hvvkOLnmCuWr3Ghr0mA2I+ASX1A==" - }, - "Microsoft.CodeAnalysis.Analyzers": { + "Gee.External.Capstone": { "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "VsT6gg2SPeToP8SK7PEcsH6Ftryb7aOqnXh9xg11zBeov05+63gP3k/TvrR+v85XIa8Nn0y3+qNl4M+qzNLBfw==" + "resolved": "2.3.0", + "contentHash": "2ap/rYmjtzCOT8hxrnEW/QeiOt+paD8iRrIcdKX0cxVwWLFa1e+JDBNeECakmccXrSFeBQuu5AV8SNkipFMMMw==" }, - "Microsoft.CodeAnalysis.Common": { - "type": "Transitive", - "resolved": "2.10.0", - "contentHash": "w57ebW3QIRFPoFFX6GCa6eF2FmuHYaWEJ/sMMHq+PBnHB51dEzLIoAQft1Byqe5nrSo4UUV6v4tad8fkTrKl8w==", - "dependencies": { - "Microsoft.CodeAnalysis.Analyzers": "2.6.1", - "System.AppContext": "4.3.0", - "System.Collections": "4.3.0", - "System.Collections.Concurrent": "4.3.0", - "System.Collections.Immutable": "1.5.0", - "System.Console": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Diagnostics.FileVersionInfo": "4.3.0", - "System.Diagnostics.StackTrace": "4.3.0", - "System.Diagnostics.Tools": "4.3.0", - "System.Dynamic.Runtime": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO.Compression": "4.3.0", - "System.IO.FileSystem": "4.3.0", - "System.IO.FileSystem.Primitives": "4.3.0", - "System.Linq": "4.3.0", - "System.Linq.Expressions": "4.3.0", - "System.Reflection": "4.3.0", - "System.Reflection.Metadata": "1.6.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Runtime.Numerics": "4.3.0", - "System.Security.Cryptography.Algorithms": "4.3.0", - "System.Security.Cryptography.Encoding": "4.3.0", - "System.Security.Cryptography.X509Certificates": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Text.Encoding.CodePages": "4.3.0", - "System.Text.Encoding.Extensions": "4.3.0", - "System.Threading": "4.3.0", - "System.Threading.Tasks": "4.3.0", - "System.Threading.Tasks.Extensions": "4.3.0", - "System.Threading.Tasks.Parallel": "4.3.0", - "System.Threading.Thread": "4.3.0", - "System.ValueTuple": "4.3.0", - "System.Xml.ReaderWriter": "4.3.0", - "System.Xml.XDocument": "4.3.0", - "System.Xml.XPath.XDocument": "4.3.0", - "System.Xml.XmlDocument": "4.3.0" - } - }, - "Microsoft.CodeAnalysis.CSharp": { - "type": "Transitive", - "resolved": "2.10.0", - "contentHash": "bTr6j4V7G4ZPhRDUdowdtbEvXsQA4w1TYfOtXiYdv8TF7STl9ShOKtlSVzAusmeEWsZksJm9D1VSxt6XIyNB0w==", - "dependencies": { - "Microsoft.CodeAnalysis.Common": "[2.10.0]" - } - }, - "Microsoft.Diagnostics.NETCore.Client": { - "type": "Transitive", - "resolved": "0.2.61701", - "contentHash": "/whUqXLkTiUvG+vfSFd77DHHsLZW2HztZt+ACOpuvGyLKoGGN86M8cR1aYfRW6fxXF3SVGMKMswcL485SQEDuQ==" - }, - "Microsoft.Diagnostics.Runtime": { - "type": "Transitive", - "resolved": "1.1.126102", - "contentHash": "2lyoyld8bd/zSq5HJPkyXVtsSdfS30qr75V96S4nEJ/nUiUp0WfGjxnTcZXBLCqzwE0DLUR0lUcNpMp0gEtuzA==" - }, - "Microsoft.Diagnostics.Tracing.TraceEvent": { - "type": "Transitive", - "resolved": "2.0.61", - "contentHash": "czZJRJZEZbGyBauIXYfWIfVV6Nx88L55RARKmEb7ja+nmb1yI+LiROgnD1N0Fyh/RnzvUUD/J0YYMkAEBT1Z6w==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "4.5.2" - } - }, - "Microsoft.DotNet.PlatformAbstractions": { - "type": "Transitive", - "resolved": "2.1.0", - "contentHash": "9KPDwvb/hLEVXYruVHVZ8BkebC8j17DmPb56LnqRF74HqSPLjCkrlFUjOtFpQPA2DeADBRTI/e69aCfRBfrhxw==", - "dependencies": { - "System.AppContext": "4.1.0", - "System.Collections": "4.0.11", - "System.IO": "4.1.0", - "System.IO.FileSystem": "4.0.1", - "System.Reflection.TypeExtensions": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.InteropServices": "4.1.0", - "System.Runtime.InteropServices.RuntimeInformation": "4.0.0" - } - }, - "Microsoft.NETCore.Platforms": { + "Iced": { "type": "Transitive", - "resolved": "2.0.0", - "contentHash": "VdLJOCXhZaEMY7Hm2GKiULmn7IEPFE4XC5LPSfBVCUIA8YLZVh846gtfBJalsPQF2PlzdD7ecX7DZEulJ402ZQ==" + "resolved": "1.17.0", + "contentHash": "8x+HCVTl/HHTGpscH3vMBhV8sknN/muZFw9s3TsI8SA6+c43cOTCi2+jE4KsU8pNLbJ++iF2ZFcpcXHXtDglnw==" }, - "Microsoft.NETCore.Targets": { + "Microsoft.Bcl.AsyncInterfaces": { "type": "Transitive", "resolved": "1.1.0", - "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" + "contentHash": "1Am6l4Vpn3/K32daEqZI+FFr96OlZkgwK2LcT3pZ2zWubR5zTPW3/FkO1Rat9kb7oQOa4rxgl9LJHc5tspCWfg==" }, - "Microsoft.Win32.Registry": { - "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "+FWlwd//+Tt56316p00hVePBCouXyEzT86Jb3+AuRotTND0IYn0OO3obs1gnQEs/txEnt+rF2JBGLItTG+Be6A==", - "dependencies": { - "System.Security.AccessControl": "4.5.0", - "System.Security.Principal.Windows": "4.5.0" - } - }, - "Perfolizer": { - "type": "Transitive", - "resolved": "0.2.1", - "contentHash": "Dt4aCxCT8NPtWBKA8k+FsN/RezOQ2C6omNGm5o/qmYRiIwlQYF93UgFmeF1ezVNsztTnkg7P5P63AE+uNkLfrw==", - "dependencies": { - "System.Memory": "4.5.3" - } - }, - "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "HdSSp5MnJSsg08KMfZThpuLPJpPwE5hBXvHwoKWosyHHfe8Mh5WKT0ylEOf6yNzX6Ngjxe4Whkafh5q7Ymac4Q==" - }, - "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "+yH1a49wJMy8Zt4yx5RhJrxO/DBDByAiCzNwiETI+1S4mPdCu0OY4djdciC7Vssk0l22wQaDLrXxXkp+3+7bVA==" - }, - "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "c3YNH1GQJbfIPJeCnr4avseugSqPrxwIqzthYyZDN6EuOyNOzq+y2KSUfRcXauya1sF4foESTgwM5e1A8arAKw==" - }, - "runtime.native.System": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "c/qWt2LieNZIj1jGnVNsE2Kl23Ya2aSTBuXMD6V7k9KWr6l16Tqdwq+hJScEpWER9753NWC8h96PaVNY5Ld7Jw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0" - } - }, - "runtime.native.System.IO.Compression": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "INBPonS5QPEgn7naufQFXJEp3zX6L4bwHgJ/ZH78aBTpeNfQMtf7C6VrAFhlq2xxWBveIOWyFzQjJ8XzHMhdOQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0" - } - }, - "runtime.native.System.Net.Http": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "ZVuZJqnnegJhd2k/PtAbbIcZ3aZeITq3sj06oKfMBSfphW3HDmk/t4ObvbOk/JA/swGR0LNqMksAh/f7gpTROg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0" - } - }, - "runtime.native.System.Security.Cryptography.Apple": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "DloMk88juo0OuOWr56QG7MNchmafTLYWvABy36izkrLI5VledI0rq28KGs1i9wbpeT9NPQrx/wTf8U2vazqQ3Q==", - "dependencies": { - "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "4.3.0" - } - }, - "runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "NS1U+700m4KFRHR5o4vo9DSlTmlCKu/u7dtE5sUHVIPB+xpXxYQvgBgA6wEIeCz6Yfn0Z52/72WYsToCEPJnrw==", - "dependencies": { - "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", - "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", - "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", - "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", - "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", - "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", - "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", - "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", - "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0", - "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" - } - }, - "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "b3pthNgxxFcD+Pc0WSEoC0+md3MyhRS6aCEeenvNE3Fdw1HyJ18ZhRFVJJzIeR/O/jpxPboB805Ho0T3Ul7w8A==" - }, - "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "KeLz4HClKf+nFS7p/6Fi/CqyLXh81FpiGzcmuS8DGi9lUqSnZ6Es23/gv2O+1XVGfrbNmviF7CckBpavkBoIFQ==" - }, - "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "kVXCuMTrTlxq4XOOMAysuNwsXWpYeboGddNGpIgNSZmv1b6r/s/DPk0fYMB7Q5Qo4bY68o48jt4T4y5BVecbCQ==" - }, - "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "X7IdhILzr4ROXd8mI1BUCQMSHSQwelUlBjF1JyTKCjXaOGn2fB4EKBxQbCK2VjO3WaWIdlXZL3W6TiIVnrhX4g==" - }, - "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "nyFNiCk/r+VOiIqreLix8yN+q3Wga9+SE8BCgkf+2BwEKiNx6DyvFjCgkfV743/grxv8jHJ8gUK4XEQw7yzRYg==" - }, - "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "ytoewC6wGorL7KoCAvRfsgoJPJbNq+64k2SqW6JcOAebWsFUvCCYgfzQMrnpvPiEl4OrblUlhF2ji+Q1+SVLrQ==" - }, - "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "I8bKw2I8k58Wx7fMKQJn2R8lamboCAiHfHeV/pS65ScKWMMI0+wJkLYlEKvgW1D/XvSl/221clBoR2q9QNNM7A==" - }, - "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "Microsoft.CodeAnalysis.Analyzers": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "VB5cn/7OzUfzdnC8tqAIMQciVLiq2epm2NrAm1E9OjNRyG4lVhfR61SMcLizejzQP8R8Uf/0l5qOIbUEi+RdEg==" + "resolved": "3.3.3", + "contentHash": "j/rOZtLMVJjrfLRlAMckJLPW/1rze9MT1yfWqSIbUPGRu1m1P0fuo9PmqapwsmePfGB5PJrudQLvmUOAMF0DqQ==" }, - "System.AppContext": { + "Microsoft.CodeAnalysis.Common": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "fKC+rmaLfeIzUhagxY17Q9siv/sPrjjKcfNg1Ic8IlQkZLipo8ljcaZQu4VtI4Jqbzjc2VTjzGLF6WmsRXAEgA==", + "resolved": "4.1.0", + "contentHash": "bNzTyxP3iD5FPFHfVDl15Y6/wSoI7e3MeV0lOaj9igbIKTjgrmuw6LoVJ06jUNFA7+KaDC/OIsStWl/FQJz6sQ==", "dependencies": { - "System.Runtime": "4.3.0" + "Microsoft.CodeAnalysis.Analyzers": "3.3.3", + "System.Collections.Immutable": "5.0.0", + "System.Memory": "4.5.4", + "System.Reflection.Metadata": "5.0.0", + "System.Runtime.CompilerServices.Unsafe": "5.0.0", + "System.Text.Encoding.CodePages": "4.5.1", + "System.Threading.Tasks.Extensions": "4.5.4" } }, - "System.Buffers": { + "Microsoft.CodeAnalysis.CSharp": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "ratu44uTIHgeBeI0dE8DWvmXVBSo4u7ozRZZHOMmK/JPpYyo0dAfgSiHlpiObMQ5lEtEyIXA40sKRYg5J6A8uQ==", + "resolved": "4.1.0", + "contentHash": "sbu6kDGzo9bfQxuqWpeEE7I9P30bSuZEnpDz9/qz20OU6pm79Z63+/BsAzO2e/R/Q97kBrpj647wokZnEVr97w==", "dependencies": { - "System.Diagnostics.Debug": "4.3.0", - "System.Diagnostics.Tracing": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Threading": "4.3.0" + "Microsoft.CodeAnalysis.Common": "[4.1.0]" } }, - "System.CodeDom": { - "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "gqpR1EeXOuzNQWL7rOzmtdIz3CaXVjSQCiaGOs2ivjPwynKSJYm39X81fdlp7WuojZs/Z5t1k5ni7HtKQurhjw==" - }, - "System.Collections": { + "Microsoft.Diagnostics.NETCore.Client": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==", + "resolved": "0.2.251802", + "contentHash": "bqnYl6AdSeboeN4v25hSukK6Odm6/54E3Y2B8rBvgqvAW0mF8fo7XNRVE2DMOG7Rk0fiuA079QIH28+V+W1Zdg==", "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" + "Microsoft.Bcl.AsyncInterfaces": "1.1.0", + "Microsoft.Extensions.Logging": "2.1.1" } }, - "System.Collections.Concurrent": { + "Microsoft.Diagnostics.Runtime": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "ztl69Xp0Y/UXCL+3v3tEU+lIy+bvjKNUmopn1wep/a291pVPK7dxBd6T7WnlQqRog+d1a/hSsgRsmFnIBKTPLQ==", + "resolved": "2.2.332302", + "contentHash": "Hp84ivxSKIMTBzYSATxmUsm3YSXHWivcwiRRbsydGmqujMUK8BAueLN0ssAVEOkOBmh0vjUBhrq7YcroT7VCug==", "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Diagnostics.Tracing": "4.3.0", - "System.Globalization": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0", - "System.Threading.Tasks": "4.3.0" + "Microsoft.Diagnostics.NETCore.Client": "0.2.251802", + "System.Collections.Immutable": "5.0.0", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" } }, - "System.Collections.Immutable": { - "type": "Transitive", - "resolved": "1.5.0", - "contentHash": "EXKiDFsChZW0RjrZ4FYHu9aW6+P4MCgEDCklsVseRfhoO0F+dXeMSsMRAlVXIo06kGJ/zv+2w1a2uc2+kxxSaQ==" - }, - "System.Console": { + "Microsoft.Diagnostics.Tracing.TraceEvent": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "DHDrIxiqk1h03m6khKWV2X8p/uvN79rgSqpilL6uzpmSfxfU5ng8VcPtW4qsDsQDHiTv6IPV9TmD5M/vElPNLg==", + "resolved": "3.0.2", + "contentHash": "Pr7t+Z/qBe6DxCow4BmYmDycHe2MrGESaflWXRcSUI4XNGyznx1ttS+9JNOxLuBZSoBSPTKw9Dyheo01Yi6anQ==", "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.IO": "4.3.0", - "System.Runtime": "4.3.0", - "System.Text.Encoding": "4.3.0" + "System.Runtime.CompilerServices.Unsafe": "4.5.3" } }, - "System.Diagnostics.Debug": { + "Microsoft.DotNet.PlatformAbstractions": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "ZUhUOdqmaG5Jk3Xdb8xi5kIyQYAA4PnTNlHx1mu9ZY3qv4ELIdKbnL/akbGaKi2RnNUWaZsAs31rvzFdewTj2g==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } + "resolved": "3.1.6", + "contentHash": "jek4XYaQ/PGUwDKKhwR8K47Uh1189PFzMeLqO83mXrXQVIpARZCcfuDedH50YDTepBkfijCZN5U/vZi++erxtg==" }, - "System.Diagnostics.FileVersionInfo": { + "Microsoft.Extensions.Configuration": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "omCF64wzQ3Q2CeIqkD6lmmxeMZtGHUmzgFMPjfVaOsyqpR66p/JaZzManMw1s33osoAb5gqpncsjie67+yUPHQ==", + "resolved": "2.1.1", + "contentHash": "LjVKO6P2y52c5ZhTLX/w8zc5H4Y3J/LJsgqTBj49TtFq/hAtVNue/WA0F6/7GMY90xhD7K0MDZ4qpOeWXbLvzg==", "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.IO.FileSystem": "4.3.0", - "System.IO.FileSystem.Primitives": "4.3.0", - "System.Reflection.Metadata": "1.4.1", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.InteropServices": "4.3.0" + "Microsoft.Extensions.Configuration.Abstractions": "2.1.1" } }, - "System.Diagnostics.StackTrace": { + "Microsoft.Extensions.Configuration.Abstractions": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "BiHg0vgtd35/DM9jvtaC1eKRpWZxr0gcQd643ABG7GnvSlf5pOkY2uyd42mMOJoOmKvnpNj0F4tuoS1pacTwYw==", + "resolved": "2.1.1", + "contentHash": "VfuZJNa0WUshZ/+8BFZAhwFKiKuu/qOUCFntfdLpHj7vcRnsGHqd3G2Hse78DM+pgozczGM63lGPRLmy+uhUOA==", "dependencies": { - "System.IO.FileSystem": "4.3.0", - "System.Reflection": "4.3.0", - "System.Reflection.Metadata": "1.4.1", - "System.Runtime": "4.3.0" + "Microsoft.Extensions.Primitives": "2.1.1" } }, - "System.Diagnostics.Tools": { + "Microsoft.Extensions.Configuration.Binder": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "UUvkJfSYJMM6x527dJg2VyWPSRqIVB0Z7dbjHst1zmwTXz5CcXSYJFWRpuigfbO1Lf7yfZiIaEUesfnl/g5EyA==", + "resolved": "2.1.1", + "contentHash": "fcLCTS03poWE4v9tSNBr3pWn0QwGgAn1vzqHXlXgvqZeOc7LvQNzaWcKRQZTdEc3+YhQKwMsOtm3VKSA2aWQ8w==", "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" + "Microsoft.Extensions.Configuration": "2.1.1" } }, - "System.Diagnostics.Tracing": { + "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "rswfv0f/Cqkh78rA5S8eN8Neocz234+emGCtTF3lxPY96F+mmmUen6tbn0glN6PMvlKQb9bPAY5e9u7fgPTkKw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } + "resolved": "2.1.1", + "contentHash": "MgYpU5cwZohUMKKg3sbPhvGG+eAZ/59E9UwPwlrUkyXU+PGzqwZg9yyQNjhxuAWmoNoFReoemeCku50prYSGzA==" }, - "System.Dynamic.Runtime": { + "Microsoft.Extensions.Logging": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "SNVi1E/vfWUAs/WYKhE9+qlS6KqK0YVhnlT0HQtr8pMIA8YX3lwy3uPMownDwdYISBdmAF/2holEIldVp85Wag==", + "resolved": "2.1.1", + "contentHash": "hh+mkOAQDTp6XH80xJt3+wwYVzkbwYQl9XZRCz4Um0JjP/o7N9vHM3rZ6wwwtr+BBe/L6iBO2sz0px6OWBzqZQ==", "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Linq": "4.3.0", - "System.Linq.Expressions": "4.3.0", - "System.ObjectModel": "4.3.0", - "System.Reflection": "4.3.0", - "System.Reflection.Emit": "4.3.0", - "System.Reflection.Emit.ILGeneration": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Reflection.TypeExtensions": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0" + "Microsoft.Extensions.Configuration.Binder": "2.1.1", + "Microsoft.Extensions.DependencyInjection.Abstractions": "2.1.1", + "Microsoft.Extensions.Logging.Abstractions": "2.1.1", + "Microsoft.Extensions.Options": "2.1.1" } }, - "System.Globalization": { + "Microsoft.Extensions.Logging.Abstractions": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } + "resolved": "2.1.1", + "contentHash": "XRzK7ZF+O6FzdfWrlFTi1Rgj2080ZDsd46vzOjadHUB0Cz5kOvDG8vI7caa5YFrsHQpcfn0DxtjS4E46N4FZsA==" }, - "System.Globalization.Calendars": { + "Microsoft.Extensions.Options": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "GUlBtdOWT4LTV3I+9/PJW+56AnnChTaOqqTLFtdmype/L500M2LIyXgmtd9X2P2VOkmJd5c67H5SaC2QcL1bFA==", + "resolved": "2.1.1", + "contentHash": "V7lXCU78lAbzaulCGFKojcCyG8RTJicEbiBkPJjFqiqXwndEBBIehdXRMWEVU3UtzQ1yDvphiWUL9th6/4gJ7w==", "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Globalization": "4.3.0", - "System.Runtime": "4.3.0" + "Microsoft.Extensions.DependencyInjection.Abstractions": "2.1.1", + "Microsoft.Extensions.Primitives": "2.1.1" } }, - "System.IO": { + "Microsoft.Extensions.Primitives": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==", + "resolved": "2.1.1", + "contentHash": "scJ1GZNIxMmjpENh0UZ8XCQ6vzr/LzeF9WvEA51Ix2OQGAs9WPgPu8ABVUdvpKPLuor/t05gm6menJK3PwqOXg==", "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading.Tasks": "4.3.0" + "System.Memory": "4.5.1", + "System.Runtime.CompilerServices.Unsafe": "4.5.1" } }, - "System.IO.Compression": { + "Microsoft.NETCore.Platforms": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "YHndyoiV90iu4iKG115ibkhrG+S3jBm8Ap9OwoUAzO5oPDAWcr0SFwQFm0HjM8WkEZWo0zvLTyLmbvTkW1bXgg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Buffers": "4.3.0", - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0", - "System.Threading.Tasks": "4.3.0", - "runtime.native.System": "4.3.0", - "runtime.native.System.IO.Compression": "4.3.0" - } + "resolved": "5.0.0", + "contentHash": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==" }, - "System.IO.FileSystem": { + "Microsoft.Win32.Registry": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "3wEMARTnuio+ulnvi+hkRNROYwa1kylvYahhcLk4HSoVdl+xxTFVeVlYOfLwrDPImGls0mDqbMhrza8qnWPTdA==", + "resolved": "5.0.0", + "contentHash": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.IO": "4.3.0", - "System.IO.FileSystem.Primitives": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading.Tasks": "4.3.0" + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" } }, - "System.IO.FileSystem.Primitives": { + "Perfolizer": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "6QOb2XFLch7bEc4lIcJH49nJN2HV+OC3fHDgsLVsBVBk3Y4hFAnOBGzJ2lUu7CyDDFo9IBWkSsnbkT6IBwwiMw==", + "resolved": "0.2.1", + "contentHash": "Dt4aCxCT8NPtWBKA8k+FsN/RezOQ2C6omNGm5o/qmYRiIwlQYF93UgFmeF1ezVNsztTnkg7P5P63AE+uNkLfrw==", "dependencies": { - "System.Runtime": "4.3.0" + "System.Memory": "4.5.3" } }, - "System.Linq": { + "System.CodeDom": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "5DbqIUpsDp0dFftytzuMmc0oeMdQwjcP/EWxsksIz/w1TcFRkZ3yKKz0PqiYFMmEwPSWw+qNVqD7PJ889JzHbw==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0" - } + "resolved": "5.0.0", + "contentHash": "JPJArwA1kdj8qDAkY2XGjSWoYnqiM7q/3yRNkt6n28Mnn95MuEGkZXUbPBf7qc3IjwrGY5ttQon7yqHZyQJmOQ==" }, - "System.Linq.Expressions": { + "System.Collections.Immutable": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "PGKkrd2khG4CnlyJwxwwaWWiSiWFNBGlgXvJpeO0xCXrZ89ODrQ6tjEWS/kOqZ8GwEOUATtKtzp1eRgmYNfclg==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Linq": "4.3.0", - "System.ObjectModel": "4.3.0", - "System.Reflection": "4.3.0", - "System.Reflection.Emit": "4.3.0", - "System.Reflection.Emit.ILGeneration": "4.3.0", - "System.Reflection.Emit.Lightweight": "4.3.0", - "System.Reflection.Extensions": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Reflection.TypeExtensions": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0" - } + "resolved": "5.0.0", + "contentHash": "FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g==" }, "System.Management": { "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "Z6ac0qPGr3yJtwZEX1SRkhwWa0Kf5NJxx7smLboYsGrApQFECNFdqhGy252T4lrZ5Nwzhd9VQiaifndR3bfHdg==", + "resolved": "5.0.0", + "contentHash": "MF1CHaRcC+MLFdnDthv4/bKWBZnlnSpkGqa87pKukQefgEdwtb9zFW6zs0GjPp73qtpYYg4q6PEKbzJbxCpKfw==", "dependencies": { - "Microsoft.NETCore.Platforms": "2.0.0", - "Microsoft.Win32.Registry": "4.5.0", - "System.CodeDom": "4.5.0" + "Microsoft.NETCore.Platforms": "5.0.0", + "Microsoft.Win32.Registry": "5.0.0", + "System.CodeDom": "5.0.0" } }, "System.Memory": { "type": "Transitive", - "resolved": "4.5.3", - "contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA==" - }, - "System.ObjectModel": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "bdX+80eKv9bN6K4N+d77OankKHGn6CH711a6fcOpMQu2Fckp/Ft4L/kW9WznHpyR0NRAvJutzOMHNNlBGvxQzQ==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.Reflection": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.IO": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Reflection.Emit": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "228FG0jLcIwTVJyz8CLFKueVqQK36ANazUManGaJHkO0icjiIypKW7YLWLIWahyIkdh5M7mV2dJepllLyA1SKg==", - "dependencies": { - "System.IO": "4.3.0", - "System.Reflection": "4.3.0", - "System.Reflection.Emit.ILGeneration": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Reflection.Emit.ILGeneration": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "59tBslAk9733NXLrUJrwNZEzbMAcu8k344OYo+wfSVygcgZ9lgBdGIzH/nrg3LYhXceynyvTc8t5/GD4Ri0/ng==", - "dependencies": { - "System.Reflection": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Reflection.Emit.Lightweight": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "oadVHGSMsTmZsAF864QYN1t1QzZjIcuKU3l2S9cZOwDdDueNTrqq1yRj7koFfIGEnKpt6NjpL3rOzRhs4ryOgA==", - "dependencies": { - "System.Reflection": "4.3.0", - "System.Reflection.Emit.ILGeneration": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Reflection.Extensions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "rJkrJD3kBI5B712aRu4DpSIiHRtr6QlfZSQsb0hYHrDCZORXCFjQfoipo2LaMUHoT9i1B7j7MnfaEKWDFmFQNQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Reflection": "4.3.0", - "System.Runtime": "4.3.0" - } + "resolved": "4.5.4", + "contentHash": "1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==" }, "System.Reflection.Metadata": { "type": "Transitive", - "resolved": "1.6.0", - "contentHash": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ==" - }, - "System.Reflection.Primitives": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Reflection.TypeExtensions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "7u6ulLcZbyxB5Gq0nMkQttcdBTx57ibzw+4IOXEfR+sXYQoHvjW5LTLyNr8O22UIMrqYbchJQJnos4eooYzYJA==", - "dependencies": { - "System.Reflection": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Resources.ResourceManager": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Globalization": "4.3.0", - "System.Reflection": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Runtime": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0" - } + "resolved": "5.0.0", + "contentHash": "5NecZgXktdGg34rh1OenY1rFNDCI8xSjFr+Z4OU4cU06AQHUdRnIIEeWENu3Wl4YowbzkymAIMvi3WyK9U53pQ==" }, "System.Runtime.CompilerServices.Unsafe": { "type": "Transitive", - "resolved": "4.5.2", - "contentHash": "wprSFgext8cwqymChhrBLu62LMg/1u92bU+VOwyfBimSPVFXtsNqEWC92Pf9ofzJFlk4IHmJA75EDJn1b2goAQ==" - }, - "System.Runtime.Extensions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Runtime.Handles": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Runtime.InteropServices": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Reflection": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Handles": "4.3.0" - } - }, - "System.Runtime.InteropServices.RuntimeInformation": { - "type": "Transitive", - "resolved": "4.0.0", - "contentHash": "hWPhJxc453RCa8Z29O91EmfGeZIHX1ZH2A8L6lYQVSaKzku2DfArSfMEb1/MYYzPQRJZeu0c9dmYeJKxW5Fgng==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "System.Reflection": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.InteropServices": "4.1.0", - "System.Threading": "4.0.11", - "runtime.native.System": "4.0.0" - } - }, - "System.Runtime.Numerics": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "yMH+MfdzHjy17l2KESnPiF2dwq7T+xLnSJar7slyimAkUh/gTrS9/UQOtv7xarskJ2/XDSNvfLGOBQPjL7PaHQ==", - "dependencies": { - "System.Globalization": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0" - } + "resolved": "5.0.0", + "contentHash": "ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==" }, "System.Security.AccessControl": { "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "vW8Eoq0TMyz5vAG/6ce483x/CP83fgm4SJe5P8Tb1tZaobcvPrbMEL7rhH1DRdrYbbb6F0vq3OlzmK0Pkwks5A==", - "dependencies": { - "Microsoft.NETCore.Platforms": "2.0.0", - "System.Security.Principal.Windows": "4.5.0" - } - }, - "System.Security.Cryptography.Algorithms": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "W1kd2Y8mYSCgc3ULTAZ0hOP2dSdG5YauTb1089T0/kRcN2MpSAW1izOFROrJgxSlMn3ArsgHXagigyi+ibhevg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Collections": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Runtime.Numerics": "4.3.0", - "System.Security.Cryptography.Encoding": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Text.Encoding": "4.3.0", - "runtime.native.System.Security.Cryptography.Apple": "4.3.0", - "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" - } - }, - "System.Security.Cryptography.Cng": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "03idZOqFlsKRL4W+LuCpJ6dBYDUWReug6lZjBa3uJWnk5sPCUXckocevTaUA8iT/MFSrY/2HXkOt753xQ/cf8g==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Cryptography.Algorithms": "4.3.0", - "System.Security.Cryptography.Encoding": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Text.Encoding": "4.3.0" - } - }, - "System.Security.Cryptography.Csp": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "X4s/FCkEUnRGnwR3aSfVIkldBmtURMhmexALNTwpjklzxWU7yjMk7GHLKOZTNkgnWnE0q7+BCf9N2LVRWxewaA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.IO": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Cryptography.Algorithms": "4.3.0", - "System.Security.Cryptography.Encoding": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.Security.Cryptography.Encoding": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "1DEWjZZly9ae9C79vFwqaO5kaOlI5q+3/55ohmq/7dpDyDfc8lYe7YVxJUZ5MF/NtbkRjwFRo14yM4OEo9EmDw==", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Collections": "4.3.0", - "System.Collections.Concurrent": "4.3.0", - "System.Linq": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Text.Encoding": "4.3.0", - "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" - } - }, - "System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "h4CEgOgv5PKVF/HwaHzJRiVboL2THYCou97zpmhjghx5frc7fIvlkY1jL+lnIQyChrJDMNEXS6r7byGif8Cy4w==", - "dependencies": { - "System.Collections": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Runtime.Numerics": "4.3.0", - "System.Security.Cryptography.Algorithms": "4.3.0", - "System.Security.Cryptography.Encoding": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Text.Encoding": "4.3.0", - "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" - } - }, - "System.Security.Cryptography.Primitives": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "7bDIyVFNL/xKeFHjhobUAQqSpJq9YTOpbEs6mR233Et01STBMXNAc/V+BM6dwYGc95gVh/Zf+iVXWzj3mE8DWg==", - "dependencies": { - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Threading": "4.3.0", - "System.Threading.Tasks": "4.3.0" - } - }, - "System.Security.Cryptography.X509Certificates": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "t2Tmu6Y2NtJ2um0RtcuhP7ZdNNxXEgUm2JeoA/0NvlMjAhKCnM1NX07TDl3244mVp3QU6LPEhT3HTtH1uF7IYw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.Globalization.Calendars": "4.3.0", - "System.IO": "4.3.0", - "System.IO.FileSystem": "4.3.0", - "System.IO.FileSystem.Primitives": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Runtime.Numerics": "4.3.0", - "System.Security.Cryptography.Algorithms": "4.3.0", - "System.Security.Cryptography.Cng": "4.3.0", - "System.Security.Cryptography.Csp": "4.3.0", - "System.Security.Cryptography.Encoding": "4.3.0", - "System.Security.Cryptography.OpenSsl": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0", - "runtime.native.System": "4.3.0", - "runtime.native.System.Net.Http": "4.3.0", - "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" } }, "System.Security.Principal.Windows": { "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "U77HfRXlZlOeIXd//Yoj6Jnk8AXlbeisf1oq1os+hxOGVnuG+lGSfGqTwTZBoORFF6j/0q7HXIl8cqwQ9aUGqQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "2.0.0" - } - }, - "System.Text.Encoding": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" }, "System.Text.Encoding.CodePages": { "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "IRiEFUa5b/Gs5Egg8oqBVoywhtOeaO2KOx3j0RfcYY/raxqBuEK7NXRDgOwtYM8qbi+7S4RPXUbNt+ZxyY0/NQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Collections": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.Text.Encoding.Extensions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "YVMK0Bt/A43RmwizJoZ22ei2nmrhobgeiYwFzC4YAN+nue8RF6djXDMog0UCn+brerQoYVyaS+ghy9P/MUVcmw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0", - "System.Text.Encoding": "4.3.0" - } - }, - "System.Text.RegularExpressions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "RpT2DA+L660cBt1FssIE9CAGpLFdFPuheB7pLpKpn6ZXNby7jDERe8Ua/Ne2xGiwLVG2JOqziiaVCGDon5sKFA==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, - "System.Threading": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "VkUS0kOBcUf3Wwm0TSbrevDDZ6BlM+b/HRiapRFWjM5O0NS0LviG0glKmFK+hhPDd1XFeSdU1GmlLhb2CoVpIw==", + "resolved": "4.5.1", + "contentHash": "4J2JQXbftjPMppIHJ7IC+VXQ9XfEagN92vZZNoG12i+zReYlim5dMoXFC1Zzg7tsnKDM7JPo5bYfFK4Jheq44w==", "dependencies": { - "System.Runtime": "4.3.0", - "System.Threading.Tasks": "4.3.0" - } - }, - "System.Threading.Tasks": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" + "Microsoft.NETCore.Platforms": "2.1.2", + "System.Runtime.CompilerServices.Unsafe": "4.5.2" } }, "System.Threading.Tasks.Extensions": { "type": "Transitive", - "resolved": "4.5.2", - "contentHash": "BG/TNxDFv0svAzx8OiMXDlsHfGw623BZ8tCXw4YLhDFDvDhNUEV58jKYMGRnkbJNm7c3JNNJDiN7JBMzxRBR2w==" - }, - "System.Threading.Tasks.Parallel": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "cbjBNZHf/vQCfcdhzx7knsiygoCKgxL8mZOeocXZn5gWhCdzHIq6bYNKWX0LAJCWYP7bds4yBK8p06YkP0oa0g==", - "dependencies": { - "System.Collections.Concurrent": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Diagnostics.Tracing": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0", - "System.Threading.Tasks": "4.3.0" - } - }, - "System.Threading.Thread": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "OHmbT+Zz065NKII/ZHcH9XO1dEuLGI1L2k7uYss+9C1jLxTC9kTZZuzUOyXHayRk+dft9CiDf3I/QZ0t8JKyBQ==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, - "System.ValueTuple": { - "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ==" - }, - "System.Xml.ReaderWriter": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "GrprA+Z0RUXaR4N7/eW71j1rgMnEnEVlgii49GZyAjTH7uliMnrOU3HNFBr6fEDBCJCIdlVNq9hHbaDR621XBA==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.IO.FileSystem": "4.3.0", - "System.IO.FileSystem.Primitives": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Text.Encoding.Extensions": "4.3.0", - "System.Text.RegularExpressions": "4.3.0", - "System.Threading.Tasks": "4.3.0", - "System.Threading.Tasks.Extensions": "4.3.0" - } - }, - "System.Xml.XDocument": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "5zJ0XDxAIg8iy+t4aMnQAu0MqVbqyvfoUVl1yDV61xdo3Vth45oA2FoY4pPkxYAH5f8ixpmTqXeEIya95x0aCQ==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Diagnostics.Tools": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0", - "System.Xml.ReaderWriter": "4.3.0" - } - }, - "System.Xml.XmlDocument": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "lJ8AxvkX7GQxpC6GFCeBj8ThYVyQczx2+f/cWHJU8tjS7YfI6Cv6bon70jVEgs2CiFbmmM8b9j1oZVx0dSI2Ww==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0", - "System.Xml.ReaderWriter": "4.3.0" - } - }, - "System.Xml.XPath": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "v1JQ5SETnQusqmS3RwStF7vwQ3L02imIzl++sewmt23VGygix04pEH+FCj1yWb+z4GDzKiljr1W7Wfvrx0YwgA==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0", - "System.Xml.ReaderWriter": "4.3.0" - } - }, - "System.Xml.XPath.XDocument": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "jw9oHHEIVW53mHY9PgrQa98Xo2IZ0ZjrpdOTmtvk+Rvg4tq7dydmxdNqUvJ5YwjDqhn75mBXWttWjiKhWP53LQ==", - "dependencies": { - "System.Diagnostics.Debug": "4.3.0", - "System.Linq": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0", - "System.Xml.ReaderWriter": "4.3.0", - "System.Xml.XDocument": "4.3.0", - "System.Xml.XPath": "4.3.0" - } + "resolved": "4.5.4", + "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" }, "FuzzySearch.Net": { "type": "Project" diff --git a/FuzzySearchNet.Tests/FuzzySearchNet.Tests.csproj b/FuzzySearchNet.Tests/FuzzySearchNet.Tests.csproj index d421817..26e7aba 100644 --- a/FuzzySearchNet.Tests/FuzzySearchNet.Tests.csproj +++ b/FuzzySearchNet.Tests/FuzzySearchNet.Tests.csproj @@ -13,11 +13,15 @@ - - - - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive +all + + runtime; build; native; contentfiles; analyzers; buildtransitive +all + diff --git a/FuzzySearchNet.Tests/Tests/FuzzySearchSubstitutionsOnlyTests.cs b/FuzzySearchNet.Tests/Tests/FuzzySearchSubstitutionsOnlyTests.cs index 3275b58..3a78487 100644 --- a/FuzzySearchNet.Tests/Tests/FuzzySearchSubstitutionsOnlyTests.cs +++ b/FuzzySearchNet.Tests/Tests/FuzzySearchSubstitutionsOnlyTests.cs @@ -2,6 +2,34 @@ namespace FuzzySearchNet.Tests; public class FuzzySearchSubstitutionsOnlyTests { + [Test] + public void TestPatternWithGrapheme() + { + var word = "PATTERN"; + var text = "👩‍👩‍👦‍👦PATTERN"; + + var results = FuzzySearch.Find(word, text, 1, SearchOptions.SubstitutionsOnly).ToList(); + + Assert.Multiple(() => + { + Assert.That(results[0].Distance, Is.EqualTo(0)); + Assert.That(results[0].StartIndex, Is.EqualTo(11)); + Assert.That(results[0].EndIndex, Is.EqualTo(18)); + Assert.That(results[0].Match, Is.EqualTo(word)); + }); + } + + [Test] + public void TestEmptyPatternWithGrapheme() + { + var word = ""; + var text = "👩‍👩‍👦‍👦PATTERN"; + + var results = FuzzySearch.Find(word, text, 1, SearchOptions.SubstitutionsOnly).ToList(); + + Assert.That(results, Is.Empty); + } + [Test] public void TestZeroMaxDistanceMultiple() { diff --git a/FuzzySearchNet.Tests/packages.lock.json b/FuzzySearchNet.Tests/packages.lock.json index 6c3a68b..4fc9aae 100644 --- a/FuzzySearchNet.Tests/packages.lock.json +++ b/FuzzySearchNet.Tests/packages.lock.json @@ -4,40 +4,40 @@ "net6.0": { "coverlet.collector": { "type": "Direct", - "requested": "[3.1.2, )", - "resolved": "3.1.2", - "contentHash": "wuLDIDKD5XMt0A7lE31JPenT7QQwZPFkP5rRpdJeblyXZ9MGLI8rYjvm5fvAKln+2/X+4IxxQDxBtwdrqKNLZw==" + "requested": "[6.0.0, )", + "resolved": "6.0.0", + "contentHash": "tW3lsNS+dAEII6YGUX/VMoJjBS1QvsxqJeqLaJXub08y1FSjasFPtQ4UBUsudE9PNrzLjooClMsPtY2cZLdXpQ==" }, "Microsoft.NET.Test.Sdk": { "type": "Direct", - "requested": "[17.3.0, )", - "resolved": "17.3.0", - "contentHash": "ch4JCT7AZdBzvCAKD36t6fDsl7NEzzunwW7MwXUG2uFPoWcMd8B8KYg5fiwxnpdXJHodJk6yIBdSwMpN3Ikt9w==", + "requested": "[17.8.0, )", + "resolved": "17.8.0", + "contentHash": "BmTYGbD/YuDHmApIENdoyN1jCk0Rj1fJB0+B/fVekyTdVidr91IlzhqzytiUgaEAzL1ZJcYCme0MeBMYvJVzvw==", "dependencies": { - "Microsoft.CodeCoverage": "17.3.0", - "Microsoft.TestPlatform.TestHost": "17.3.0" + "Microsoft.CodeCoverage": "17.8.0", + "Microsoft.TestPlatform.TestHost": "17.8.0" } }, "NUnit": { "type": "Direct", - "requested": "[3.13.3, )", - "resolved": "3.13.3", - "contentHash": "KNPDpls6EfHwC3+nnA67fh5wpxeLb3VLFAfLxrug6JMYDLHH6InaQIWR7Sc3y75d/9IKzMksH/gi08W7XWbmnQ==", + "requested": "[3.14.0, )", + "resolved": "3.14.0", + "contentHash": "R7iPwD7kbOaP3o2zldWJbWeMQAvDKD0uld27QvA3PAALl1unl7x0v2J7eGiJOYjimV/BuGT4VJmr45RjS7z4LA==", "dependencies": { "NETStandard.Library": "2.0.0" } }, "NUnit.Analyzers": { "type": "Direct", - "requested": "[3.3.0, )", - "resolved": "3.3.0", - "contentHash": "gyRc0qmXUIjHaTcHTWZDHK5ccOF6cLEOGQJ6Fj5JWKh8/W1XzPFC6zGXRu5sDNSxfKaNeQRmkdz3M73ArQkY1A==" + "requested": "[3.9.0, )", + "resolved": "3.9.0", + "contentHash": "8bGAEljlBnzR+uU8oGQhTVKnbgBw1Mo71qjVkgzHdvtUkiB5XOIDyjAcS4KUo/j+F2Zv/xBUZRkCWXmejx4bfA==" }, "NUnit3TestAdapter": { "type": "Direct", - "requested": "[4.2.1, )", - "resolved": "4.2.1", - "contentHash": "kgH8VKsrcZZgNGQXRpVCrM7TnNz9li3b/snH+YmnXUNqsaWa1Xw9EQWHpbzq4Li2FbTjTE/E5N5HdLNXzZ8BpQ==" + "requested": "[4.5.0, )", + "resolved": "4.5.0", + "contentHash": "s8JpqTe9bI2f49Pfr3dFRfoVSuFQyraTj68c3XXjIS/MRGvvkLnrg6RLqnTjdShX+AdFUCCU/4Xex58AdUfs6A==" }, "System.Linq.Async": { "type": "Direct", @@ -55,58 +55,30 @@ }, "Microsoft.CodeCoverage": { "type": "Transitive", - "resolved": "17.3.0", - "contentHash": "/xxz+e29F2V5pePtInjbLffoqWVTm60KCX87vSj2laNboeWq65WFJ634fGtBcMZO3VEfOmh9/XcoWEfLlWWG+g==" - }, - "Microsoft.CSharp": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "17h8b5mXa87XYKrrVqdgZ38JefSUqLChUQpXgSnpzsM0nDOhE40FTeNWOJ/YmySGV6tG6T8+hjz6vxbknHJr6A==", - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Dynamic.Runtime": "4.0.11", - "System.Globalization": "4.0.11", - "System.Linq": "4.1.0", - "System.Linq.Expressions": "4.1.0", - "System.ObjectModel": "4.0.12", - "System.Reflection": "4.1.0", - "System.Reflection.Extensions": "4.0.1", - "System.Reflection.Primitives": "4.0.1", - "System.Reflection.TypeExtensions": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.InteropServices": "4.1.0", - "System.Threading": "4.0.11" - } + "resolved": "17.8.0", + "contentHash": "KC8SXWbGIdoFVdlxKk9WHccm0llm9HypcHMLUUFabRiTS3SO2fQXNZfdiF3qkEdTJhbRrxhdRxjL4jbtwPq4Ew==" }, "Microsoft.NETCore.Platforms": { "type": "Transitive", "resolved": "1.1.0", "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" }, - "Microsoft.NETCore.Targets": { - "type": "Transitive", - "resolved": "1.0.1", - "contentHash": "rkn+fKobF/cbWfnnfBOQHKVKIOpxMZBvlSHkqDWgBpwGDcLRduvs3D9OLGeV6GWGvVwNlVi2CBbTjuPmtHvyNw==" - }, "Microsoft.TestPlatform.ObjectModel": { "type": "Transitive", - "resolved": "17.3.0", - "contentHash": "6NRzi6QbmWV49Psf8A9z1LTJU4nBrlJdCcDOUyD4Ttm1J2wvksu98GlV+52CkxtpgNsUjGr9Mv1Rbb1/dB06yQ==", + "resolved": "17.8.0", + "contentHash": "AYy6vlpGMfz5kOFq99L93RGbqftW/8eQTqjT9iGXW6s9MRP3UdtY8idJ8rJcjeSja8A18IhIro5YnH3uv1nz4g==", "dependencies": { - "NuGet.Frameworks": "5.11.0", + "NuGet.Frameworks": "6.5.0", "System.Reflection.Metadata": "1.6.0" } }, "Microsoft.TestPlatform.TestHost": { "type": "Transitive", - "resolved": "17.3.0", - "contentHash": "uOJALDWtKXZkISKuNI7kOlRi/lk2CqXZtLkNS0Ei+RXqRUjUpCsjAPYSP+DJ/a4QwJ5cI9CVF52vtajnGOaEpw==", + "resolved": "17.8.0", + "contentHash": "9ivcl/7SGRmOT0YYrHQGohWiT5YCpkmy/UEzldfVisLm6QxbLaK3FAJqZXI34rnRLmqqDCeMQxKINwmKwAPiDw==", "dependencies": { - "Microsoft.TestPlatform.ObjectModel": "17.3.0", - "Newtonsoft.Json": "9.0.1" + "Microsoft.TestPlatform.ObjectModel": "17.8.0", + "Newtonsoft.Json": "13.0.1" } }, "NETStandard.Library": { @@ -119,430 +91,19 @@ }, "Newtonsoft.Json": { "type": "Transitive", - "resolved": "9.0.1", - "contentHash": "U82mHQSKaIk+lpSVCbWYKNavmNH1i5xrExDEquU1i6I5pV6UMOqRnJRSlKO3cMPfcpp0RgDY+8jUXHdQ4IfXvw==", - "dependencies": { - "Microsoft.CSharp": "4.0.1", - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Dynamic.Runtime": "4.0.11", - "System.Globalization": "4.0.11", - "System.IO": "4.1.0", - "System.Linq": "4.1.0", - "System.Linq.Expressions": "4.1.0", - "System.ObjectModel": "4.0.12", - "System.Reflection": "4.1.0", - "System.Reflection.Extensions": "4.0.1", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.Serialization.Primitives": "4.1.1", - "System.Text.Encoding": "4.0.11", - "System.Text.Encoding.Extensions": "4.0.11", - "System.Text.RegularExpressions": "4.1.0", - "System.Threading": "4.0.11", - "System.Threading.Tasks": "4.0.11", - "System.Xml.ReaderWriter": "4.0.11", - "System.Xml.XDocument": "4.0.11" - } + "resolved": "13.0.1", + "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" }, "NuGet.Frameworks": { "type": "Transitive", - "resolved": "5.11.0", - "contentHash": "eaiXkUjC4NPcquGWzAGMXjuxvLwc6XGKMptSyOGQeT0X70BUZObuybJFZLA0OfTdueLd3US23NBPTBb6iF3V1Q==" - }, - "System.Collections": { - "type": "Transitive", - "resolved": "4.0.11", - "contentHash": "YUJGz6eFKqS0V//mLt25vFGrrCvOnsXjlvFQs+KimpwNxug9x0Pzy4PlFMU3Q2IzqAa9G2L4LsK3+9vCBK7oTg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1", - "System.Runtime": "4.1.0" - } - }, - "System.Diagnostics.Debug": { - "type": "Transitive", - "resolved": "4.0.11", - "contentHash": "w5U95fVKHY4G8ASs/K5iK3J5LY+/dLFd4vKejsnI/ZhBsWS9hQakfx3Zr7lRWKg4tAw9r4iktyvsTagWkqYCiw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1", - "System.Runtime": "4.1.0" - } - }, - "System.Diagnostics.Tools": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "xBfJ8pnd4C17dWaC9FM6aShzbJcRNMChUMD42I6772KGGrqaFdumwhn9OdM68erj1ueNo3xdQ1EwiFjK5k8p0g==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1", - "System.Runtime": "4.1.0" - } - }, - "System.Dynamic.Runtime": { - "type": "Transitive", - "resolved": "4.0.11", - "contentHash": "db34f6LHYM0U0JpE+sOmjar27BnqTVkbLJhgfwMpTdgTigG/Hna3m2MYVwnFzGGKnEJk2UXFuoVTr8WUbU91/A==", - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Globalization": "4.0.11", - "System.Linq": "4.1.0", - "System.Linq.Expressions": "4.1.0", - "System.ObjectModel": "4.0.12", - "System.Reflection": "4.1.0", - "System.Reflection.Emit": "4.0.1", - "System.Reflection.Emit.ILGeneration": "4.0.1", - "System.Reflection.Primitives": "4.0.1", - "System.Reflection.TypeExtensions": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Threading": "4.0.11" - } - }, - "System.Globalization": { - "type": "Transitive", - "resolved": "4.0.11", - "contentHash": "B95h0YLEL2oSnwF/XjqSWKnwKOy/01VWkNlsCeMTFJLLabflpGV26nK164eRs5GiaRSBGpOxQ3pKoSnnyZN5pg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1", - "System.Runtime": "4.1.0" - } - }, - "System.IO": { - "type": "Transitive", - "resolved": "4.1.0", - "contentHash": "3KlTJceQc3gnGIaHZ7UBZO26SHL1SHE4ddrmiwumFnId+CEHP+O8r386tZKaE6zlk5/mF8vifMBzHj9SaXN+mQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1", - "System.Runtime": "4.1.0", - "System.Text.Encoding": "4.0.11", - "System.Threading.Tasks": "4.0.11" - } - }, - "System.IO.FileSystem": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "IBErlVq5jOggAD69bg1t0pJcHaDbJbWNUZTPI96fkYWzwYbN6D9wRHMULLDd9dHsl7C2YsxXL31LMfPI1SWt8w==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1", - "System.IO": "4.1.0", - "System.IO.FileSystem.Primitives": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Handles": "4.0.1", - "System.Text.Encoding": "4.0.11", - "System.Threading.Tasks": "4.0.11" - } - }, - "System.IO.FileSystem.Primitives": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "kWkKD203JJKxJeE74p8aF8y4Qc9r9WQx4C0cHzHPrY3fv/L/IhWnyCHaFJ3H1QPOH6A93whlQ2vG5nHlBDvzWQ==", - "dependencies": { - "System.Runtime": "4.1.0" - } - }, - "System.Linq": { - "type": "Transitive", - "resolved": "4.1.0", - "contentHash": "bQ0iYFOQI0nuTnt+NQADns6ucV4DUvMdwN6CbkB1yj8i7arTGiTN5eok1kQwdnnNWSDZfIUySQY+J3d5KjWn0g==", - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0" - } - }, - "System.Linq.Expressions": { - "type": "Transitive", - "resolved": "4.1.0", - "contentHash": "I+y02iqkgmCAyfbqOmSDOgqdZQ5tTj80Akm5BPSS8EeB0VGWdy6X1KCoYe8Pk6pwDoAKZUOdLVxnTJcExiv5zw==", - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Globalization": "4.0.11", - "System.IO": "4.1.0", - "System.Linq": "4.1.0", - "System.ObjectModel": "4.0.12", - "System.Reflection": "4.1.0", - "System.Reflection.Emit": "4.0.1", - "System.Reflection.Emit.ILGeneration": "4.0.1", - "System.Reflection.Emit.Lightweight": "4.0.1", - "System.Reflection.Extensions": "4.0.1", - "System.Reflection.Primitives": "4.0.1", - "System.Reflection.TypeExtensions": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Threading": "4.0.11" - } - }, - "System.ObjectModel": { - "type": "Transitive", - "resolved": "4.0.12", - "contentHash": "tAgJM1xt3ytyMoW4qn4wIqgJYm7L7TShRZG4+Q4Qsi2PCcj96pXN7nRywS9KkB3p/xDUjc2HSwP9SROyPYDYKQ==", - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Threading": "4.0.11" - } - }, - "System.Reflection": { - "type": "Transitive", - "resolved": "4.1.0", - "contentHash": "JCKANJ0TI7kzoQzuwB/OoJANy1Lg338B6+JVacPl4TpUwi3cReg3nMLplMq2uqYfHFQpKIlHAUVAJlImZz/4ng==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1", - "System.IO": "4.1.0", - "System.Reflection.Primitives": "4.0.1", - "System.Runtime": "4.1.0" - } - }, - "System.Reflection.Emit": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "P2wqAj72fFjpP6wb9nSfDqNBMab+2ovzSDzUZK7MVIm54tBJEPr9jWfSjjoTpPwj1LeKcmX3vr0ttyjSSFM47g==", - "dependencies": { - "System.IO": "4.1.0", - "System.Reflection": "4.1.0", - "System.Reflection.Emit.ILGeneration": "4.0.1", - "System.Reflection.Primitives": "4.0.1", - "System.Runtime": "4.1.0" - } - }, - "System.Reflection.Emit.ILGeneration": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "Ov6dU8Bu15Bc7zuqttgHF12J5lwSWyTf1S+FJouUXVMSqImLZzYaQ+vRr1rQ0OZ0HqsrwWl4dsKHELckQkVpgA==", - "dependencies": { - "System.Reflection": "4.1.0", - "System.Reflection.Primitives": "4.0.1", - "System.Runtime": "4.1.0" - } - }, - "System.Reflection.Emit.Lightweight": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "sSzHHXueZ5Uh0OLpUQprhr+ZYJrLPA2Cmr4gn0wj9+FftNKXx8RIMKvO9qnjk2ebPYUjZ+F2ulGdPOsvj+MEjA==", - "dependencies": { - "System.Reflection": "4.1.0", - "System.Reflection.Emit.ILGeneration": "4.0.1", - "System.Reflection.Primitives": "4.0.1", - "System.Runtime": "4.1.0" - } - }, - "System.Reflection.Extensions": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "GYrtRsZcMuHF3sbmRHfMYpvxZoIN2bQGrYGerUiWLEkqdEUQZhH3TRSaC/oI4wO0II1RKBPlpIa1TOMxIcOOzQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1", - "System.Reflection": "4.1.0", - "System.Runtime": "4.1.0" - } + "resolved": "6.5.0", + "contentHash": "QWINE2x3MbTODsWT1Gh71GaGb5icBz4chS8VYvTgsBnsi8esgN6wtHhydd7fvToWECYGq7T4cgBBDiKD/363fg==" }, "System.Reflection.Metadata": { "type": "Transitive", "resolved": "1.6.0", "contentHash": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ==" }, - "System.Reflection.Primitives": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "4inTox4wTBaDhB7V3mPvp9XlCbeGYWVEM9/fXALd52vNEAVisc1BoVWQPuUuD0Ga//dNbA/WeMy9u9mzLxGTHQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1", - "System.Runtime": "4.1.0" - } - }, - "System.Reflection.TypeExtensions": { - "type": "Transitive", - "resolved": "4.1.0", - "contentHash": "tsQ/ptQ3H5FYfON8lL4MxRk/8kFyE0A+tGPXmVP967cT/gzLHYxIejIYSxp4JmIeFHVP78g/F2FE1mUUTbDtrg==", - "dependencies": { - "System.Reflection": "4.1.0", - "System.Runtime": "4.1.0" - } - }, - "System.Resources.ResourceManager": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "TxwVeUNoTgUOdQ09gfTjvW411MF+w9MBYL7AtNVc+HtBCFlutPLhUCdZjNkjbhj3bNQWMdHboF0KIWEOjJssbA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1", - "System.Globalization": "4.0.11", - "System.Reflection": "4.1.0", - "System.Runtime": "4.1.0" - } - }, - "System.Runtime": { - "type": "Transitive", - "resolved": "4.1.0", - "contentHash": "v6c/4Yaa9uWsq+JMhnOFewrYkgdNHNG2eMKuNqRn8P733rNXeRCGvV5FkkjBXn2dbVkPXOsO0xjsEeM1q2zC0g==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1" - } - }, - "System.Runtime.Extensions": { - "type": "Transitive", - "resolved": "4.1.0", - "contentHash": "CUOHjTT/vgP0qGW22U4/hDlOqXmcPq5YicBaXdUR2UiUoLwBT+olO6we4DVbq57jeX5uXH2uerVZhf0qGj+sVQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1", - "System.Runtime": "4.1.0" - } - }, - "System.Runtime.Handles": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "nCJvEKguXEvk2ymk1gqj625vVnlK3/xdGzx0vOKicQkoquaTBJTP13AIYkocSUwHCLNBwUbXTqTWGDxBTWpt7g==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1", - "System.Runtime": "4.1.0" - } - }, - "System.Runtime.InteropServices": { - "type": "Transitive", - "resolved": "4.1.0", - "contentHash": "16eu3kjHS633yYdkjwShDHZLRNMKVi/s0bY8ODiqJ2RfMhDMAwxZaUaWVnZ2P71kr/or+X9o/xFWtNqz8ivieQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1", - "System.Reflection": "4.1.0", - "System.Reflection.Primitives": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Handles": "4.0.1" - } - }, - "System.Runtime.Serialization.Primitives": { - "type": "Transitive", - "resolved": "4.1.1", - "contentHash": "HZ6Du5QrTG8MNJbf4e4qMO3JRAkIboGT5Fk804uZtg3Gq516S7hAqTm2UZKUHa7/6HUGdVy3AqMQKbns06G/cg==", - "dependencies": { - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0" - } - }, - "System.Text.Encoding": { - "type": "Transitive", - "resolved": "4.0.11", - "contentHash": "U3gGeMlDZXxCEiY4DwVLSacg+DFWCvoiX+JThA/rvw37Sqrku7sEFeVBBBMBnfB6FeZHsyDx85HlKL19x0HtZA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1", - "System.Runtime": "4.1.0" - } - }, - "System.Text.Encoding.Extensions": { - "type": "Transitive", - "resolved": "4.0.11", - "contentHash": "jtbiTDtvfLYgXn8PTfWI+SiBs51rrmO4AAckx4KR6vFK9Wzf6tI8kcRdsYQNwriUeQ1+CtQbM1W4cMbLXnj/OQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1", - "System.Runtime": "4.1.0", - "System.Text.Encoding": "4.0.11" - } - }, - "System.Text.RegularExpressions": { - "type": "Transitive", - "resolved": "4.1.0", - "contentHash": "i88YCXpRTjCnoSQZtdlHkAOx4KNNik4hMy83n0+Ftlb7jvV6ZiZWMpnEZHhjBp6hQVh8gWd/iKNPzlPF7iyA2g==", - "dependencies": { - "System.Collections": "4.0.11", - "System.Globalization": "4.0.11", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Threading": "4.0.11" - } - }, - "System.Threading": { - "type": "Transitive", - "resolved": "4.0.11", - "contentHash": "N+3xqIcg3VDKyjwwCGaZ9HawG9aC6cSDI+s7ROma310GQo8vilFZa86hqKppwTHleR/G0sfOzhvgnUxWCR/DrQ==", - "dependencies": { - "System.Runtime": "4.1.0", - "System.Threading.Tasks": "4.0.11" - } - }, - "System.Threading.Tasks": { - "type": "Transitive", - "resolved": "4.0.11", - "contentHash": "k1S4Gc6IGwtHGT8188RSeGaX86Qw/wnrgNLshJvsdNUOPP9etMmo8S07c+UlOAx4K/xLuN9ivA1bD0LVurtIxQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1", - "System.Runtime": "4.1.0" - } - }, - "System.Threading.Tasks.Extensions": { - "type": "Transitive", - "resolved": "4.0.0", - "contentHash": "pH4FZDsZQ/WmgJtN4LWYmRdJAEeVkyriSwrv2Teoe5FOU0Yxlb6II6GL8dBPOfRmutHGATduj3ooMt7dJ2+i+w==", - "dependencies": { - "System.Collections": "4.0.11", - "System.Runtime": "4.1.0", - "System.Threading.Tasks": "4.0.11" - } - }, - "System.Xml.ReaderWriter": { - "type": "Transitive", - "resolved": "4.0.11", - "contentHash": "ZIiLPsf67YZ9zgr31vzrFaYQqxRPX9cVHjtPSnmx4eN6lbS/yEyYNr2vs1doGDEscF0tjCZFsk9yUg1sC9e8tg==", - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Globalization": "4.0.11", - "System.IO": "4.1.0", - "System.IO.FileSystem": "4.0.1", - "System.IO.FileSystem.Primitives": "4.0.1", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.InteropServices": "4.1.0", - "System.Text.Encoding": "4.0.11", - "System.Text.Encoding.Extensions": "4.0.11", - "System.Text.RegularExpressions": "4.1.0", - "System.Threading.Tasks": "4.0.11", - "System.Threading.Tasks.Extensions": "4.0.0" - } - }, - "System.Xml.XDocument": { - "type": "Transitive", - "resolved": "4.0.11", - "contentHash": "Mk2mKmPi0nWaoiYeotq1dgeNK1fqWh61+EK+w4Wu8SWuTYLzpUnschb59bJtGywaPq7SmTuPf44wrXRwbIrukg==", - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Diagnostics.Tools": "4.0.1", - "System.Globalization": "4.0.11", - "System.IO": "4.1.0", - "System.Reflection": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Text.Encoding": "4.0.11", - "System.Threading": "4.0.11", - "System.Xml.ReaderWriter": "4.0.11" - } - }, "FuzzySearch.Net": { "type": "Project" } diff --git a/FuzzySearchNet.sln b/FuzzySearchNet.sln index 1d4a2af..83bf16d 100644 --- a/FuzzySearchNet.sln +++ b/FuzzySearchNet.sln @@ -3,12 +3,14 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.2.32505.173 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FuzzySearchNet", "FuzzySearchNet\FuzzySearchNet.csproj", "{5DCAC51E-CE47-4268-8CCE-44B4D3F95EAF}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FuzzySearchNet", "FuzzySearchNet\FuzzySearchNet.csproj", "{5DCAC51E-CE47-4268-8CCE-44B4D3F95EAF}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FuzzySearchNet.Tests", "FuzzySearchNet.Tests\FuzzySearchNet.Tests.csproj", "{98ABDD95-91F2-4828-A151-4801ED9DF08D}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FuzzySearchNet.Benchmark", "FuzzySearchNet.Benchmark\FuzzySearchNet.Benchmark.csproj", "{3E8EA714-797A-4A0C-BF88-3BFD46CC19E3}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleTester", "ConsoleTester\ConsoleTester.csproj", "{1968930E-61AB-41A1-8976-CEBD944E1408}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,6 +29,10 @@ Global {3E8EA714-797A-4A0C-BF88-3BFD46CC19E3}.Debug|Any CPU.Build.0 = Release|Any CPU {3E8EA714-797A-4A0C-BF88-3BFD46CC19E3}.Release|Any CPU.ActiveCfg = Release|Any CPU {3E8EA714-797A-4A0C-BF88-3BFD46CC19E3}.Release|Any CPU.Build.0 = Release|Any CPU + {1968930E-61AB-41A1-8976-CEBD944E1408}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1968930E-61AB-41A1-8976-CEBD944E1408}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1968930E-61AB-41A1-8976-CEBD944E1408}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1968930E-61AB-41A1-8976-CEBD944E1408}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/FuzzySearchNet/FuzzySearchNet.csproj b/FuzzySearchNet/FuzzySearchNet.csproj index 3ffc1bc..0c1222c 100644 --- a/FuzzySearchNet/FuzzySearchNet.csproj +++ b/FuzzySearchNet/FuzzySearchNet.csproj @@ -13,7 +13,7 @@ FuzzySearch.Net - 0.3.3 + 0.4.0 FuzzySearch.Net Verner Fortelius Fuzzy search library for finding strings in strings. Inspired by and attempts to be somewhat compatible with fuzzysearch for python https://github.com/taleinat/fuzzysearch @@ -22,7 +22,7 @@ https://github.com/vforteli/FuzzySearch.Net https://github.com/vforteli/FuzzySearch.Net https://github.com/vforteli/FuzzySearch.Net/blob/main/LICENSE.md - Support for streaming find using IAsyncEnumerable + Memory usage optimizations fuzzy search;levenshtein distance;dotnet;.net;c#;fuzzysearch.net true snupkg @@ -30,6 +30,6 @@ - + diff --git a/FuzzySearchNet/src/CandidateMatch.cs b/FuzzySearchNet/src/CandidateMatch.cs index 9e288cb..a88db9a 100644 --- a/FuzzySearchNet/src/CandidateMatch.cs +++ b/FuzzySearchNet/src/CandidateMatch.cs @@ -1,15 +1,3 @@ namespace FuzzySearchNet; public record struct CandidateMatch(int StartIndex, int TextIndex, int SubSequenceIndex = 0, int Distance = 0, int Deletions = 0, int Substitutions = 0, int Insertions = 0); - -// using a record struct improves performance around 30% in benchmarks -//public record CandidateMatch -//{ -// public int StartIndex; -// public int TextIndex => StartIndex + Position; -// public int SubSequenceIndex => Position + Offset; -// public int Deletions = 0; -// public int Substitutions = 0; -// public int Insertions = 0; -// public int Distance => Deletions + Insertions + Substitutions; -//} \ No newline at end of file diff --git a/FuzzySearchNet/src/FuzzySearchLevenshtein.cs b/FuzzySearchNet/src/FuzzySearchLevenshtein.cs index f3fb296..bfadbba 100644 --- a/FuzzySearchNet/src/FuzzySearchLevenshtein.cs +++ b/FuzzySearchNet/src/FuzzySearchLevenshtein.cs @@ -1,4 +1,6 @@ -namespace FuzzySearchNet; +using System.Runtime.CompilerServices; + +namespace FuzzySearchNet; public partial class FuzzySearch { @@ -7,14 +9,15 @@ public partial class FuzzySearch /// /// /// - public static IEnumerable FindLevenshtein(string subSequence, string text, FuzzySearchOptions options) => Utils.GetBestMatches(FindLevenshteinAll(subSequence, text, options), options.MaxTotalDistance); + public static IEnumerable FindLevenshtein(string subSequence, string text, FuzzySearchOptions options) => + Utils.GetBestMatches(text, FindLevenshteinAll(subSequence, text, options), options.MaxTotalDistance); /// /// Finds sub sequence in text with max levenshtein distance /// This method finds all matches and does not try to consolidate overlapping matches /// - internal static IEnumerable FindLevenshteinAll(string subSequence, string text, FuzzySearchOptions options) + internal static IEnumerable FindLevenshteinAll(string subSequence, string text, FuzzySearchOptions options) { if (string.IsNullOrEmpty(subSequence)) { @@ -37,16 +40,7 @@ internal static IEnumerable FindLevenshteinAll(string subSequence, if (candidate.TextIndex <= text.Length) { bestFoundDistance = candidate.Distance; - yield return new MatchResult - { - StartIndex = candidate.StartIndex, - EndIndex = candidate.TextIndex, - Distance = candidate.Distance, - Match = text[candidate.StartIndex..candidate.TextIndex], - Deletions = candidate.Deletions, - Substitutions = candidate.Substitutions, - Insertions = candidate.Insertions, - }; + yield return candidate; } // No point searching for better matches if we find a perfect match @@ -59,52 +53,7 @@ internal static IEnumerable FindLevenshteinAll(string subSequence, continue; } - if (candidate.SubSequenceIndex < subSequence.Length && candidate.TextIndex < text.Length && text[candidate.TextIndex] == subSequence[candidate.SubSequenceIndex]) - { - if (candidate.Distance < bestFoundDistance && options.CanInsert(candidate.Distance, candidate.Insertions)) - { - // jump over one character in text - candidates.Push(candidate with - { - Insertions = candidate.Insertions + 1, - Distance = candidate.Distance + 1, - SubSequenceIndex = candidate.SubSequenceIndex + 1, - TextIndex = candidate.TextIndex + 2, - }); - } - - // match - candidates.Push(candidate with - { - TextIndex = candidate.TextIndex + 1, - SubSequenceIndex = candidate.SubSequenceIndex + 1, - }); - } - else if (candidate.Distance < bestFoundDistance) - { - if (options.CanDelete(candidate.Distance, candidate.Deletions)) - { - // jump over one character in subsequence - candidates.Push(candidate with - { - Deletions = candidate.Deletions + 1, - Distance = candidate.Distance + 1, - SubSequenceIndex = candidate.SubSequenceIndex + 1, - }); - } - - if (options.CanSubstitute(candidate.Distance, candidate.Substitutions)) - { - // substitute one character - candidates.Push(candidate with - { - Substitutions = candidate.Substitutions + 1, - Distance = candidate.Distance + 1, - TextIndex = candidate.TextIndex + 1, - SubSequenceIndex = candidate.SubSequenceIndex + 1, - }); - } - } + HandleCandidate(candidates, candidate, text, subSequence, bestFoundDistance, options, text.Length); } } } @@ -113,14 +62,15 @@ internal static IEnumerable FindLevenshteinAll(string subSequence, /// /// Finds sub sequence in text with max levenshtein distance /// - public static IAsyncEnumerable FindLevenshteinAsync(string subSequence, Stream textStream, FuzzySearchOptions options, int bufferSize = 4096) => Utils.GetBestMatchesAsync(FindLevenshteinAllAsync(subSequence, textStream, options, bufferSize), options.MaxTotalDistance); + public static IAsyncEnumerable FindLevenshteinAsync(string subSequence, Stream textStream, FuzzySearchOptions options, int bufferSize = 4096, bool leaveOpen = false) => + Utils.GetBestMatchesAsync(FindLevenshteinAllAsync(subSequence, textStream, options, bufferSize, leaveOpen), options.MaxTotalDistance); /// /// Finds sub sequence in text with max levenshtein distance /// This method finds all matches and does not try to consolidate overlapping matches /// - internal static async IAsyncEnumerable FindLevenshteinAllAsync(string subSequence, Stream textStream, FuzzySearchOptions options, int bufferSize = 4096) + internal static async IAsyncEnumerable FindLevenshteinAllAsync(string subSequence, Stream textStream, FuzzySearchOptions options, int bufferSize, bool leaveOpen = false) { if (subSequence.Length > 0) { @@ -129,7 +79,7 @@ internal static async IAsyncEnumerable FindLevenshteinAllAsync(stri var startBuffer = subSequence.Length + options.MaxTotalDistance; bufferSize = ((startBuffer * 2 / bufferSize) + 1) * bufferSize; var buffer = new char[bufferSize]; - using var streamReader = new StreamReader(textStream); + using var streamReader = new StreamReader(textStream, null, true, -1, leaveOpen); var streamIndexOffset = 0; @@ -151,7 +101,7 @@ internal static async IAsyncEnumerable FindLevenshteinAllAsync(stri if (candidate.TextIndex <= bytesRead) { bestFoundDistance = candidate.Distance; - yield return new MatchResult + yield return new MatchResultWithValue { StartIndex = streamIndexOffset + candidate.StartIndex, EndIndex = streamIndexOffset + candidate.TextIndex, @@ -173,57 +123,13 @@ internal static async IAsyncEnumerable FindLevenshteinAllAsync(stri continue; } - if (candidate.SubSequenceIndex < subSequence.Length && candidate.TextIndex < bytesRead && buffer[candidate.TextIndex] == subSequence[candidate.SubSequenceIndex]) - { - if (candidate.Distance < bestFoundDistance && options.CanInsert(candidate.Distance, candidate.Insertions)) - { - // jump over one character in text - candidates.Push(candidate with - { - Insertions = candidate.Insertions + 1, - Distance = candidate.Distance + 1, - SubSequenceIndex = candidate.SubSequenceIndex + 1, - TextIndex = candidate.TextIndex + 2, - }); - } - - // match - candidates.Push(candidate with - { - TextIndex = candidate.TextIndex + 1, - SubSequenceIndex = candidate.SubSequenceIndex + 1, - }); - } - else if (candidate.Distance < bestFoundDistance) - { - if (options.CanDelete(candidate.Distance, candidate.Deletions)) - { - // jump over one character in subsequence - candidates.Push(candidate with - { - Deletions = candidate.Deletions + 1, - Distance = candidate.Distance + 1, - SubSequenceIndex = candidate.SubSequenceIndex + 1, - }); - } - - if (options.CanSubstitute(candidate.Distance, candidate.Substitutions)) - { - // substitute one character - candidates.Push(candidate with - { - Substitutions = candidate.Substitutions + 1, - Distance = candidate.Distance + 1, - TextIndex = candidate.TextIndex + 1, - SubSequenceIndex = candidate.SubSequenceIndex + 1, - }); - } - } + HandleCandidate(candidates, candidate, buffer, subSequence, bestFoundDistance, options, bytesRead); } } streamIndexOffset += bytesRead - startBuffer; + // basically stride to ensure matches spanning chunks are handled correctly Array.Copy(buffer, buffer.Length - startBuffer, buffer, 0, startBuffer); bytesRead = await streamReader.ReadBlockAsync(buffer, startBuffer, buffer.Length - startBuffer); bytesRead += startBuffer; @@ -231,4 +137,56 @@ internal static async IAsyncEnumerable FindLevenshteinAllAsync(stri while (bytesRead > startBuffer); } } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void HandleCandidate(Stack candidates, in CandidateMatch candidate, ReadOnlySpan text, string subSequence, int bestFoundDistance, FuzzySearchOptions options, int textLength) + { + if (candidate.TextIndex < textLength && text[candidate.TextIndex] == subSequence[candidate.SubSequenceIndex]) + { + if (candidate.Distance < bestFoundDistance && options.CanInsert(candidate.Distance, candidate.Insertions)) + { + // jump over one character in text + candidates.Push(candidate with + { + Insertions = candidate.Insertions + 1, + Distance = candidate.Distance + 1, + SubSequenceIndex = candidate.SubSequenceIndex + 1, + TextIndex = candidate.TextIndex + 2, + }); + } + + // match + candidates.Push(candidate with + { + TextIndex = candidate.TextIndex + 1, + SubSequenceIndex = candidate.SubSequenceIndex + 1, + }); + } + else if (candidate.Distance < bestFoundDistance) + { + if (options.CanDelete(candidate.Distance, candidate.Deletions)) + { + // jump over one character in subsequence + candidates.Push(candidate with + { + Deletions = candidate.Deletions + 1, + Distance = candidate.Distance + 1, + SubSequenceIndex = candidate.SubSequenceIndex + 1, + }); + } + + if (options.CanSubstitute(candidate.Distance, candidate.Substitutions)) + { + // substitute one character + candidates.Push(candidate with + { + Substitutions = candidate.Substitutions + 1, + Distance = candidate.Distance + 1, + TextIndex = candidate.TextIndex + 1, + SubSequenceIndex = candidate.SubSequenceIndex + 1, + }); + } + } + } } diff --git a/FuzzySearchNet/src/MatchResultValue.cs b/FuzzySearchNet/src/MatchResultValue.cs new file mode 100644 index 0000000..2cafdd0 --- /dev/null +++ b/FuzzySearchNet/src/MatchResultValue.cs @@ -0,0 +1,12 @@ +namespace FuzzySearchNet; + +internal record MatchResultWithValue +{ + public int StartIndex { get; set; } + public int EndIndex { get; set; } + public int Distance { get; set; } + public string Match { get; set; } = ""; + public int Deletions { get; set; } + public int Substitutions { get; set; } + public int Insertions { get; set; } +} diff --git a/FuzzySearchNet/src/Utils.cs b/FuzzySearchNet/src/Utils.cs index 152f2a5..67a742c 100644 --- a/FuzzySearchNet/src/Utils.cs +++ b/FuzzySearchNet/src/Utils.cs @@ -1,4 +1,6 @@ -namespace FuzzySearchNet; +using System.Runtime.CompilerServices; + +namespace FuzzySearchNet; public static class Utils { @@ -6,11 +8,11 @@ public static class Utils /// Group matches and return best. /// Currently assumes the matches are in the same order they are found... /// - public static IEnumerable GetBestMatches(IEnumerable matches, int maxDistanece) + internal static IEnumerable GetBestMatches(string text, IEnumerable matches, int maxDistanece) { var matchesEnumerator = matches.GetEnumerator(); - var group = new List(); + var group = new List(); if (matchesEnumerator.MoveNext()) { @@ -20,26 +22,21 @@ public static IEnumerable GetBestMatches(IEnumerable m while (matchesEnumerator.MoveNext()) { - var currentMatch = matchesEnumerator.Current; - - if (currentMatch != null) + if (matchesEnumerator.Current.StartIndex > (matchStartIndex + maxDistanece)) { - if (currentMatch.StartIndex > (matchStartIndex + maxDistanece)) - { - yield return group.OrderBy(o => o.Distance).ThenByDescending(o => o.Match.Length).First(); - group.Clear(); - } + yield return GetBestMatchFromGroup(group, text); + group.Clear(); + } - group.Add(currentMatch); + group.Add(matchesEnumerator.Current); - matchStartIndex = currentMatch.StartIndex; - } + matchStartIndex = matchesEnumerator.Current.StartIndex; } } if (group.Any()) { - yield return group.OrderBy(o => o.Distance).ThenByDescending(o => o.Match.Length).First(); + yield return GetBestMatchFromGroup(group, text); } } @@ -48,11 +45,11 @@ public static IEnumerable GetBestMatches(IEnumerable m /// Group matches and return best. /// Currently assumes the matches are in the same order they are found... /// - public static async IAsyncEnumerable GetBestMatchesAsync(IAsyncEnumerable matches, int maxDistanece) + internal static async IAsyncEnumerable GetBestMatchesAsync(IAsyncEnumerable matches, int maxDistanece) { var matchesEnumerator = matches.GetAsyncEnumerator(); - var group = new List(); + var group = new List(); if (await matchesEnumerator.MoveNextAsync()) { @@ -62,26 +59,72 @@ public static async IAsyncEnumerable GetBestMatchesAsync(IAsyncEnum while (await matchesEnumerator.MoveNextAsync()) { - var currentMatch = matchesEnumerator.Current; - - if (currentMatch != null) + if (matchesEnumerator.Current.StartIndex > (matchStartIndex + maxDistanece)) { - if (currentMatch.StartIndex > (matchStartIndex + maxDistanece)) - { - yield return group.OrderBy(o => o.Distance).ThenByDescending(o => o.Match.Length).First(); - group.Clear(); - } + yield return GetBestMatchFromGroupWithValue(group); + group.Clear(); + } - group.Add(currentMatch); + group.Add(matchesEnumerator.Current); - matchStartIndex = currentMatch.StartIndex; - } + matchStartIndex = matchesEnumerator.Current.StartIndex; } } if (group.Any()) { - yield return group.OrderBy(o => o.Distance).ThenByDescending(o => o.Match.Length).First(); + yield return GetBestMatchFromGroupWithValue(group); + } + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static MatchResult GetBestMatchFromGroup(List group, string text) + { + var bestMatch = group.First(); + + foreach (var match in group.Skip(1)) + { + if (match.Distance < bestMatch.Distance || match.Distance == bestMatch.Distance && (match.TextIndex - match.StartIndex) > (bestMatch.TextIndex - bestMatch.StartIndex)) + { + bestMatch = match; + } + } + + return new MatchResult + { + StartIndex = bestMatch.StartIndex, + EndIndex = bestMatch.TextIndex, + Distance = bestMatch.Distance, + Match = text[bestMatch.StartIndex..bestMatch.TextIndex], + Deletions = bestMatch.Deletions, + Insertions = bestMatch.Insertions, + Substitutions = bestMatch.Substitutions, + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static MatchResult GetBestMatchFromGroupWithValue(List group) + { + var bestMatch = group.First(); + + foreach (var match in group.Skip(1)) + { + if (match.Distance < bestMatch.Distance || match.Distance == bestMatch.Distance && (match.EndIndex - match.StartIndex) > (bestMatch.EndIndex - bestMatch.StartIndex)) + { + bestMatch = match; + } } + + return new MatchResult + { + StartIndex = bestMatch.StartIndex, + EndIndex = bestMatch.EndIndex, + Distance = bestMatch.Distance, + Match = bestMatch.Match, + Deletions = bestMatch.Deletions, + Insertions = bestMatch.Insertions, + Substitutions = bestMatch.Substitutions, + }; } -} \ No newline at end of file +} diff --git a/README.md b/README.md index 6a4fefe..a28173a 100644 --- a/README.md +++ b/README.md @@ -53,3 +53,8 @@ Searching for strings in strings public int Insertions { get; set; } } ``` + +# Performance considerations +Prefer limiting matching to substitutions only in case insertions and deletions are not needed. Substitution only matching is generally several orders of magnitude faster than Levenshtein distance with insertions and deletions. + +With small texts, the non async methods will put much less pressure on garbage collections. With larger texts, the streaming async methods can avoid reading the whole text into memory at the cost of more GC pressure. \ No newline at end of file