Skip to content

Commit 241880e

Browse files
committed
checkpoint
1 parent 1f2c3cb commit 241880e

57 files changed

Lines changed: 1703 additions & 1185 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

PolylineAlgorithm.slnx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
<Project Path="samples/PolylineAlgorithm.NetTopologySuite.Sample/PolylineAlgorithm.NetTopologySuite.Sample.csproj" Id="27a8fc47-0a3c-49c7-af5e-530514827785" />
1010
</Folder>
1111
<Folder Name="/src/">
12+
<Project Path="src/PolylineAlgorithm.Gps/PolylineAlgorithm.Gps.csproj" Id="816a7001-8faf-472e-8927-86286149a8d1" />
1213
<Project Path="src/PolylineAlgorithm/PolylineAlgorithm.csproj" />
1314
</Folder>
1415
<Folder Name="/tests/">
16+
<Project Path="tests/PolylineAlgorithm.Gps.Tests/PolylineAlgorithm.Gps.Tests.csproj" />
1517
<Project Path="tests/PolylineAlgorithm.Tests/PolylineAlgorithm.Tests.csproj" />
1618
</Folder>
1719
<Folder Name="/utilities/" Id="02ea681e-c7d8-13c7-8484-4ac65e1b71e8">

benchmarks/PolylineAlgorithm.Benchmarks/PolylineAlgorithm.Benchmarks.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
</ItemGroup>
2626

2727
<ItemGroup>
28+
<ProjectReference Include="..\..\src\PolylineAlgorithm.Gps\PolylineAlgorithm.Gps.csproj" />
2829
<ProjectReference Include="..\..\src\PolylineAlgorithm\PolylineAlgorithm.csproj" />
2930
<ProjectReference Include="..\..\utilities\PolylineAlgorithm.Utility\PolylineAlgorithm.Utility.csproj" />
3031
</ItemGroup>

benchmarks/PolylineAlgorithm.Benchmarks/PolylineBenchmark.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//
1+
//
22
// Copyright © Pete Sramek. All rights reserved.
33
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
44
//
@@ -8,6 +8,7 @@ namespace PolylineAlgorithm.Benchmarks;
88
using BenchmarkDotNet.Attributes;
99
using BenchmarkDotNet.Engines;
1010
using PolylineAlgorithm;
11+
using PolylineAlgorithm.Gps;
1112
using PolylineAlgorithm.Utility;
1213

1314
/// <summary>

benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//
1+
//
22
// Copyright © Pete Sramek. All rights reserved.
33
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
44
//
@@ -7,8 +7,8 @@ namespace PolylineAlgorithm.Benchmarks;
77

88
using BenchmarkDotNet.Attributes;
99
using BenchmarkDotNet.Engines;
10-
using PolylineAlgorithm;
11-
using PolylineAlgorithm.Extensions;
10+
using PolylineAlgorithm.Gps;
11+
using PolylineAlgorithm.Gps.Extensions;
1212
using PolylineAlgorithm.Utility;
1313

1414
/// <summary>

benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//
1+
//
22
// Copyright © Pete Sramek. All rights reserved.
33
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
44
//
@@ -7,8 +7,8 @@ namespace PolylineAlgorithm.Benchmarks;
77

88
using BenchmarkDotNet.Attributes;
99
using BenchmarkDotNet.Engines;
10-
using PolylineAlgorithm;
11-
using PolylineAlgorithm.Extensions;
10+
using PolylineAlgorithm.Gps;
11+
using PolylineAlgorithm.Gps.Extensions;
1212
using PolylineAlgorithm.Utility;
1313
using System.Collections.Generic;
1414

global.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
{
1+
{
22
"test": {
33
"runner": "Microsoft.Testing.Platform"
44
}
5-
}
5+
}

samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
//
1+
//
22
// Copyright © Pete Sramek. All rights reserved.
33
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
44
//
55

66
namespace PolylineAlgorithm.NetTopologySuite.Sample;
77

