Skip to content

Commit b2044d4

Browse files
author
Petr Sramek
committed
lot of rewortk done
1 parent 97f383b commit b2044d4

30 files changed

+677
-662
lines changed

benchmarks/PolylineAlgorithm.Benchmarks/PolylineAlgorithm.Benchmarks.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
<ItemGroup>
1818
<PackageReference Include="BenchmarkDotNet" Version="0.*" />
19+
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="9.0.2" />
1920
</ItemGroup>
2021

2122
<ItemGroup>

benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace PolylineAlgorithm.Benchmarks;
99
using BenchmarkDotNet.Engines;
1010
using PolylineAlgorithm;
1111
using PolylineAlgorithm.Benchmarks.Internal;
12+
using System.Diagnostics;
1213

1314
/// <summary>
1415
/// Benchmarks for the <see cref="PolylineDecoder"/> class.
@@ -42,6 +43,11 @@ public class PolylineDecoderBenchmark {
4243
/// </summary>
4344
public PolylineDecoder Decoder = new();
4445

46+
/// <summary>
47+
/// The async polyline decoder instance.
48+
/// </summary>
49+
public AsyncPolylineDecoder AsyncDecoder = new();
50+
4551
/// <summary>
4652
/// Sets up the data for the benchmarks.
4753
/// </summary>
@@ -60,7 +66,7 @@ public void PolylineDecoder_Decode_FromString() {
6066
Polyline polyline = Polyline.FromString(StringValue);
6167

6268
Decoder
63-
.Decode(in polyline)
69+
.Decode(polyline)
6470
.Consume(_consumer);
6571
}
6672

@@ -72,7 +78,7 @@ public void PolylineDecoder_Decode_FromCharArray() {
7278
Polyline polyline = Polyline.FromCharArray(CharArray);
7379

7480
Decoder
75-
.Decode(in polyline)
81+
.Decode(polyline)
7682
.Consume(_consumer);
7783
}
7884

@@ -84,7 +90,49 @@ public void PolylineDecoder_Decode_FromMemory() {
8490
Polyline polyline = Polyline.FromMemory(Memory);
8591

8692
Decoder
87-
.Decode(in polyline)
93+
.Decode(polyline)
8894
.Consume(_consumer);
8995
}
96+
97+
/// <summary>
98+
/// Benchmarks the decoding of a polyline from read-only memory.
99+
/// </summary>
100+
[Benchmark]
101+
public async Task PolylineDecoder_DecodeAsync_FromString() {
102+
Polyline polyline = Polyline.FromString(StringValue);
103+
104+
var result = AsyncDecoder
105+
.DecodeAsync(polyline)
106+
.ConfigureAwait(false);
107+
108+
await foreach (var _ in result) { }
109+
}
110+
111+
/// <summary>
112+
/// Benchmarks the decoding of a polyline from read-only memory.
113+
/// </summary>
114+
[Benchmark]
115+
public async Task PolylineDecoder_DecodeAsync_CharArray() {
116+
Polyline polyline = Polyline.FromCharArray(CharArray);
117+
118+
var result = AsyncDecoder
119+
.DecodeAsync(polyline)
120+
.ConfigureAwait(false);
121+
122+
await foreach (var _ in result) { }
123+
}
124+
125+
/// <summary>
126+
/// Benchmarks the decoding of a polyline from read-only memory.
127+
/// </summary>
128+
[Benchmark]
129+
public async Task PolylineDecoder_DecodeAsync_FromMemory() {
130+
Polyline polyline = Polyline.FromMemory(Memory);
131+
132+
var result = AsyncDecoder
133+
.DecodeAsync(polyline)
134+
.ConfigureAwait(false);
135+
136+
await foreach (var _ in result) { }
137+
}
90138
}

benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,23 @@
66
namespace PolylineAlgorithm.Benchmarks;
77

88
using BenchmarkDotNet.Attributes;
9+
using Microsoft.Extensions.ObjectPool;
910
using PolylineAlgorithm;
11+
using PolylineAlgorithm.Abstraction;
1012
using PolylineAlgorithm.Benchmarks.Internal;
13+
using System;
1114
using System.Collections.Generic;
15+
using System.Text;
16+
using System.Threading.Tasks;
1217

