Skip to content

Commit c131987

Browse files
committed
performance imporvements
1 parent 0cb85c7 commit c131987

26 files changed

Lines changed: 170 additions & 159 deletions

Directory.Build.props

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<Project>
2+
3+
<PropertyGroup>
4+
<LangVersion>14.0</LangVersion>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<InvariantGlobalization>true</InvariantGlobalization>
8+
<NeutralLanguage>en</NeutralLanguage>
9+
</PropertyGroup>
10+
11+
<PropertyGroup>
12+
<AnalysisLevel>latest</AnalysisLevel>
13+
<AnalysisMode>All</AnalysisMode>
14+
<EnableNETAnalyzers>true</EnableNETAnalyzers>
15+
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
16+
</PropertyGroup>
17+
18+
<ItemGroup>
19+
<PackageReference Include="Meziantou.Analyzer" />
20+
<PackageReference Include="Roslynator.Analyzers" />
21+
<PackageReference Include="SonarAnalyzer.CSharp" />
22+
</ItemGroup>
23+
24+
</Project>

Directory.Packages.props

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<Project>
2+
<PropertyGroup>
3+
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
4+
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
5+
<NoWarn>$(NoWarn);NU1507</NoWarn>
6+
</PropertyGroup>
7+
<ItemGroup>
8+
<PackageVersion Include="Meziantou.Analyzer" Version="3.0.19" />
9+
<PackageVersion Include="Roslynator.Analyzers" Version="4.15.0" />
10+
<PackageVersion Include="SonarAnalyzer.CSharp" Version="10.20.0.135146" />
11+
<PackageVersion Include="NetTopologySuite" Version="2.6.0" />
12+
<PackageVersion Include="BenchmarkDotNet" Version="0.15.8" />
13+
<PackageVersion Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.15.8" />
14+
<PackageVersion Include="Microsoft.VisualStudio.DiagnosticsHub.BenchmarkDotNetDiagnosers" Version="18.3.36812.1" />
15+
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
16+
<PackageVersion Include="MSTest" Version="4.1.0" />
17+
<PackageVersion Include="Microsoft.Testing.Platform.MSBuild" Version="2.1.0" />
18+
<PackageVersion Include="Microsoft.Testing.Extensions.CodeCoverage" Version="18.5.2" />
19+
<PackageVersion Include="Microsoft.Testing.Extensions.TrxReport" Version="2.1.0" />
20+
<PackageVersion Include="Microsoft.Extensions.Diagnostics.Testing" Version="10.3.0" />
21+
<PackageVersion Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="4.0.0" />
22+
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.3" />
23+
</ItemGroup>
24+
</Project>

PolylineAlgorithm.slnx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
<Solution>
2+
<Folder Name="/.build/">
3+
<File Path="Directory.Build.props" />
4+
<File Path="Directory.Packages.props" />
5+
</Folder>
26
<Folder Name="/benchmarks/">
37
<Project Path="benchmarks/PolylineAlgorithm.Benchmarks/PolylineAlgorithm.Benchmarks.csproj" />
48
</Folder>

benchmarks/PolylineAlgorithm.Benchmarks/PolylineAlgorithm.Benchmarks.csproj

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,7 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFrameworks>net8.0;net9.0;net10.0;</TargetFrameworks>
6-
<LangVersion>14.0</LangVersion>
7-
<Nullable>enable</Nullable>
8-
<ImplicitUsings>enable</ImplicitUsings>
9-
<InvariantGlobalization>true</InvariantGlobalization>
10-
<NeutralLanguage>en</NeutralLanguage>
5+
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
116
</PropertyGroup>
127

138
<PropertyGroup>
@@ -20,9 +15,9 @@
2015
</PropertyGroup>
2116

2217
<ItemGroup>
23-
<PackageReference Include="BenchmarkDotNet" Version="0.15.*" />
24-
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.15.8" />
25-
<PackageReference Include="Microsoft.VisualStudio.DiagnosticsHub.BenchmarkDotNetDiagnosers" Version="18.3.36812.1" />
18+
<PackageReference Include="BenchmarkDotNet" />
19+
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" />
20+
<PackageReference Include="Microsoft.VisualStudio.DiagnosticsHub.BenchmarkDotNetDiagnosers" />
2621
</ItemGroup>
2722

2823
<ItemGroup>