88
using global::NetTopologySuite.Geometries;
9-
using PolylineAlgorithm.Abstraction;
9+
using PolylineAlgorithm.Gps.Abstraction;
1010
using System;
1111

1212
/// <summary>

samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
//
1+
//
22
// Copyright © Pete Sramek. All rights reserved.
33
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
44
//
55

66
namespace PolylineAlgorithm.NetTopologySuite.Sample;
77

88
using global::NetTopologySuite.Geometries;
9-
using PolylineAlgorithm.Abstraction;
9+
using PolylineAlgorithm.Gps.Abstraction;
1010

1111
/// <summary>
1212
/// Polyline encoder using NetTopologySuite's Point type.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
</ItemGroup>
1414

1515
<ItemGroup>
16-
<ProjectReference Include="..\..\src\PolylineAlgorithm\PolylineAlgorithm.csproj" />
16+
<ProjectReference Include="..\..\src\PolylineAlgorithm.Gps\PolylineAlgorithm.Gps.csproj" />
1717
</ItemGroup>
1818

1919
</Project>

src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs renamed to src/PolylineAlgorithm.Gps/Abstraction/AbstractPolylineDecoder.cs

Lines changed: 76 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,47 @@
55

66
using Microsoft.Extensions.Logging;
77
using PolylineAlgorithm.Diagnostics;
8+
using PolylineAlgorithm.Gps.Internal;
89
using PolylineAlgorithm.Internal;
910
using PolylineAlgorithm.Internal.Diagnostics;
1011
using System.Runtime.CompilerServices;
1112