1318
/// <summary>
1419
/// Benchmarks for the <see cref="PolylineEncoder"/> class.
1520
/// </summary>
1621
[RankColumn]
1722
public class PolylineEncoderBenchmark {
23+
private static string _dir = "C:\\temp_benchmark";
24+
private static StringBuilderPooledObjectPolicy _policy = new();
25+
1826
[Params(10, 100, 1_000, 10_000, 100_000)]
1927
public int N;
2028

@@ -28,20 +36,35 @@ public class PolylineEncoderBenchmark {
2836
/// Gets the list of coordinates to be encoded.
2937
/// </summary>
3038
public static List<Coordinate> List { get; private set; }
39+
40+
public static IAsyncEnumerable<Coordinate> AsyncEnumeration { get; private set; }
3141
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
3242

3343
/// <summary>
3444
/// The polyline encoder instance.
3545
/// </summary>
3646
public PolylineEncoder Encoder = new();
3747

48+
/// <summary>
49+
/// The async polyline encoder instance.
50+
/// </summary>
51+
public AsyncPolylineEncoder AsyncEncoder = new();
52+
3853
/// <summary>
3954
/// Sets up the data for the benchmarks.
4055
/// </summary>
4156
[GlobalSetup]
4257
public void SetupData() {
58+
Directory.CreateDirectory(_dir);
4359
Enumeration = ValueProvider.GetCoordinates(N);
44-
List = [..Enumeration];
60+
List = [.. Enumeration];
61+
AsyncEnumeration = GetAsyncEnumeration(Enumeration!);
62+
}
63+
64+
private async IAsyncEnumerable<Coordinate> GetAsyncEnumeration(IEnumerable<Coordinate> enumerable) {
65+
foreach (var item in enumerable) {
66+
yield return await new ValueTask<Coordinate>(item);
67+
}
4568
}
4669

4770
/// <summary>
@@ -50,7 +73,9 @@ public void SetupData() {
5073
/// <returns>The encoded polyline.</returns>
5174
[Benchmark]
5275
public Polyline PolylineEncoder_Encode_List() {
53-
return Encoder.Encode(List!);
76+
var polyline = Encoder.Encode(List!);
77+
78+
return polyline;
5479
}
5580

5681
/// <summary>
@@ -59,6 +84,20 @@ public Polyline PolylineEncoder_Encode_List() {
5984
/// <returns>The encoded polyline.</returns>
6085
[Benchmark]
6186
public Polyline PolylineEncoder_Encode_Enumerator() {
62-
return Encoder.Encode(Enumeration!);
87+
var polyline = Encoder.Encode(Enumeration!);
88+
89+
return polyline;
90+
}
91+
92+
/// <summary>
93+
/// Benchmarks the encoding of an enumeration of coordinates into a polyline.
94+
/// </summary>
95+
/// <returns>The encoded polyline.</returns>
96+
[Benchmark]
97+
public async Task PolylineEncoder_EncodeAsync_String() {
98+
var result = AsyncEncoder
99+
.EncodeAsync(AsyncEnumeration!);
100+
101+
await foreach (var _ in result) { }
63102
}
64103
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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+
6+
namespace PolylineAlgorithm.Abstraction;
7+
8+
using System.Collections.Generic;
9+
10+
/// <summary>
11+
/// Defines a method to decode an encoded polyline into a set of coordinates.
12+
/// </summary>
13+
public interface IAsyncPolylineDecoder {
14+
/// <summary>
15+
/// Converts an encoded polyline to a set of coordinates.
16+
/// </summary>
17+
/// <param name="polyline">An encoded polyline to decode.</param>
18+
/// <returns>A set of coordinates represented by the encoded polyline.</returns>
19+
IAsyncEnumerable<Coordinate> DecodeAsync(Polyline polyline);
20+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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+
6+
namespace PolylineAlgorithm.Abstraction;
7+
8+
using System.Collections.Generic;
9+
10+
/// <summary>
11+
/// Defines a method to encode a set of coordinates into an encoded polyline.
12+
/// </summary>
13+
public interface IAsyncPolylineEncoder {
14+
/// <summary>
15+
/// Converts a set of coordinates to an encoded polyline.
16+
/// </summary>
17+
/// <param name="coordinates">A set of coordinates to encode.</param>
18+
/// <returns>An encoded polyline representing the set of coordinates.</returns>
19+
IAsyncEnumerable<Polyline> EncodeAsync(IAsyncEnumerable<Coordinate> coordinates);
20+
}

src/PolylineAlgorithm/IPolylineDecoder.cs renamed to src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
44
//
55

6-
namespace PolylineAlgorithm;
6+
namespace PolylineAlgorithm.Abstraction;
77

88
using System.Collections.Generic;
99

@@ -16,5 +16,5 @@ public interface IPolylineDecoder {
1616
/// </summary>
1717
/// <param name="polyline">An encoded polyline to decode.</param>
1818
/// <returns>A set of coordinates represented by the encoded polyline.</returns>
19-
IEnumerable<Coordinate> Decode(ref readonly Polyline polyline);
19+
IEnumerable<Coordinate> Decode(Polyline polyline);
2020
}

src/PolylineAlgorithm/IPolylineEncoder.cs renamed to src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
44
//
55

6-
namespace PolylineAlgorithm;
6+
namespace PolylineAlgorithm.Abstraction;
77

88
using System.Collections.Generic;
99

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
6+
namespace PolylineAlgorithm;
7+
8+
using PolylineAlgorithm.Abstraction;
9+
using PolylineAlgorithm.Internal;
10+
using PolylineAlgorithm.Properties;
11+
using System.Buffers;
12+
13+
14+
/// <summary>
15+
/// Performs polyline algorithm decoding
16+
/// </summary>
17+
public class AsyncPolylineDecoder : IAsyncPolylineDecoder {
18+
/// <inheritdoc />
19+
/// <exception cref="ArgumentException">Thrown when <paramref name="polyline"/> argument is null -or- empty.</exception>
20+
/// <exception cref="InvalidOperationException">Thrown when <paramref name="polyline"/> is not in correct format.</exception>
21+
public async IAsyncEnumerable<Coordinate> DecodeAsync(Polyline polyline) {
22+
// Checking null and at least one character
23+
if (polyline.IsEmpty) {
24+
throw new ArgumentException(ExceptionMessageResource.ArgumentCannotBeNullEmptyOrWhitespaceMessage, nameof(polyline));
25+
}
26+
27+
int latitude = 0;
28+
int longitude = 0;
29+
long position = 0;
30+
ReadOnlySequence<char> sequence = polyline.AsSequence();
31+
32+
while (
33+
DecodingAlgorithm.DecodeNext(ref latitude, ref position, ref sequence)
34+
&& DecodingAlgorithm.DecodeNext(ref longitude, ref position, ref sequence)
35+
) {
36+
Coordinate coordinate = Coordinate.FromImprecise(latitude, longitude);
37+
38+
InvalidCoordinateException.ThrowIfNotValid(coordinate);
39+
40+
yield return await new ValueTask<Coordinate>(coordinate)
41+
.ConfigureAwait(false);
42+
}
43+
}
44+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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+
6+
namespace PolylineAlgorithm;
7+
8+
using PolylineAlgorithm.Abstraction;
9+
using PolylineAlgorithm.Internal;
10+
11+
12+
/// <summary>
13+
/// Performs polyline algorithm decoding
14+
/// </summary>
15+
public class AsyncPolylineEncoder : IAsyncPolylineEncoder {
16+
private uint _batchSize = 10000;
17+
18+
/// <inheritdoc />
19+
/// <exception cref="ArgumentException">Thrown when <paramref name="polyline"/> argument is null -or- empty.</exception>
20+
/// <exception cref="InvalidOperationException">Thrown when <paramref name="polyline"/> is not in correct format.</exception>
21+
public async IAsyncEnumerable<Polyline> EncodeAsync(IAsyncEnumerable<Coordinate> coordinates) {
22+
if (coordinates is null) {
23+
throw new ArgumentNullException(nameof(coordinates));
24+
}
25+
26+
ulong index = 0;
27+
CoordinateDifference diff = new();
28+
Polyline polyline = new();
29+
30+
await foreach (var coordinate in coordinates.ConfigureAwait(false)) {
31+
InvalidCoordinateException.ThrowIfNotValid(coordinate);
32+
33+
diff.DiffNext(coordinate);
34+
35+
var result = EncodingAlgorithm.EncodeNext(diff.Latitude, diff.Longitude);
36+
37+
polyline = polyline
38+
.Append(Polyline.FromMemory(result));
39+
40+
index++;
41+
42+
if (index == _batchSize) {
43+
var temp = polyline;
44+
45+
polyline = new();
46+
47+
yield return temp;
48+
}
49+
}
50+
}
51+
}

src/PolylineAlgorithm/Coordinate.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
namespace PolylineAlgorithm;
77

8+
using PolylineAlgorithm.Internal;
89
using PolylineAlgorithm.Validation;
910
using System;
1011
using System.Diagnostics;
@@ -18,6 +19,8 @@ namespace PolylineAlgorithm;
1819
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 16)]
1920
[DebuggerDisplay("{ToString()}")]
2021
public readonly struct Coordinate : IEquatable<Coordinate> {
22+
internal static readonly Coordinate Default = new();
23+
2124
/// <summary>
2225
/// Creates a new <see cref="Coordinate"/> structure with <see cref="Latitude"/> and <see cref="Longitude"/> set to their default values.
2326
/// </summary>
@@ -70,6 +73,15 @@ public void Deconstruct(out double latitude, out double longitude) {
7073
longitude = Longitude;
7174
}
7275

76+
internal void Imprecise(out int latitude, out int longitude) {
77+
latitude = Convert.ToInt32(Latitude * Defaults.Algorithm.Precision);
78+
longitude = Convert.ToInt32(Longitude * Defaults.Algorithm.Precision);
79+
}
80+
81+
internal static Coordinate FromImprecise(int latitude, int longitude) {
82+
return new(latitude / Defaults.Algorithm.Precision, longitude / Defaults.Algorithm.Precision);
83+
}
84+
7385
#region Overrides
7486

7587
/// <inheritdoc />

0 commit comments

Comments
 (0)