Skip to content

Commit 3b971cc

Browse files
Copilotpetesramek
andauthored
fix: update all callers of AbstractPolylineEncoder/Decoder and PolylineEncodingOptions to new API
Agent-Logs-Url: https://github.com/petesramek/polyline-algorithm-csharp/sessions/01588b5e-a054-44f2-8639-946d11b55609 Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com>
1 parent 8f35f95 commit 3b971cc

12 files changed

Lines changed: 411 additions & 601 deletions

File tree

benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ namespace PolylineAlgorithm.Benchmarks;
77

88
using BenchmarkDotNet.Attributes;
99
using BenchmarkDotNet.Engines;
10-
using PolylineAlgorithm.Abstraction;
10+
using PolylineAlgorithm;
1111
using PolylineAlgorithm.Utility;
1212

1313
/// <summary>
14-
/// Benchmarks for <see cref="PolylineDecoder"/>.
14+
/// Benchmarks for <see cref="PolylineDecoder{TPolyline, TCoordinate}"/>.
1515
/// </summary>
1616
public class PolylineDecoderBenchmark {
1717
private readonly Consumer _consumer = new();
@@ -40,17 +40,50 @@ public class PolylineDecoderBenchmark {
4040
/// <summary>
4141
/// String polyline decoder instance.
4242
/// </summary>
43-
private readonly StringPolylineDecoder _stringDecoder = new();
43+
private readonly PolylineDecoder<string, (double Latitude, double Longitude)> _stringDecoder = CreateStringDecoder();
4444

4545
/// <summary>
4646
/// Char array polyline decoder instance.
4747
/// </summary>
48-
private readonly CharArrayPolylineDecoder _charArrayDecoder = new();
48+
private readonly PolylineDecoder<char[], (double Latitude, double Longitude)> _charArrayDecoder = CreateCharArrayDecoder();
4949

5050
/// <summary>
51-
/// String polyline decoder instance.
51+
/// Memory char polyline decoder instance.
5252
/// </summary>
53-
private readonly MemoryCharPolylineDecoder _memoryCharDecoder = new();
53+
private readonly PolylineDecoder<ReadOnlyMemory<char>, (double Latitude, double Longitude)> _memoryCharDecoder = CreateMemoryDecoder();
54+
55+
private static PolylineFormatter<(double Latitude, double Longitude), T> BuildFormatter<T>(
56+
Func<ReadOnlyMemory<char>, T> write, Func<T, ReadOnlyMemory<char>> read) =>
57+
FormatterBuilder<(double Latitude, double Longitude), T>.Create()
58+
.AddValue("lat", static c => c.Latitude)
59+
.AddValue("lon", static c => c.Longitude)
60+
.WithCreate(static v => (v[0] / 1e5, v[1] / 1e5))
61+
.ForPolyline(write, read)
62+
.Build();
63+
64+
private static PolylineDecoder<string, (double Latitude, double Longitude)> CreateStringDecoder() {
65+
var fmt = BuildFormatter<string>(
66+
static m => new string(m.Span),
67+
static s => s?.AsMemory() ?? Memory<char>.Empty);
68+
return new PolylineDecoder<string, (double Latitude, double Longitude)>(
69+
new PolylineOptions<(double Latitude, double Longitude), string>(fmt));
70+
}
71+
72+
private static PolylineDecoder<char[], (double Latitude, double Longitude)> CreateCharArrayDecoder() {
73+
var fmt = BuildFormatter<char[]>(
74+
static m => m.ToArray(),
75+
static a => a?.AsMemory() ?? Memory<char>.Empty);
76+
return new PolylineDecoder<char[], (double Latitude, double Longitude)>(
77+
new PolylineOptions<(double Latitude, double Longitude), char[]>(fmt));
78+
}
79+
80+
private static PolylineDecoder<ReadOnlyMemory<char>, (double Latitude, double Longitude)> CreateMemoryDecoder() {
81+
var fmt = BuildFormatter<ReadOnlyMemory<char>>(
82+
static m => m,
83+
static m => m);
84+
return new PolylineDecoder<ReadOnlyMemory<char>, (double Latitude, double Longitude)>(
85+
new PolylineOptions<(double Latitude, double Longitude), ReadOnlyMemory<char>>(fmt));
86+
}
5487

5588
/// <summary>
5689
/// Sets up benchmark data.
@@ -91,34 +124,4 @@ public void PolylineDecoder_Decode_Memory() {
91124
.Decode(Memory)
92125
.Consume(_consumer);
93126
}
94-
95-
private sealed class StringPolylineDecoder : AbstractPolylineDecoder<string, (double Latitude, double Longitude)> {
96-
protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) {
97-
return (latitude, longitude);
98-
}
99-
100-
protected override ReadOnlyMemory<char> GetReadOnlyMemory(in string polyline) {
101-
return polyline?.AsMemory() ?? Memory<char>.Empty;
102-
}
103-
}
104-
105-
private sealed class CharArrayPolylineDecoder : AbstractPolylineDecoder<char[], (double Latitude, double Longitude)> {
106-
protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) {
107-
return (latitude, longitude);
108-
}
109-
110-
protected override ReadOnlyMemory<char> GetReadOnlyMemory(in char[] polyline) {
111-
return polyline?.AsMemory() ?? Memory<char>.Empty;
112-
}
113-
}
114-
115-
private sealed class MemoryCharPolylineDecoder : AbstractPolylineDecoder<ReadOnlyMemory<char>, (double Latitude, double Longitude)> {
116-
protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) {
117-
return (latitude, longitude);
118-
}
119-
120-
protected override ReadOnlyMemory<char> GetReadOnlyMemory(in ReadOnlyMemory<char> polyline) {
121-
return polyline;
122-
}
123-
}
124-
}
127+
}

benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
1-
//
2-
// Copyright © Pete Sramek. All rights reserved.
3-
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
4-
//
5-
61
namespace PolylineAlgorithm.Benchmarks;
72

83
using BenchmarkDotNet.Attributes;
94
using BenchmarkDotNet.Engines;
10-
using PolylineAlgorithm.Abstraction;
5+
using PolylineAlgorithm;
116
using PolylineAlgorithm.Extensions;
127
using PolylineAlgorithm.Utility;
138
using System.Collections.Generic;
149

1510
/// <summary>
16-
/// Benchmarks for <see cref="AbstractPolylineEncoder{TCoordinate, TPolyline}"/>.
11+
/// Benchmarks for <see cref="PolylineEncoder{TCoordinate, TPolyline}"/>.
1712
/// </summary>
1813
public class PolylineEncoderBenchmark {
1914
private readonly Consumer _consumer = new();
@@ -45,7 +40,19 @@ public class PolylineEncoderBenchmark {
4540
/// <summary>
4641
/// Polyline encoder instance.
4742
/// </summary>
48-
private readonly StringPolylineEncoder _encoder = new();
43+
private readonly PolylineEncoder<(double Latitude, double Longitude), string> _encoder = CreateEncoder();
44+
45+
private static PolylineEncoder<(double Latitude, double Longitude), string> CreateEncoder() {
46+
PolylineFormatter<(double Latitude, double Longitude), string> formatter =
47+
FormatterBuilder<(double Latitude, double Longitude), string>.Create()
48+
.AddValue("lat", static c => c.Latitude)
49+
.AddValue("lon", static c => c.Longitude)
50+
.ForPolyline(static m => new string(m.Span), static s => s.AsMemory())
51+
.Build();
52+
53+
return new PolylineEncoder<(double Latitude, double Longitude), string>(
54+
new PolylineOptions<(double Latitude, double Longitude), string>(formatter));
55+
}
4956

5057
/// <summary>
5158
/// Sets up benchmark data.
@@ -83,10 +90,4 @@ public void PolylineEncoder_Encode_List() {
8390
var polyline = _encoder.Encode(List);
8491
_consumer.Consume(polyline);
8592
}
86-
87-
private sealed class StringPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
88-
protected override string CreatePolyline(ReadOnlyMemory<char> polyline) => polyline.ToString();
89-
protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude;
90-
protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude;
91-
}
9293
}

samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,37 @@
66
namespace PolylineAlgorithm.NetTopologySuite.Sample;
77

88
using global::NetTopologySuite.Geometries;
9+
using PolylineAlgorithm;
910
using PolylineAlgorithm.Abstraction;
10-
using System;
11+
using System.Collections.Generic;
12+
using System.Threading;
1113

1214
/// <summary>
1315
/// Polyline decoder using NetTopologySuite.
1416
/// </summary>
15-
internal sealed class NetTopologyPolylineDecoder : AbstractPolylineDecoder<string, Point> {
16-
/// <summary>
17-
/// Creates a NetTopologySuite point from latitude and longitude.
18-
/// </summary>
19-
/// <param name="latitude">Latitude value.</param>
20-
/// <param name="longitude">Longitude value.</param>
21-
/// <returns>Point instance.</returns>
22-
protected override Point CreateCoordinate(double latitude, double longitude) {
23-
// NetTopologySuite Point: x = longitude, y = latitude
24-
return new Point(longitude, latitude);
25-
}
17+
internal sealed class NetTopologyPolylineDecoder : IPolylineDecoder<string, Point> {
18+
private readonly PolylineDecoder<string, Point> _inner;
2619

2720
/// <summary>
28-
/// Converts polyline string to read-only memory.
21+
/// Initializes a new instance of the <see cref="NetTopologyPolylineDecoder"/> class.
2922
/// </summary>
30-
/// <param name="polyline">Encoded polyline string.</param>
31-
/// <returns>ReadOnlyMemory of characters.</returns>
32-
protected override ReadOnlyMemory<char> GetReadOnlyMemory(in string polyline) {
33-
return polyline.AsMemory();
23+
internal NetTopologyPolylineDecoder() {
24+
PolylineFormatter<Point, string> formatter =
25+
FormatterBuilder<Point, string>.Create()
26+
// NetTopologySuite Point: Y = latitude, X = longitude
27+
.AddValue("lat", static p => p.Y)
28+
.AddValue("lon", static p => p.X)
29+
// v[0] = scaled latitude, v[1] = scaled longitude (factor = 1e5 for default precision 5)
30+
.WithCreate(static v => new Point(x: v[1] / 1e5, y: v[0] / 1e5))
31+
.ForPolyline(
32+
static m => m.IsEmpty ? string.Empty : new string(m.Span),
33+
static s => s.AsMemory())
34+
.Build();
35+
36+
_inner = new PolylineDecoder<string, Point>(new PolylineOptions<Point, string>(formatter));
3437
}
38+
39+
/// <inheritdoc/>
40+
public IEnumerable<Point> Decode(string polyline, CancellationToken cancellationToken = default)
41+
=> _inner.Decode(polyline, cancellationToken);
3542
}

samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,46 +6,34 @@
66
namespace PolylineAlgorithm.NetTopologySuite.Sample;
77

88
using global::NetTopologySuite.Geometries;
9+
using PolylineAlgorithm;
910
using PolylineAlgorithm.Abstraction;
11+
using System.Threading;
1012

1113
/// <summary>
1214
/// Polyline encoder using NetTopologySuite's Point type.
1315
/// </summary>
14-
internal sealed class NetTopologyPolylineEncoder : AbstractPolylineEncoder<Point, string> {
15-
/// <summary>
16-
/// Creates encoded polyline string from memory.
17-
/// </summary>
18-
/// <param name="polyline">Polyline memory.</param>
19-
/// <returns>Encoded polyline string.</returns>
20-
protected override string CreatePolyline(ReadOnlyMemory<char> polyline) {
21-
if (polyline.IsEmpty) {
22-
return string.Empty;
23-
}
24-
25-
return polyline.ToString();
26-
}
16+
internal sealed class NetTopologyPolylineEncoder : IPolylineEncoder<Point, string> {
17+
private readonly PolylineEncoder<Point, string> _inner;
2718

2819
/// <summary>
29-
/// Gets latitude from point.
20+
/// Initializes a new instance of the <see cref="NetTopologyPolylineEncoder"/> class.
3021
/// </summary>
31-
/// <param name="current">Point instance.</param>
32-
/// <returns>Latitude value.</returns>
33-
protected override double GetLatitude(Point current) {
34-
ArgumentNullException.ThrowIfNull(current);
35-
36-
// NetTopologySuite Point: Y = latitude
37-
return current.Y;
22+
internal NetTopologyPolylineEncoder() {
23+
PolylineFormatter<Point, string> formatter =
24+
FormatterBuilder<Point, string>.Create()
25+
// NetTopologySuite Point: Y = latitude, X = longitude
26+
.AddValue("lat", static p => { ArgumentNullException.ThrowIfNull(p); return p.Y; })
27+
.AddValue("lon", static p => { ArgumentNullException.ThrowIfNull(p); return p.X; })
28+
.ForPolyline(
29+
static m => m.IsEmpty ? string.Empty : new string(m.Span),
30+
static s => s.AsMemory())
31+
.Build();
32+
33+
_inner = new PolylineEncoder<Point, string>(new PolylineOptions<Point, string>(formatter));
3834
}
3935

40-
/// <summary>
41-
/// Gets longitude from point.
42-
/// </summary>
43-
/// <param name="current">Point instance.</param>
44-
/// <returns>Longitude value.</returns>
45-
protected override double GetLongitude(Point current) {
46-
ArgumentNullException.ThrowIfNull(current);
47-
48-
// NetTopologySuite Point: X = longitude
49-
return current.X;
50-
}
36+
/// <inheritdoc/>
37+
public string Encode(ReadOnlySpan<Point> coordinates, CancellationToken cancellationToken = default)
38+
=> _inner.Encode(coordinates, cancellationToken);
5139
}

samples/PolylineAlgorithm.SensorData.Sample/SensorDataDecoder.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ namespace PolylineAlgorithm.SensorData.Sample;
1616
/// <remarks>
1717
/// <para>
1818
/// This class demonstrates implementing <see cref="IPolylineDecoder{TPolyline,TValue}"/> for a custom
19-
/// scalar type, following the same structural pattern as <see cref="AbstractPolylineDecoder{TPolyline,TCoordinate}"/>.
19+
/// scalar type, following the same structural pattern as a custom polyline decoder.
2020
/// </para>
2121
/// <para>
2222
/// Each encoded pair consists of a delta-compressed Unix timestamp (seconds since Unix epoch, precision 0)
23-
/// followed by a delta-compressed temperature value (at <see cref="PolylineEncodingOptions.Precision"/>).
23+
/// followed by a delta-compressed temperature value (at <see cref="SensorEncodingOptions.Precision"/>).
2424
/// Both are recovered and used to reconstruct the original <see cref="SensorReading"/>.
2525
/// </para>
2626
/// </remarks>
@@ -30,19 +30,19 @@ internal sealed class SensorDataDecoder : IPolylineDecoder<string, SensorReading
3030
/// Initializes a new instance of the <see cref="SensorDataDecoder"/> class with default encoding options.
3131
/// </summary>
3232
public SensorDataDecoder()
33-
: this(new PolylineEncodingOptions()) { }
33+
: this(new SensorEncodingOptions()) { }
3434

3535
/// <summary>
3636
/// Initializes a new instance of the <see cref="SensorDataDecoder"/> class with the specified encoding options.
3737
/// </summary>
3838
/// <param name="options">
39-
/// The <see cref="PolylineEncodingOptions"/> to use for decoding operations.
40-
/// The <see cref="PolylineEncodingOptions.Precision"/> value must match the precision used during encoding.
39+
/// The <see cref="SensorEncodingOptions"/> to use for decoding operations.
40+
/// The <see cref="SensorEncodingOptions.Precision"/> value must match the precision used during encoding.
4141
/// </param>
4242
/// <exception cref="ArgumentNullException">
4343
/// Thrown when <paramref name="options"/> is <see langword="null"/>.
4444
/// </exception>
45-
public SensorDataDecoder(PolylineEncodingOptions options) {
45+
public SensorDataDecoder(SensorEncodingOptions options) {
4646
ArgumentNullException.ThrowIfNull(options);
4747

4848
Options = options;
@@ -51,7 +51,7 @@ public SensorDataDecoder(PolylineEncodingOptions options) {
5151
/// <summary>
5252
/// Gets the encoding options used by this decoder.
5353
/// </summary>
54-
public PolylineEncodingOptions Options { get; }
54+
public SensorEncodingOptions Options { get; }
5555

5656
/// <summary>
5757
/// Decodes a polyline string back into a sequence of <see cref="SensorReading"/> values.

samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@ namespace PolylineAlgorithm.SensorData.Sample;
1717
/// <remarks>
1818
/// <para>
1919
/// This class demonstrates implementing <see cref="IPolylineEncoder{TValue,TPolyline}"/> for a custom
20-
/// scalar type, following the same structural pattern as <see cref="AbstractPolylineEncoder{TCoordinate,TPolyline}"/>.
20+
/// scalar type, following the same structural pattern as a custom polyline encoder.
2121
/// </para>
2222
/// <para>
23-
/// Because sensor readings carry two numeric dimensions (timestamp and temperature), the base class designed
23+
/// Because sensor readings carry two numeric dimensions (timestamp and temperature), the generic encoder
2424
/// for geographic coordinate pairs is not used. Instead, <see cref="PolylineEncoding"/> static
2525
/// helpers are called directly to perform normalisation, delta computation, and character-level encoding.
2626
/// </para>
2727
/// <para>
2828
/// Each reading is encoded as a pair of delta-compressed values:
29-
/// the Unix timestamp in seconds (precision 0) followed by the temperature (at <see cref="PolylineEncodingOptions.Precision"/>).
29+
/// the Unix timestamp in seconds (precision 0) followed by the temperature (at <see cref="SensorEncodingOptions.Precision"/>).
3030
/// </para>
3131
/// </remarks>
3232
internal sealed class SensorDataEncoder : IPolylineEncoder<SensorReading, string> {
@@ -38,18 +38,18 @@ internal sealed class SensorDataEncoder : IPolylineEncoder<SensorReading, string
3838
/// Initializes a new instance of the <see cref="SensorDataEncoder"/> class with default encoding options.
3939
/// </summary>
4040
public SensorDataEncoder()
41-
: this(new PolylineEncodingOptions()) { }
41+
: this(new SensorEncodingOptions()) { }
4242

4343
/// <summary>
4444
/// Initializes a new instance of the <see cref="SensorDataEncoder"/> class with the specified encoding options.
4545
/// </summary>
4646
/// <param name="options">
47-
/// The <see cref="PolylineEncodingOptions"/> to use for encoding operations.
47+
/// The <see cref="SensorEncodingOptions"/> to use for encoding operations.
4848
/// </param>
4949
/// <exception cref="ArgumentNullException">
5050
/// Thrown when <paramref name="options"/> is <see langword="null"/>.
5151
/// </exception>
52-
public SensorDataEncoder(PolylineEncodingOptions options) {
52+
public SensorDataEncoder(SensorEncodingOptions options) {
5353
ArgumentNullException.ThrowIfNull(options);
5454

5555
Options = options;
@@ -58,7 +58,7 @@ public SensorDataEncoder(PolylineEncodingOptions options) {
5858
/// <summary>
5959
/// Gets the encoding options used by this encoder.
6060
/// </summary>
61-
public PolylineEncodingOptions Options { get; }
61+
public SensorEncodingOptions Options { get; }
6262

6363
/// <summary>
6464
/// Encodes a sequence of <see cref="SensorReading"/> values into a polyline string.

0 commit comments

Comments
 (0)