Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
{
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Engines;
using System;

[MemoryDiagnoser]
public class DecodePerformanceBenchmark
{
private Consumer _consumer = new Consumer();

public static IEnumerable<(int, char[])> Polylines()
{
yield return (1, "mz}lHssngJj`gqSnx~lEcovfTnms{Zdy~qQj_deI".ToCharArray());
Expand All @@ -21,15 +21,15 @@ public class DecodePerformanceBenchmark

[Benchmark]
[ArgumentsSource(nameof(Polylines))]
public void Decode_V2((int, char[]) arg) => V2.Decode(arg.Item2).Consume(_consumer);
public void Decode_V1_Parallel((int, char[]) arg) => Parallel.For(0, 100, (i) => V1.Decode(arg.Item2).Consume(_consumer));

[Benchmark]
[ArgumentsSource(nameof(Polylines))]
public void Decode_V1_Parallel((int, char[]) arg) => Parallel.For(100, 200, (i) => V1.Decode(arg.Item2).Consume(_consumer));
public void Decode_V2((int, char[]) arg) => V2.Decode(arg.Item2).Consume(_consumer);

[Benchmark]
[ArgumentsSource(nameof(Polylines))]
public void Decode_V2_Parallel((int, char[]) arg) => Parallel.For(100, 200, (i) => V2.Decode(arg.Item2).Consume(_consumer));
public void Decode_V2_Parallel((int, char[]) arg) => Parallel.For(0, 100, (i) => V2.Decode(arg.Item2).Consume(_consumer));

private class V1
{
Expand Down Expand Up @@ -125,18 +125,18 @@ private class V2
throw new ArgumentException(nameof(polyline));
}

int index = 0;
int offset = 0;
int latitude = 0;
int longitude = 0;

while (index < polyline.Length)
while (offset < polyline.Length)
{
if (!TryCalculateNext(ref polyline, ref index, ref latitude))
if (!TryCalculateNext(ref polyline, ref offset, ref latitude))
{
throw new InvalidOperationException();
}

if (!TryCalculateNext(ref polyline, ref index, ref longitude))
if (!TryCalculateNext(ref polyline, ref offset, ref longitude))
{
throw new InvalidOperationException();
}
Expand All @@ -152,20 +152,20 @@ private class V2
}
}

private static bool TryCalculateNext(ref char[] polyline, ref int index, ref int value)
private static bool TryCalculateNext(ref char[] polyline, ref int offset, ref int value)
{
int chunk;
int sum = 0;
int shifter = 0;

do
{
chunk = polyline[index++] - Constants.ASCII.QuestionMark;
chunk = polyline[offset++] - Constants.ASCII.QuestionMark;
sum |= (chunk & Constants.ASCII.UnitSeparator) << shifter;
shifter += Constants.ShiftLength;
} while (chunk >= Constants.ASCII.Space && index < polyline.Length);
} while (chunk >= Constants.ASCII.Space && offset < polyline.Length);

if (index >= polyline.Length && chunk >= Constants.ASCII.Space)
if (offset >= polyline.Length && chunk >= Constants.ASCII.Space)
return false;

value += (sum & 1) == 1 ? ~(sum >> 1) : sum >> 1;
Expand All @@ -175,7 +175,7 @@ private static bool TryCalculateNext(ref char[] polyline, ref int index, ref int

private static double GetDoubleRepresentation(int value)
{
return Convert.ToDouble(value) / Constants.Precision;
return value / Constants.Precision;
}

public static class CoordinateValidator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ public static string Encode(IEnumerable<(double Latitude, double Longitude)> coo

EnsureCoordinates(coordinates);

int lastLatitude = 0;
int lastLongitude = 0;
int previousLatitude = 0;
int previousLongitude = 0;

var sb = _pool.Get();

Expand All @@ -147,11 +147,11 @@ public static string Encode(IEnumerable<(double Latitude, double Longitude)> coo
int latitude = GetIntegerRepresentation(coordinate.Latitude);
int longitude = GetIntegerRepresentation(coordinate.Longitude);

sb.Append(GetEncodedCharacters(latitude - lastLatitude).ToArray());
sb.Append(GetEncodedCharacters(longitude - lastLongitude).ToArray());
sb.Append(GetEncodedCharacters(latitude - previousLatitude).ToArray());
sb.Append(GetEncodedCharacters(longitude - previousLongitude).ToArray());

lastLatitude = latitude;
lastLongitude = longitude;
previousLatitude = latitude;
previousLongitude = longitude;
}

var result = sb.ToString();
Expand Down
3 changes: 3 additions & 0 deletions src/DropoutCoder.PolylineAlgorithm.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
<DocumentationFile>
</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<Compile Update="ExceptionMessageResource.Designer.cs">
<DesignTime>True</DesignTime>
Expand Down
2 changes: 0 additions & 2 deletions src/Encoding/PolylineEncodingBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
//

using DropoutCoder.PolylineAlgorithm;

namespace DropoutCoder.PolylineAlgorithm.Encoding
{
using System;
Expand Down
28 changes: 16 additions & 12 deletions src/PolylineAlgorithm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
namespace DropoutCoder.PolylineAlgorithm
{
using DropoutCoder.PolylineAlgorithm.Validation;
using Microsoft.Extensions.ObjectPool;
using System;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -16,6 +17,8 @@ namespace DropoutCoder.PolylineAlgorithm
/// </summary>
public static class PolylineAlgorithm
{
private static readonly ObjectPool<StringBuilder> _pool = new DefaultObjectPoolProvider().CreateStringBuilderPool(5, 250);

#region Methods

/// <summary>
Expand All @@ -37,7 +40,6 @@ public static class PolylineAlgorithm
int index = 0;
int latitude = 0;
int longitude = 0;
var result = new List<(double Latitude, double Longitude)>();

// Looping through encoded polyline char array
while (index < polyline.Length)
Expand All @@ -61,10 +63,8 @@ public static class PolylineAlgorithm
throw new InvalidOperationException(ExceptionMessageResource.PolylineCharArrayIsMalformed);
}

result.Add(coordinate);
yield return coordinate;
}

return result;
}

/// <summary>
Expand All @@ -85,24 +85,28 @@ public static string Encode(IEnumerable<(double Latitude, double Longitude)> coo
EnsureCoordinates(coordinates);

// Initializing local variables
int lastLat = 0;
int lastLng = 0;
var sb = new StringBuilder();
int previousLatitude = 0;
int previousLongitude = 0;
var sb = _pool.Get();

// Looping over coordinates and building encoded result
foreach (var coordinate in coordinates)
{
int latitude = GetIntegerRepresentation(coordinate.Latitude);
int longitude = GetIntegerRepresentation(coordinate.Longitude);

sb.Append(GetEncodedCharacters(latitude - lastLat).ToArray());
sb.Append(GetEncodedCharacters(longitude - lastLng).ToArray());
sb.Append(GetEncodedCharacters(latitude - previousLatitude).ToArray());
sb.Append(GetEncodedCharacters(longitude - previousLongitude).ToArray());

lastLat = latitude;
lastLng = longitude;
previousLatitude = latitude;
previousLongitude = longitude;
}

return sb.ToString();
var result = sb.ToString();

_pool.Return(sb);

return result;
}

/// <summary>
Expand Down
118 changes: 61 additions & 57 deletions tests/Defaults.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,71 +3,75 @@
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
//

namespace DropoutCoder.PolylineAlgorithm.Tests {
using System;
using System.Collections.Generic;
using System.Linq;
namespace DropoutCoder.PolylineAlgorithm.Tests
{
using System;
using System.Collections.Generic;
using System.Linq;

/// <summary>
/// Defines default values and objects used for testing purposes
/// </summary>
public static class Defaults {
/// <summary>
/// Defines default decoded values and objects udśed for testing purposes
/// </summary>
public static class Coordinate {
#region Fields
/// <summary>
/// Defines default values and objects used for testing purposes
/// </summary>
public static class Defaults
{
/// <summary>
/// Defines default decoded values and objects udśed for testing purposes
/// </summary>
public static class Coordinate
{
#region Fields

/// <summary>
/// Defines empty range of coordinates. Equals to decoded <seealso cref="Polyline.Empty"/>
/// </summary>
public static readonly IEnumerable<(double Latitude, double Longitude)> Empty = Enumerable.Empty<(double Latitude, double Longitude)>();
/// <summary>
/// Defines empty range of coordinates. Equals to decoded <seealso cref="Polyline.Empty"/>
/// </summary>
public static readonly IEnumerable<(double Latitude, double Longitude)> Empty = Enumerable.Empty<(double Latitude, double Longitude)>();

/// <summary>
/// Defines range of invalid coordinates. Equals to decoded <seealso cref="Polyline.Invalid"/>
/// </summary>
public static readonly IEnumerable<(double Latitude, double Longitude)> Invalid = new[] {
(149.47383, 259.06250),
(-158.37407, 225.31250),
(152.99363, -220.93750),
(-144.49024, -274.37500)
};
/// <summary>
/// Defines range of invalid coordinates. Equals to decoded <seealso cref="Polyline.Invalid"/>
/// </summary>
public static readonly IEnumerable<(double Latitude, double Longitude)> Invalid = new[] {
(149.47383, 259.06250),
(-158.37407, 225.31250),
(152.99363, -220.93750),
(-144.49024, -274.37500)
};

/// <summary>
/// Defines range of valid coordinates. Equals to decoded <seealso cref="Polyline.Valid"/>
/// </summary>
public static readonly IEnumerable<(double Latitude, double Longitude)> Valid = new[] {
(49.47383, 59.06250),
(-58.37407, 25.31250),
(52.99363, -120.93750),
(-44.49024, -174.37500)
};
/// <summary>
/// Defines range of valid coordinates. Equals to decoded <seealso cref="Polyline.Valid"/>
/// </summary>
public static readonly IEnumerable<(double Latitude, double Longitude)> Valid = new[] {
(49.47383, 59.06250),
(-58.37407, 25.31250),
(52.99363, -120.93750),
(-44.49024, -174.37500)
};

#endregion
}
#endregion
}

/// <summary>
/// Defines default encoded values and objects udśed for testing purposes
/// </summary>
public static class Polyline {
#region Fields
/// <summary>
/// Defines default encoded values and objects udśed for testing purposes
/// </summary>
public static class Polyline
{
#region Fields

/// <summary>
/// Defines empty string of polyline encoded coordinates. Equals to encoded <seealso cref="Coordinate.Empty"/>
/// </summary>
public static readonly string Empty = String.Empty;
/// <summary>
/// Defines empty string of polyline encoded coordinates. Equals to encoded <seealso cref="Coordinate.Empty"/>
/// </summary>
public static readonly string Empty = String.Empty;

/// <summary>
/// Defines polyline encoded range of invalid coordinates. Equals to encoded <seealso cref="Coordinate.Invalid"/>
/// </summary>
public static readonly string Invalid = "mnc~Qsm_ja@";
/// <summary>
/// Defines polyline encoded range of invalid coordinates. Equals to encoded <seealso cref="Coordinate.Invalid"/>
/// </summary>
public static readonly string Invalid = "mnc~Qsm_ja@";

/// <summary>
/// Defines polyline encoded range of valid coordinates. Equals to encoded <seealso cref="Coordinate.Valid"/>
/// </summary>
public static readonly string Valid = "mz}lHssngJj`gqSnx~lEcovfTnms{Zdy~qQj_deI";
/// <summary>
/// Defines polyline encoded range of valid coordinates. Equals to encoded <seealso cref="Coordinate.Valid"/>
/// </summary>
public static readonly string Valid = "mz}lHssngJj`gqSnx~lEcovfTnms{Zdy~qQj_deI";

#endregion
}
}
#endregion
}
}
}
Loading