12-
namespace PolylineAlgorithm.Abstraction {
13+
namespace PolylineAlgorithm.Gps.Abstraction {
1314
/// <summary>
1415
/// Decodes encoded polyline strings into sequences of geographic coordinates.
15-
/// Implements the <see cref="IPolylineDecoder{TPolyline, TCoordinate}"/> interface.
16+
/// Implements the <see cref="IPolylineDecoder{TPolyline, TValue}"/> interface.
1617
/// </summary>
1718
/// <remarks>
18-
/// This abstract class provides a base implementation for decoding polylines, allowing subclasses to define how to handle specific polyline formats.
19+
/// This abstract class provides a base implementation for decoding polylines, allowing subclasses
20+
/// to define how to handle specific polyline input types and how decoded coordinates are represented.
21+
///
22+
/// The <see cref="Decode(TPolyline, CancellationToken)"/> method uses deferred execution and yields
23+
/// coordinates as they are decoded. Consumers should be aware that decoding occurs during enumeration;
24+
/// any exceptions (format errors, cancellations) are thrown when the returned <see cref="IEnumerable{T}"/>
25+
/// is iterated.
26+
///
27+
/// The class is safe to use concurrently for decoding different inputs, provided the concrete
28+
/// implementations of <see cref="GetReadOnlyMemory(in TPolyline)"/> and <see cref="CreateCoordinate(double, double)"/>
29+
/// are themselves thread-safe.
1930
/// </remarks>
20-
public abstract class AbstractPolylineDecoder<TPolyline, TCoordinate> : IPolylineDecoder<TPolyline, TCoordinate> {
21-
private readonly ILogger<AbstractPolylineDecoder<TPolyline, TCoordinate>> _logger;
31+
public abstract class AbstractPolylineDecoder<TPolyline, TValue> : IPolylineDecoder<TPolyline, TValue> {
32+
private readonly ILogger<AbstractPolylineDecoder<TPolyline, TValue>> _logger;
2233

2334
/// <summary>
24-
/// Initializes a new instance of the <see cref="AbstractPolylineDecoder{TPolyline, TCoordinate}"/> class with default encoding options.
35+
/// Initializes a new instance of the <see cref="AbstractPolylineDecoder{TPolyline, TValue}"/> class with default encoding options.
2536
/// </summary>
2637
protected AbstractPolylineDecoder()
2738
: this(new PolylineEncodingOptions()) { }
2839

2940
/// <summary>
30-
/// Initializes a new instance of the <see cref="AbstractPolylineDecoder{TPolyline, TCoordinate}"/> class with the specified encoding options.
41+
/// Initializes a new instance of the <see cref="AbstractPolylineDecoder{TPolyline, TValue}"/> class with the specified encoding options.
3142
/// </summary>
3243
/// <param name="options">
3344
/// The <see cref="PolylineEncodingOptions"/> to use for encoding operations.
45+
/// This value supplies settings such as numeric precision and a logger factory used to create diagnostic loggers.
3446
/// </param>
3547
/// <exception cref="ArgumentNullException">
36-
/// Thrown when <paramref name="options"/> is <see langword="null" />
48+
/// Thrown when <paramref name="options"/> is <see langword="null" />.
3749
/// </exception>
3850
protected AbstractPolylineDecoder(PolylineEncodingOptions options) {
3951
if (options is null) {
@@ -43,7 +55,7 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) {
4355
Options = options;
4456
_logger = Options
4557
.LoggerFactory
46-
.CreateLogger<AbstractPolylineDecoder<TPolyline, TCoordinate>>();
58+
.CreateLogger<AbstractPolylineDecoder<TPolyline, TValue>>();
4759
}
4860

4961
/// <summary>
@@ -56,27 +68,40 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) {
5668
/// </summary>
5769
/// <param name="polyline">The encoded polyline.</param>
5870
/// <param name="cancellationToken">Cancellation token.</param>
59-
/// <returns>Decoded coordinates.</returns>
60-
/// <exception cref="ArgumentNullException"/>
61-
/// <exception cref="ArgumentException"/>
62-
/// <exception cref="InvalidPolylineException"/>
63-
public IEnumerable<TCoordinate> Decode(TPolyline polyline, CancellationToken cancellationToken = default) {
71+
/// <returns>
72+
/// An <see cref="IEnumerable{T}"/> of <typeparamref name="TValue"/> produced by decoding the provided <paramref name="polyline"/>.
73+
/// The enumeration performs the decoding work lazily; exceptions for invalid input or cancellation are raised while enumerating.
74+
/// </returns>
75+
/// <exception cref="ArgumentNullException">
76+
/// Thrown when <paramref name="polyline"/> is <see langword="null"/>.
77+
/// </exception>
78+
/// <exception cref="ArgumentException">
79+
/// Thrown when the polyline contains invalid characters or an otherwise invalid format.
80+
/// </exception>
81+
/// <exception cref="InvalidPolylineException">
82+
/// Thrown when the polyline does not meet minimum structural requirements (for example, too short),
83+
/// or when decoding finds an incomplete coordinate pair.
84+
/// </exception>
85+
/// <exception cref="OperationCanceledException">
86+
/// Thrown when the provided <paramref name="cancellationToken"/> requests cancellation during decoding.
87+
/// </exception>
88+
public IEnumerable<TValue> Decode(TPolyline polyline, CancellationToken cancellationToken = default) {
6489
const string OperationName = nameof(Decode);
6590

66-
_logger?.LogOperationStartedDebug(OperationName);
91+
try {
92+
_logger?.LogOperationStartedDebug(OperationName);
6793

68-
ValidateNullPolyline(polyline, _logger);
94+
ValidateNullPolyline(polyline, _logger);
6995

70-
ReadOnlyMemory<char> sequence = GetReadOnlyMemory(in polyline);
96+
ReadOnlyMemory<char> sequence = GetReadOnlyMemory(in polyline);
7197

72-
ValidateSequence(sequence, _logger);
73-
ValidateFormat(sequence, _logger);
98+
ValidateSequence(sequence, _logger);
99+
ValidateFormat(sequence, _logger);
74100

75-
int position = 0;
76-
int encodedLatitude = 0;
77-
int encodedLongitude = 0;
101+
int position = 0;
102+
int encodedLatitude = 0;
103+
int encodedLongitude = 0;
78104

79-
try {
80105
while (position < sequence.Length) {
81106
cancellationToken.ThrowIfCancellationRequested();
82107

@@ -130,17 +155,26 @@ private static void ValidateNullPolyline(TPolyline polyline, ILogger? logger) {
130155
/// </exception>
131156
[MethodImpl(MethodImplOptions.AggressiveInlining)]
132157
private static void ValidateSequence(ReadOnlyMemory<char> polylineSequence, ILogger? logger) {
133-
if (polylineSequence.Length < Defaults.Polyline.Block.Length.Min) {
158+
const int minLength = 2;
159+
160+
if (polylineSequence.Length < minLength) {
134161
logger?.LogOperationFailedDebug(nameof(Decode));
135-
logger?.LogPolylineCannotBeShorterThanWarning(polylineSequence.Length, Defaults.Polyline.Block.Length.Min);
162+
logger?.LogPolylineCannotBeShorterThanWarning(polylineSequence.Length, 2);
136163

137-
ExceptionGuard.ThrowInvalidPolylineLength(polylineSequence.Length, Defaults.Polyline.Block.Length.Min);
164+
ExceptionGuard.ThrowInvalidPolylineLength(polylineSequence.Length, minLength);
138165
}
139166
}
140167

141168
/// <summary>
142-
/// Validates the polyline format for allowed characters.
169+
/// Validates the polyline format for allowed characters and structural expectations.
143170
/// </summary>
171+
/// <param name="sequence">The character sequence representing the polyline to validate.</param>
172+
/// <param name="logger">Optional logger used to emit diagnostics when validation fails.</param>
173+
/// <remarks>
174+
/// The default implementation delegates to <see cref="PolylineEncoding.ValidateFormat(ReadOnlySpan{char})"/>.
175+
/// Subclasses MAY override this method to accept alternative encodings or to provide additional validation rules.
176+
/// When validation fails an <see cref="ArgumentException"/> is thrown and a diagnostic warning is logged if a logger is provided.
177+
/// </remarks>
144178
[MethodImpl(MethodImplOptions.AggressiveInlining)]
145179
protected virtual void ValidateFormat(ReadOnlyMemory<char> sequence, ILogger? logger) {
146180
try {
@@ -152,10 +186,24 @@ protected virtual void ValidateFormat(ReadOnlyMemory<char> sequence, ILogger? lo
152186
}
153187
}
154188

189+
/// <summary>
190+
/// Converts the input <typeparamref name="TPolyline"/> into a <see cref="ReadOnlyMemory{Char}"/> suitable for decoding.
191+
/// </summary>
192+
/// <param name="polyline">The polyline input instance. Implementations receive the value by reference to avoid copies where possible.</param>
193+
/// <returns>
194+
/// A <see cref="ReadOnlyMemory{Char}"/> containing the characters to decode.
195+
/// Implementations should avoid allocating when possible and may return a memory slice of the original input.
196+
/// </returns>
155197
[MethodImpl(MethodImplOptions.AggressiveInlining)]
156198
protected abstract ReadOnlyMemory<char> GetReadOnlyMemory(in TPolyline polyline);
157199

200+
/// <summary>
201+
/// Creates a coordinate instance of type <typeparamref name="TValue"/> from decoded latitude and longitude.
202+
/// </summary>
203+
/// <param name="latitude">Decoded latitude value in decimal degrees.</param>
204+
/// <param name="longitude">Decoded longitude value in decimal degrees.</param>
205+
/// <returns>A <typeparamref name="TValue"/> representing the decoded coordinate pair.</returns>
158206
[MethodImpl(MethodImplOptions.AggressiveInlining)]
159-
protected abstract TCoordinate CreateCoordinate(double latitude, double longitude);
207+
protected abstract TValue CreateCoordinate(double latitude, double longitude);
160208
}
161209
}

0 commit comments

Comments
 (0)