benchmarks/PolylineAlgorithm.Benchmarks/PolylineBenchmark.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public class PolylineBenchmark {
1818
private static readonly Consumer _consumer = new();
1919

2020
[Params(1, 100, 1_000)]
21-
public int Count;
21+
public int CoordinatesCount;
2222

2323
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
2424
/// <summary>
@@ -56,8 +56,8 @@ public class PolylineBenchmark {
5656
/// </summary>
5757
[GlobalSetup]
5858
public void SetupData() {
59-
PolylineValue = Polyline.FromString(RandomValueProvider.GetPolyline(Count));
60-
PolylineNotEqualValue = Polyline.FromString(RandomValueProvider.GetPolyline(Count + Random.Shared.Next(1, 101)));
59+
PolylineValue = Polyline.FromString(RandomValueProvider.GetPolyline(CoordinatesCount));
60+
PolylineNotEqualValue = Polyline.FromString(RandomValueProvider.GetPolyline(CoordinatesCount + Random.Shared.Next(1, 101)));
6161
StringValue = PolylineValue.ToString();
6262
CharArrayValue = [.. StringValue];
6363
MemoryValue = CharArrayValue.AsMemory();

benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public class PolylineDecoderBenchmark {
1919
private readonly Consumer _consumer = new();
2020

2121
[Params(1, 100, 1_000)]
22-
public int Count;
22+
public int CoordinatesCount;
2323

2424
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
2525
/// <summary>
@@ -54,10 +54,10 @@ public class PolylineDecoderBenchmark {
5454
/// </summary>
5555
[GlobalSetup]
5656
public void SetupData() {
57-
Polyline = Polyline.FromString(RandomValueProvider.GetPolyline(Count));
58-
String = RandomValueProvider.GetPolyline(Count);
59-
CharArray = RandomValueProvider.GetPolyline(Count).ToCharArray();
60-
Memory = RandomValueProvider.GetPolyline(Count).AsMemory();
57+
Polyline = Polyline.FromString(RandomValueProvider.GetPolyline(CoordinatesCount));
58+
String = RandomValueProvider.GetPolyline(CoordinatesCount);
59+
CharArray = RandomValueProvider.GetPolyline(CoordinatesCount).ToCharArray();
60+
Memory = RandomValueProvider.GetPolyline(CoordinatesCount).AsMemory();
6161
}
6262

6363
/// <summary>

benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public class PolylineEncoderBenchmark {
2020
private readonly Consumer _consumer = new();
2121

2222
[Params(1, 100, 1_000)]
23-
public int Count;
23+
public int CoordinatesCount;
2424

2525
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
2626
/// <summary>
@@ -50,7 +50,7 @@ public class PolylineEncoderBenchmark {
5050
/// </summary>
5151
[GlobalSetup]
5252
public void SetupData() {
53-
List = RandomValueProvider.GetCoordinates(Count).Select(c => new Coordinate(c.Latitude, c.Longitude)).ToList();
53+
List = RandomValueProvider.GetCoordinates(CoordinatesCount).Select(c => new Coordinate(c.Latitude, c.Longitude)).ToList();
5454
Array = [.. List];
5555
Memory = Array.AsMemory();
5656
}

samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public sealed class NetTopologyPolylineEncoder : AbstractPolylineEncoder<Point,
2121
/// <returns>
2222
/// An encoded polyline string representation of the provided polyline.
2323
/// </returns>
24-
protected override string CreatePolyline(ReadOnlyMemory<char> polyline) {
24+
protected override string CreatePolyline(ref ReadOnlyMemory<char> polyline) {
2525
if (polyline.IsEmpty) {
2626
return string.Empty;
2727
}

samples/PolylineAlgorithm.NetTopologySuite.Sample/PolylineAlgorithm.NetTopologySuite.Sample.csproj

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,18 @@
22

33
<PropertyGroup>
44
<TargetFramework>netstandard2.1</TargetFramework>
5-
<LangVersion>13.0</LangVersion>
6-
<Nullable>enable</Nullable>
7-
<ImplicitUsings>enable</ImplicitUsings>
8-
<InvariantGlobalization>true</InvariantGlobalization>
9-
<NeutralLanguage>en</NeutralLanguage>
10-
</PropertyGroup>
11-
12-
<PropertyGroup>
13-
<AnalysisMode>All</AnalysisMode>
14-
<AnalysisLevel>latest</AnalysisLevel>
15-
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
16-
<EnableNETAnalyzers>true</EnableNETAnalyzers>
175
</PropertyGroup>
186

197
<PropertyGroup>
208
<IsPackable>false</IsPackable>
219
</PropertyGroup>
2210

2311
<ItemGroup>
24-
<PackageReference Include="NetTopologySuite" Version="2.6.0" />
12+
<PackageReference Include="NetTopologySuite" />
2513
</ItemGroup>
2614

2715
<ItemGroup>
2816
<ProjectReference Include="..\..\src\PolylineAlgorithm\PolylineAlgorithm.csproj" />
2917
</ItemGroup>
3018

31-
</Project>
19+
</Project>

src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ namespace PolylineAlgorithm.Abstraction;
2121
/// This abstract class provides a base implementation for decoding polylines, allowing subclasses to define how to handle specific polyline formats.
2222
/// </remarks>
2323
public abstract class AbstractPolylineDecoder<TPolyline, TCoordinate> : IPolylineDecoder<TPolyline, TCoordinate> {
24+
private readonly ILogger<AbstractPolylineDecoder<TPolyline, TCoordinate>> _logger;
2425
/// <summary>
2526
/// Initializes a new instance of the <see cref="AbstractPolylineDecoder{TPolyline, TCoordinate}"/> class with default encoding options.
2627
/// </summary>
@@ -38,10 +39,13 @@ protected AbstractPolylineDecoder()
3839
/// </exception>
3940
protected AbstractPolylineDecoder(PolylineEncodingOptions options) {
4041
Options = options ?? throw new ArgumentNullException(nameof(options));
42+
_logger = Options
43+
.LoggerFactory
44+
.CreateLogger<AbstractPolylineDecoder<TPolyline, TCoordinate>>();
4145
}
4246

4347
/// <summary>
44-
/// Gets the encoding options used by this polyline encoder.
48+
/// Gets the encoding options used by this polyline decoder.
4549
/// </summary>
4650
public PolylineEncodingOptions Options { get; }
4751

@@ -56,57 +60,50 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) {
5660
/// </returns>
5761
/// <exception cref="ArgumentNullException">
5862
/// Thrown when <paramref name="polyline"/> is <see langword="null"/>.
59-
/// </exception>"
63+
/// </exception>
6064
/// <exception cref="ArgumentException">
6165
/// Thrown when <paramref name="polyline"/> is empty.
6266
/// </exception>
6367
/// <exception cref="InvalidPolylineException">
6468
/// Thrown when the polyline format is invalid or malformed at a specific position.
6569
/// </exception>
6670
public IEnumerable<TCoordinate> Decode(TPolyline polyline) {
67-
var logger = Options
68-
.LoggerFactory
69-
.CreateLogger<AbstractPolylineDecoder<TPolyline, TCoordinate>>();
71+
const string OperationName = nameof(Decode);
7072

71-
logger.
72-
LogOperationStartedInfo(nameof(Decode));
73+
_logger.
74+
LogOperationStartedDebug(OperationName);
7375

74-
ValidateNullPolyline(polyline, logger);
76+
ValidateNullPolyline(ref polyline, _logger);
7577

7678
ReadOnlyMemory<char> sequence = GetReadOnlyMemory(polyline);
7779

78-
ValidateEmptySequence(logger, sequence);
80+
ValidateEmptySequence(ref sequence, _logger);
7981

8082
int position = 0;
8183
int latitude = 0;
8284
int longitude = 0;
8385

84-
while (true) {
85-
// Check if we have reached the end of the sequence
86-
if (position >= sequence.Length) {
87-
break;
88-
}
89-
86+
while (position < sequence.Length) {
9087
// Read the next value from the polyline encoding
9188
if (!PolylineEncoding.TryReadValue(ref latitude, ref sequence, ref position)
9289
|| !PolylineEncoding.TryReadValue(ref longitude, ref sequence, ref position)
9390
) {
94-
logger
91+
_logger.
92+
LogOperationFailedDebug(OperationName);
93+
_logger
9594
.LogInvalidPolylineWarning(position);
96-
logger.
97-
LogOperationFailedInfo(nameof(Decode));
9895

9996
InvalidPolylineException.Throw(position);
10097
}
10198

10299
yield return CreateCoordinate(PolylineEncoding.Denormalize(latitude, CoordinateValueType.Latitude), PolylineEncoding.Denormalize(longitude, CoordinateValueType.Longitude));
103100
}
104101

105-
logger
106-
.LogOperationFinishedInfo(nameof(Decode));
102+
_logger
103+
.LogOperationFinishedDebug(OperationName);
107104

108105
[MethodImpl(MethodImplOptions.AggressiveInlining)]
109-
static void ValidateNullPolyline(TPolyline polyline, ILogger logger) {
106+
static void ValidateNullPolyline(ref TPolyline polyline, ILogger logger) {
110107
if (polyline is null) {
111108
logger
112109
.LogNullArgumentWarning(nameof(polyline));
@@ -116,14 +113,14 @@ static void ValidateNullPolyline(TPolyline polyline, ILogger logger) {
116113
}
117114

118115
[MethodImpl(MethodImplOptions.AggressiveInlining)]
119-
static void ValidateEmptySequence(ILogger logger, ReadOnlyMemory<char> sequence) {
120-
if (sequence.Length < Defaults.Polyline.Block.Length.Min) {
121-
logger
122-
.LogPolylineCannotBeShorterThanWarning(nameof(polyline), sequence.Length, Defaults.Polyline.Block.Length.Min);
116+
static void ValidateEmptySequence(ref ReadOnlyMemory<char> polyline, ILogger logger) {
117+
if (polyline.Length < Defaults.Polyline.Block.Length.Min) {
123118
logger.
124-
LogOperationFailedInfo(nameof(Decode));
119+
LogOperationFailedDebug(OperationName);
120+
logger
121+
.LogPolylineCannotBeShorterThanWarning(nameof(polyline), polyline.Length, Defaults.Polyline.Block.Length.Min);
125122

126-
throw new ArgumentException(string.Format(ExceptionMessageResource.PolylineCannotBeShorterThanExceptionMessage, sequence.Length), nameof(polyline));
123+
throw new ArgumentException(string.Format(ExceptionMessageResource.PolylineCannotBeShorterThanExceptionMessage, polyline.Length, Defaults.Polyline.Block.Length.Min), nameof(polyline));
127124
}
128125
}
129126
}

0 commit comments

Comments
 (0)