From a94f7c7f194754782d429a469a8b75ec3c169d5d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 5 Apr 2026 20:35:02 +0000 Subject: [PATCH 01/24] refactor: replace fixed lat/lon pair contract with N-value GetValues/CreateItem/ValuesPerItem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AbstractPolylineEncoder: remove GetLatitude/GetLongitude, add ValuesPerItem + GetValues(item, Span) - AbstractPolylineDecoder: remove CreateCoordinate(lat, lon), add ValuesPerItem + CreateItem(ReadOnlyMemory) - CoordinateDelta: generalize from lat/lon pair to N-value array with Next(ReadOnlySpan) and Deltas property - LogDebugExtensions: rename LogDecodedCoordinateDebug → LogDecodedValuesDebug(count, position) - Update all tests, samples, benchmarks, and utilities to new API - Declare new protected abstract members in PublicAPI.Unshipped.txt Agent-Logs-Url: https://github.com/petesramek/polyline-algorithm-csharp/sessions/b28a38c3-82b5-4aea-87ac-240d0503f978 Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com> --- .../PolylineDecoderBenchmark.cs | 18 ++- .../PolylineEncoderBenchmark.cs | 7 +- .../NetTopologyPolylineDecoder.cs | 17 ++- .../NetTopologyPolylineEncoder.cs | 35 +++--- .../Abstraction/AbstractPolylineDecoder.cs | 77 ++++++++---- .../Abstraction/AbstractPolylineEncoder.cs | 98 +++++++++------ .../Internal/CoordinateDelta.cs | 88 ++++++++------ .../Diagnostics/LogDebugExtensions.cs | 11 +- src/PolylineAlgorithm/PublicAPI.Unshipped.txt | 8 ++ .../AbstractPolylineDecoderTests.cs | 12 +- .../AbstractPolylineEncoderTests.cs | 7 +- .../PolylineDecoderExtensionsTests.cs | 12 +- .../PolylineEncoderExtensionsTests.cs | 7 +- .../Internal/CoordinateDeltaTests.cs | 112 ++++++++++++------ .../Diagnostics/LogDebugExtensionsTests.cs | 35 +++--- .../RandomValueProvider.cs | 11 +- 16 files changed, 349 insertions(+), 206 deletions(-) diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs index f28c8141..b6b54081 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs @@ -93,8 +93,10 @@ public void PolylineDecoder_Decode_Memory() { } private sealed class StringPolylineDecoder : AbstractPolylineDecoder { - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) { - return (latitude, longitude); + protected override int ValuesPerItem => 2; + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); } protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { @@ -103,8 +105,10 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { } private sealed class CharArrayPolylineDecoder : AbstractPolylineDecoder { - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) { - return (latitude, longitude); + protected override int ValuesPerItem => 2; + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); } protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) { @@ -113,8 +117,10 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) { } private sealed class MemoryCharPolylineDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) { - return (latitude, longitude); + protected override int ValuesPerItem => 2; + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); } protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) { diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs index e0b97c5c..c4b9d5a8 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs @@ -85,8 +85,11 @@ public void PolylineEncoder_Encode_List() { } private sealed class StringPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { + protected override int ValuesPerItem => 2; protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude; - protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude; + protected override void GetValues((double Latitude, double Longitude) item, Span destination) { + destination[0] = item.Latitude; + destination[1] = item.Longitude; + } } } diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs index d7dcb13e..dd05ca88 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs @@ -14,14 +14,21 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; /// internal sealed class NetTopologyPolylineDecoder : AbstractPolylineDecoder { /// - /// Creates a NetTopologySuite point from latitude and longitude. + /// Gets the number of encoded values per item: latitude (index 0) and longitude (index 1). /// - /// Latitude value. - /// Longitude value. + protected override int ValuesPerItem => 2; + + /// + /// Creates a NetTopologySuite point from the decoded values. + /// + /// + /// A memory region containing two values: index 0 is latitude, index 1 is longitude. + /// /// Point instance. - protected override Point CreateCoordinate(double latitude, double longitude) { + protected override Point CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; // NetTopologySuite Point: x = longitude, y = latitude - return new Point(longitude, latitude); + return new Point(span[1], span[0]); } /// diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs index c6719000..5a7b5529 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs @@ -7,11 +7,17 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; using global::NetTopologySuite.Geometries; using PolylineAlgorithm.Abstraction; +using System; /// /// Polyline encoder using NetTopologySuite's Point type. /// internal sealed class NetTopologyPolylineEncoder : AbstractPolylineEncoder { + /// + /// Gets the number of values per item: latitude (index 0) and longitude (index 1). + /// + protected override int ValuesPerItem => 2; + /// /// Creates encoded polyline string from memory. /// @@ -26,26 +32,15 @@ protected override string CreatePolyline(ReadOnlyMemory polyline) { } /// - /// Gets latitude from point. + /// Fills destination with latitude (index 0) and longitude (index 1) from the point. /// - /// Point instance. - /// Latitude value. - protected override double GetLatitude(Point current) { - ArgumentNullException.ThrowIfNull(current); - - // NetTopologySuite Point: Y = latitude - return current.Y; - } - - /// - /// Gets longitude from point. - /// - /// Point instance. - /// Longitude value. - protected override double GetLongitude(Point current) { - ArgumentNullException.ThrowIfNull(current); - - // NetTopologySuite Point: X = longitude - return current.X; + /// Point instance. + /// Span of length 2 to fill. + protected override void GetValues(Point item, Span destination) { + ArgumentNullException.ThrowIfNull(item); + + // NetTopologySuite Point: Y = latitude, X = longitude + destination[0] = item.Y; + destination[1] = item.X; } } \ No newline at end of file diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs index 1059abb9..ea087776 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs @@ -6,19 +6,27 @@ using Microsoft.Extensions.Logging; using PolylineAlgorithm.Internal; using PolylineAlgorithm.Internal.Diagnostics; +using System.Buffers; using System.Runtime.CompilerServices; namespace PolylineAlgorithm.Abstraction; /// -/// Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates. +/// Provides a base implementation for decoding encoded polyline strings into sequences of items. /// /// -/// Derive from this class to implement a decoder for a specific polyline type. Override -/// and to provide type-specific behavior. +/// Derive from this class to implement a decoder for a specific polyline type. Override +/// , , and to provide +/// type-specific behavior. +/// +/// The polyline format encodes each item as a fixed-length run of delta-compressed +/// values. All items in a single polyline must have the same number of values. For example, a 2D GPS decoder +/// sets to 2 (latitude, longitude), while a 3D GPS decoder sets it to 3 +/// (latitude, longitude, altitude). +/// /// /// The type that represents the encoded polyline input. -/// The type that represents a decoded geographic coordinate. +/// The type that represents a decoded item. public abstract class AbstractPolylineDecoder : IPolylineDecoder { private readonly ILogger> _logger; @@ -53,6 +61,16 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) { /// public PolylineEncodingOptions Options { get; } + /// + /// Gets the number of encoded values that make up a single decoded item. + /// + /// + /// Override this property to specify the arity of each item. For example, return 2 for + /// latitude/longitude pairs, 3 for latitude/longitude/altitude triples, or any other count + /// that matches the encoding scheme used to produce the polyline. + /// + protected abstract int ValuesPerItem { get; } + /// /// Decodes an encoded into a sequence of instances, /// with support for cancellation. @@ -64,7 +82,7 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) { /// A that can be used to cancel the decoding operation. /// /// - /// An of representing the decoded latitude and longitude pairs. + /// An of representing the decoded items. /// /// /// Thrown when is . @@ -90,30 +108,45 @@ public IEnumerable Decode(TPolyline polyline, CancellationToken can ValidateSequence(sequence, _logger); ValidateFormat(sequence, _logger); + int valuesPerItem = ValuesPerItem; int position = 0; - int encodedLatitude = 0; - int encodedLongitude = 0; + + int[]? runningRent = ArrayPool.Shared.Rent(valuesPerItem); + // Zero-initialize so delta decoding starts from 0 for all dimensions. + for (int j = 0; j < valuesPerItem; j++) { + runningRent[j] = 0; + } try { while (position < sequence.Length) { cancellationToken.ThrowIfCancellationRequested(); - if (!PolylineEncoding.TryReadValue(ref encodedLatitude, sequence, ref position) - || !PolylineEncoding.TryReadValue(ref encodedLongitude, sequence, ref position)) { + bool allRead = true; + for (int j = 0; j < valuesPerItem; j++) { + if (!PolylineEncoding.TryReadValue(ref runningRent[j], sequence, ref position)) { + allRead = false; + break; + } + } + + if (!allRead) { _logger?.LogOperationFailedDebug(OperationName); _logger?.LogInvalidPolylineWarning(position); ExceptionGuard.ThrowInvalidPolylineFormat(position); } - double decodedLatitude = PolylineEncoding.Denormalize(encodedLatitude, Options.Precision); - double decodedLongitude = PolylineEncoding.Denormalize(encodedLongitude, Options.Precision); + double[] decoded = new double[valuesPerItem]; + for (int j = 0; j < valuesPerItem; j++) { + decoded[j] = PolylineEncoding.Denormalize(runningRent[j], Options.Precision); + } - _logger?.LogDecodedCoordinateDebug(decodedLatitude, decodedLongitude, position); + _logger?.LogDecodedValuesDebug(valuesPerItem, position); - yield return CreateCoordinate(decodedLatitude, decodedLongitude); + yield return CreateItem(decoded.AsMemory()); } } finally { + ArrayPool.Shared.Return(runningRent!); _logger?.LogOperationFinishedDebug(OperationName); } } @@ -188,17 +221,19 @@ protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? lo protected abstract ReadOnlyMemory GetReadOnlyMemory(in TPolyline polyline); /// - /// Creates a instance from the specified latitude and longitude values. + /// Creates a instance from the specified decoded values. /// - /// - /// The latitude component of the coordinate, in degrees. - /// - /// - /// The longitude component of the coordinate, in degrees. + /// + /// A of containing exactly + /// decoded values for this item, in the same order they were encoded. /// /// - /// A instance representing the specified geographic coordinate. + /// A instance representing the decoded item. /// + /// + /// Implementations should read all required values from and construct the + /// immediately. The memory is valid only for the duration of this call. + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract TCoordinate CreateCoordinate(double latitude, double longitude); + protected abstract TCoordinate CreateItem(ReadOnlyMemory values); } diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs index 1bcdb0ee..dff4eac3 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs @@ -16,13 +16,19 @@ namespace PolylineAlgorithm.Abstraction; using System.Threading; /// -/// Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings. +/// Provides a base implementation for encoding sequences of items into encoded polyline strings. /// /// -/// Derive from this class to implement an encoder for a specific coordinate and polyline type. Override -/// , , and to provide type-specific behavior. +/// Derive from this class to implement an encoder for a specific item and polyline type. Override +/// , , and to provide type-specific behavior. +/// +/// The polyline format encodes each item as a fixed-length run of delta-compressed +/// values. All items in a single polyline must have the same number of values. For example, a 2D GPS encoder +/// sets to 2 (latitude, longitude), while a 3D GPS encoder sets it to 3 +/// (latitude, longitude, altitude). +/// /// -/// The type that represents a geographic coordinate to encode. +/// The type that represents an item to encode. /// The type that represents the encoded polyline output. public abstract class AbstractPolylineEncoder : IPolylineEncoder { private readonly ILogger> _logger; @@ -56,6 +62,16 @@ protected AbstractPolylineEncoder(PolylineEncodingOptions options) { /// public PolylineEncodingOptions Options { get; } + /// + /// Gets the number of values that make up a single encoded item. + /// + /// + /// Override this property to specify the arity of each item. For example, return 2 for + /// latitude/longitude pairs, 3 for latitude/longitude/altitude triples, or any other count + /// that matches your encoding scheme. + /// + protected abstract int ValuesPerItem { get; } + /// /// Encodes a collection of instances into an encoded string. /// @@ -88,11 +104,12 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken ValidateEmptyCoordinates(ref coordinates, _logger); - CoordinateDelta delta = new(); + int valuesPerItem = ValuesPerItem; + CoordinateDelta delta = new(valuesPerItem); int position = 0; int consumed = 0; - int length = GetMaxBufferLength(coordinates.Length); + int length = GetMaxBufferLength(coordinates.Length, valuesPerItem); char[]? temp = length <= Options.StackAllocLimit ? null @@ -100,29 +117,37 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken Span buffer = temp is null ? stackalloc char[length] : temp.AsSpan(0, length); + int[]? normalizedRent = ArrayPool.Shared.Rent(valuesPerItem); + Span normalized = normalizedRent.AsSpan(0, valuesPerItem); + + double[]? valuesRent = ArrayPool.Shared.Rent(valuesPerItem); + Span values = valuesRent.AsSpan(0, valuesPerItem); + string encodedResult; try { for (var i = 0; i < coordinates.Length; i++) { cancellationToken.ThrowIfCancellationRequested(); - delta - .Next( - PolylineEncoding.Normalize(GetLatitude(coordinates[i]), Options.Precision), - PolylineEncoding.Normalize(GetLongitude(coordinates[i]), Options.Precision) - ); + GetValues(coordinates[i], values); + + for (int j = 0; j < valuesPerItem; j++) { + normalized[j] = PolylineEncoding.Normalize(values[j], Options.Precision); + } - if (!PolylineEncoding.TryWriteValue(delta.Latitude, buffer, ref position) - || !PolylineEncoding.TryWriteValue(delta.Longitude, buffer, ref position) - ) { - // This shouldn't happen, but if it does, log the error and throw an exception. - _logger - .LogOperationFailedDebug(OperationName); - _logger - .LogCannotWriteValueToBufferWarning(position, consumed); + delta.Next(normalized); - ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer(); + ReadOnlySpan deltas = delta.Deltas; + for (int j = 0; j < deltas.Length; j++) { + if (!PolylineEncoding.TryWriteValue(deltas[j], buffer, ref position)) { + // This shouldn't happen, but if it does, log the error and throw an exception. + _logger + .LogOperationFailedDebug(OperationName); + _logger + .LogCannotWriteValueToBufferWarning(position, consumed); + ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer(); + } } consumed++; @@ -130,6 +155,8 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken encodedResult = buffer[..position].ToString(); } finally { + ArrayPool.Shared.Return(valuesRent!); + ArrayPool.Shared.Return(normalizedRent!); if (temp is not null) { ArrayPool.Shared.Return(temp); } @@ -141,10 +168,10 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken return CreatePolyline(encodedResult.AsMemory()); [MethodImpl(MethodImplOptions.AggressiveInlining)] - static int GetMaxBufferLength(int count) { + static int GetMaxBufferLength(int count, int perItem) { Debug.Assert(count > 0, "Count must be greater than zero."); - int requestedBufferLength = count * 2 * Defaults.Polyline.Block.Length.Max; + int requestedBufferLength = count * perItem * Defaults.Polyline.Block.Length.Max; Debug.Assert(requestedBufferLength > 0, "Requested buffer length must be greater than zero."); @@ -175,23 +202,18 @@ static void ValidateEmptyCoordinates(ref ReadOnlySpan coordinates, protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline); /// - /// Extracts the longitude value from the specified coordinate. - /// - /// The coordinate from which to extract the longitude. - /// - /// The longitude value as a . - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract double GetLongitude(TCoordinate current); - - /// - /// Extracts the latitude value from the specified coordinate. + /// Fills with the values to encode for the specified item. /// - /// The coordinate from which to extract the latitude. - /// - /// The latitude value as a . - /// + /// The item from which to extract values. + /// + /// A of length to fill with the item's values, + /// in the order they should be encoded. + /// + /// + /// Implementations should write exactly values into . + /// For example, a 2D GPS encoder writes destination[0] = latitude; destination[1] = longitude;. + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract double GetLatitude(TCoordinate current); + protected abstract void GetValues(TCoordinate item, Span destination); } diff --git a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs index ae217c57..70826216 100644 --- a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs +++ b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs @@ -5,68 +5,82 @@ namespace PolylineAlgorithm.Internal; +using System; using System.Diagnostics; using System.Runtime.InteropServices; +using System.Text; /// -/// Represents the difference (delta) in latitude and longitude between consecutive geographic coordinates. +/// Represents the running delta state for an arbitrary number of encoded values between consecutive items. /// /// -/// This struct computes and stores the change in coordinate values as integer deltas between successive coordinates. +/// This struct computes and stores the change in each value dimension as integer deltas between successive items. +/// The number of dimensions is specified at construction time, enabling support for any number of encoded fields +/// (e.g. latitude/longitude, latitude/longitude/altitude, or arbitrary sensor fields). /// [DebuggerDisplay("{ToString(),nq}")] [StructLayout(LayoutKind.Auto)] internal struct CoordinateDelta { - private (int Latitude, int Longitude) _current; + private readonly int[] _current; + private readonly int[] _deltas; /// - /// Initializes a new instance of the struct with the default latitude and longitude deltas. + /// Initializes a new instance of the struct for the specified number of value dimensions. /// - public CoordinateDelta() { - _current = (default, default); - } + /// The number of value dimensions to track. Must be greater than zero. + public CoordinateDelta(int count) { + Debug.Assert(count > 0, "Count must be greater than zero."); - /// - /// Gets the current delta in latitude between the most recent and previous coordinate. - /// - public int Latitude { get; private set; } + _current = new int[count]; + _deltas = new int[count]; + } /// - /// Gets the current delta in longitude between the most recent and previous coordinate. + /// Gets the current deltas computed by the most recent call to . /// - public int Longitude { get; private set; } + public ReadOnlySpan Deltas => _deltas; /// - /// Updates the delta values based on the next latitude and longitude, and sets the current coordinate as next delta baseline. + /// Updates the delta values based on the next set of values, and sets them as the baseline for the next call. /// - /// The next latitude value. - /// The next longitude value. - public void Next(int latitude, int longitude) { - Latitude = Delta(_current.Latitude, latitude); - Longitude = Delta(_current.Longitude, longitude); + /// + /// The next normalized integer values. Must have the same length as the count passed to the constructor. + /// + public void Next(ReadOnlySpan values) { + Debug.Assert(values.Length == _current.Length, "Values length must match the delta dimension count."); - _current.Latitude = latitude; - _current.Longitude = longitude; + for (int i = 0; i < values.Length; i++) { + _deltas[i] = values[i] - _current[i]; + _current[i] = values[i]; + } } /// - /// Calculates the delta between two coordinate values. - /// - /// - /// This method computes the difference between two integer coordinate values, handling cases where the values may be positive or negative. - /// - /// The previous coordinate value. - /// The next coordinate value. - /// The computed delta between and . - private static int Delta(int initial, int next) => next - initial; - - /// - /// Returns a string representation of the current coordinate delta. + /// Returns a string representation of the current values and deltas. /// /// - /// A string in the format { Coordinate: { Latitude: [int], Longitude: [int] }, Delta: { Latitude: [int], Longitude: [int] } } representing the current coordinate and deltas to previous coordinate. + /// A string in the format { Values: [v0, v1, ...], Deltas: [d0, d1, ...] }. /// - public override readonly string ToString() => - $"{{ Coordinate: {{ Latitude: {_current.Latitude}, Longitude: {_current.Longitude} }}, " + - $"Delta: {{ Latitude: {Latitude}, Longitude: {Longitude} }} }}"; + public override readonly string ToString() { + var sb = new StringBuilder("{ Values: ["); + for (int i = 0; i < _current.Length; i++) { + if (i > 0) { + sb.Append(", "); + } + + sb.Append(_current[i]); + } + + sb.Append("], Deltas: ["); + for (int i = 0; i < _deltas.Length; i++) { + if (i > 0) { + sb.Append(", "); + } + + sb.Append(_deltas[i]); + } + + sb.Append("] }"); + return sb.ToString(); + } } \ No newline at end of file diff --git a/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs b/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs index cc58c702..9a422a73 100644 --- a/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs +++ b/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs @@ -46,12 +46,11 @@ internal static partial class LogDebugExtensions { internal static partial void LogOperationFinishedDebug(this ILogger logger, string operationName); /// - /// Logs a debug message containing the decoded coordinate values and position. + /// Logs a debug message containing the number of decoded values and position. /// /// The used to write the log entry. - /// The decoded latitude value. - /// The decoded longitude value. - /// The position in the polyline buffer at which the coordinate was decoded. - [LoggerMessage(EVENT_ID_BASE + 4, LOG_LEVEL, "Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}.")] - internal static partial void LogDecodedCoordinateDebug(this ILogger logger, double latitude, double longitude, int position); + /// The number of values that were decoded for this item. + /// The position in the polyline buffer at which the item was decoded. + [LoggerMessage(EVENT_ID_BASE + 4, LOG_LEVEL, "Decoded {count} values at position {position}.")] + internal static partial void LogDecodedValuesDebug(this ILogger logger, int count, int position); } diff --git a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt index 7dc5c581..4033ef24 100644 --- a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt +++ b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt @@ -1 +1,9 @@ #nullable enable +abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.CreateItem(System.ReadOnlyMemory values) -> TCoordinate +abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.GetReadOnlyMemory(in TPolyline polyline) -> System.ReadOnlyMemory +abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValuesPerItem.get -> int +abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.GetValues(TCoordinate item, System.Span destination) -> void +abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.ValuesPerItem.get -> int +virtual PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValidateFormat(System.ReadOnlyMemory sequence, Microsoft.Extensions.Logging.ILogger? logger) -> void +PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException() -> void +PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException(string! message, System.Exception! innerException) -> void diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs index c6734c6c..b5a64627 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs @@ -16,16 +16,24 @@ namespace PolylineAlgorithm.Tests.Abstraction; [TestClass] public sealed class AbstractPolylineDecoderTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { + protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); + } } private sealed class TestStringDecoderWithOptions : AbstractPolylineDecoder { public TestStringDecoderWithOptions(PolylineEncodingOptions options) : base(options) { } + protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); + } } /// diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs index f537dda2..1500b0de 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs @@ -21,9 +21,12 @@ public TestStringEncoder() public TestStringEncoder(PolylineEncodingOptions options) : base(options) { } + protected override int ValuesPerItem => 2; protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude; - protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude; + protected override void GetValues((double Latitude, double Longitude) item, Span destination) { + destination[0] = item.Latitude; + destination[1] = item.Longitude; + } } /// diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs index c44c914d..069c639f 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs @@ -17,13 +17,21 @@ namespace PolylineAlgorithm.Tests.Extensions; [TestClass] public sealed class PolylineDecoderExtensionsTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { + protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); + } } private sealed class TestMemoryDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { + protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) => polyline; - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); + } } // ----- Decode(char[]) for IPolylineDecoder ----- diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs index da8a622e..874f168c 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs @@ -17,9 +17,12 @@ namespace PolylineAlgorithm.Tests.Extensions; [TestClass] public sealed class PolylineEncoderExtensionsTests { private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { + protected override int ValuesPerItem => 2; protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude; - protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude; + protected override void GetValues((double Latitude, double Longitude) item, Span destination) { + destination[0] = item.Latitude; + destination[1] = item.Longitude; + } } // ----- Encode(List) ----- diff --git a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs index 1e915fe2..03ef5e66 100644 --- a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs +++ b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs @@ -6,7 +6,6 @@ namespace PolylineAlgorithm.Tests.Internal; using PolylineAlgorithm.Internal; -using System.Globalization; /// /// Tests for . @@ -14,20 +13,22 @@ namespace PolylineAlgorithm.Tests.Internal; [TestClass] public sealed class CoordinateDeltaTests { /// - /// Tests that the default constructor initializes delta values to zero. + /// Tests that a newly constructed instance reports all-zero deltas. /// [TestMethod] - public void Constructor_Default_Initializes_Latitude_And_Longitude_To_Zero() { + public void Constructor_Default_Initializes_Deltas_To_Zero() { // Act - CoordinateDelta delta = new(); + CoordinateDelta delta = new(2); // Assert - Assert.AreEqual(0, delta.Latitude); - Assert.AreEqual(0, delta.Longitude); + ReadOnlySpan deltas = delta.Deltas; + Assert.AreEqual(2, deltas.Length); + Assert.AreEqual(0, deltas[0]); + Assert.AreEqual(0, deltas[1]); } /// - /// Tests that a single call to Next computes the correct delta from the initial zero state. + /// Tests that a single call to Next computes the correct delta from the initial zero state for 2 values. /// [TestMethod] [DataRow(10, 20, 10, 20)] @@ -35,59 +36,94 @@ public void Constructor_Default_Initializes_Latitude_And_Longitude_To_Zero() { [DataRow(0, 0, 0, 0)] [DataRow(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue)] [DataRow(int.MinValue, int.MinValue, int.MinValue, int.MinValue)] - public void Next_Single_Call_From_Zero_Computes_Expected_Delta(int latitude, int longitude, int expectedLatitude, int expectedLongitude) { + public void Next_Single_Call_From_Zero_Computes_Expected_Delta_For_Two_Values(int v0, int v1, int expectedD0, int expectedD1) { // Arrange - CoordinateDelta delta = new(); + CoordinateDelta delta = new(2); // Act - delta.Next(latitude, longitude); + delta.Next([v0, v1]); // Assert - Assert.AreEqual(expectedLatitude, delta.Latitude); - Assert.AreEqual(expectedLongitude, delta.Longitude); + ReadOnlySpan deltas = delta.Deltas; + Assert.AreEqual(expectedD0, deltas[0]); + Assert.AreEqual(expectedD1, deltas[1]); } /// - /// Tests that two consecutive calls to Next compute the delta relative to the previous value. + /// Tests that two consecutive calls to Next compute the delta relative to the previous value for 2 values. /// [TestMethod] [DataRow(10, 20, 15, 30, 5, 10)] [DataRow(100, 200, 50, 150, -50, -50)] [DataRow(42, 84, 42, 84, 0, 0)] [DataRow(-50, 100, 25, -75, 75, -175)] - public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value( - int firstLatitude, int firstLongitude, - int secondLatitude, int secondLongitude, - int expectedLatitude, int expectedLongitude) { + public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value_For_Two_Values( + int first0, int first1, + int second0, int second1, + int expectedD0, int expectedD1) { // Arrange - CoordinateDelta delta = new(); - delta.Next(firstLatitude, firstLongitude); + CoordinateDelta delta = new(2); + delta.Next([first0, first1]); // Act - delta.Next(secondLatitude, secondLongitude); + delta.Next([second0, second1]); // Assert - Assert.AreEqual(expectedLatitude, delta.Latitude); - Assert.AreEqual(expectedLongitude, delta.Longitude); + ReadOnlySpan deltas = delta.Deltas; + Assert.AreEqual(expectedD0, deltas[0]); + Assert.AreEqual(expectedD1, deltas[1]); } /// - /// Tests that ToString on a default instance returns a string containing expected structural keywords and a zero value. + /// Tests that Next works correctly for a single value dimension. + /// + [TestMethod] + public void Next_Single_Dimension_Computes_Correct_Delta() { + // Arrange + CoordinateDelta delta = new(1); + delta.Next([100]); + + // Act + delta.Next([150]); + + // Assert + Assert.AreEqual(50, delta.Deltas[0]); + } + + /// + /// Tests that Next works correctly for three value dimensions. + /// + [TestMethod] + public void Next_Three_Dimensions_Computes_Correct_Deltas() { + // Arrange + CoordinateDelta delta = new(3); + delta.Next([10, 20, 30]); + + // Act + delta.Next([15, 25, 25]); + + // Assert + ReadOnlySpan deltas = delta.Deltas; + Assert.AreEqual(5, deltas[0]); + Assert.AreEqual(5, deltas[1]); + Assert.AreEqual(-5, deltas[2]); + } + + /// + /// Tests that ToString on a default instance returns a non-null string containing structural keywords. /// [TestMethod] public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zeros() { // Arrange - CoordinateDelta delta = new(); + CoordinateDelta delta = new(2); // Act string result = delta.ToString(); // Assert Assert.IsNotNull(result); - Assert.IsTrue(result.Contains("Coordinate", StringComparison.Ordinal)); - Assert.IsTrue(result.Contains("Delta", StringComparison.Ordinal)); - Assert.IsTrue(result.Contains("Latitude", StringComparison.Ordinal)); - Assert.IsTrue(result.Contains("Longitude", StringComparison.Ordinal)); + Assert.IsTrue(result.Contains("Values", StringComparison.Ordinal)); + Assert.IsTrue(result.Contains("Deltas", StringComparison.Ordinal)); Assert.Contains('0', result); } @@ -97,20 +133,18 @@ public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zero [TestMethod] [DataRow(42, 84)] [DataRow(-100, -200)] - [DataRow(int.MaxValue, int.MaxValue)] - [DataRow(int.MinValue, int.MinValue)] - public void ToString_After_Next_Contains_Expected_Values(int latitude, int longitude) { + public void ToString_After_Next_Contains_Expected_Values(int v0, int v1) { // Arrange - CoordinateDelta delta = new(); - delta.Next(latitude, longitude); + CoordinateDelta delta = new(2); + delta.Next([v0, v1]); // Act string result = delta.ToString(); // Assert Assert.IsNotNull(result); - Assert.IsTrue(result.Contains(latitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal)); - Assert.IsTrue(result.Contains(longitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal)); + Assert.IsTrue(result.Contains(v0.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.Ordinal)); + Assert.IsTrue(result.Contains(v1.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.Ordinal)); } /// @@ -119,9 +153,9 @@ public void ToString_After_Next_Contains_Expected_Values(int latitude, int longi [TestMethod] public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Latest_Values() { // Arrange - CoordinateDelta delta = new(); - delta.Next(10, 20); - delta.Next(30, 50); + CoordinateDelta delta = new(2); + delta.Next([10, 20]); + delta.Next([30, 50]); // Act string result = delta.ToString(); @@ -132,5 +166,5 @@ public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Lat Assert.IsTrue(result.Contains("50", StringComparison.Ordinal)); Assert.IsTrue(result.Contains("20", StringComparison.Ordinal)); } - } + diff --git a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs index 0dff7193..c9daaa1f 100644 --- a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs @@ -80,20 +80,21 @@ public void LogOperationFinishedDebug_With_Operation_Name_Logs_Finished_Message( } /// - /// Tests that LogDecodedCoordinateDebug WithCoordinatesAndPosition LogsDecodedCoordinateMessage. + /// Tests that LogDecodedValuesDebug WithCountAndPosition LogsDecodedValuesMessage. /// [TestMethod] - public void LogDecodedCoordinateDebug_With_Coordinates_And_Position_Logs_Decoded_Coordinate_Message() { + public void LogDecodedValuesDebug_With_Count_And_Position_Logs_Decoded_Values_Message() { var logger = new TestLogger(); - const double latitude = 38.5; - const double longitude = -120.2; + const int count = 2; const int position = 42; - logger.LogDecodedCoordinateDebug(latitude, longitude, position); + logger.LogDecodedValuesDebug(count, position); Assert.HasCount(1, logger.Logs); Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level); - Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}."), logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains("Decoded", logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains(count.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains(position.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal); } /// @@ -142,37 +143,35 @@ public void LogOperationFinishedDebug_With_Null_Operation_Name_Logs_Message() { } /// - /// Tests that LogDecodedCoordinateDebug WithZeroCoordinates LogsMessage. + /// Tests that LogDecodedValuesDebug WithZeroCountAndPosition LogsMessage. /// [TestMethod] - public void LogDecodedCoordinateDebug_With_Zero_Coordinates_Logs_Message() { + public void LogDecodedValuesDebug_With_Zero_Count_Logs_Message() { var logger = new TestLogger(); - const double latitude = 0.0; - const double longitude = 0.0; + const int count = 0; const int position = 0; - logger.LogDecodedCoordinateDebug(latitude, longitude, position); + logger.LogDecodedValuesDebug(count, position); Assert.HasCount(1, logger.Logs); Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level); - Assert.Contains("Decoded coordinate", logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains("Decoded", logger.Logs[0].Message, StringComparison.Ordinal); } /// - /// Tests that LogDecodedCoordinateDebug WithNegativeCoordinates LogsMessage. + /// Tests that LogDecodedValuesDebug WithLargeCount LogsMessage. /// [TestMethod] - public void LogDecodedCoordinateDebug_With_Negative_Coordinates_Logs_Message() { + public void LogDecodedValuesDebug_With_Large_Count_Logs_Message() { var logger = new TestLogger(); - const double latitude = -90.0; - const double longitude = -180.0; + const int count = 5; const int position = 100; - logger.LogDecodedCoordinateDebug(latitude, longitude, position); + logger.LogDecodedValuesDebug(count, position); Assert.HasCount(1, logger.Logs); Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level); - Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Latitude: {latitude}, Longitude: {longitude}"), logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains(count.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal); } /// diff --git a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs index d3d83b9e..0ca40426 100644 --- a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs +++ b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs @@ -105,16 +105,15 @@ private readonly struct PolylineCoordinateCollectionPair(IEnumerable<(double Lat private sealed class PolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { + protected override int ValuesPerItem => 2; + protected override string CreatePolyline(ReadOnlyMemory polyline) { return polyline.ToString(); } - protected override double GetLatitude((double Latitude, double Longitude) current) { - return current.Latitude; - } - - protected override double GetLongitude((double Latitude, double Longitude) current) { - return current.Longitude; + protected override void GetValues((double Latitude, double Longitude) item, Span destination) { + destination[0] = item.Latitude; + destination[1] = item.Longitude; } } } \ No newline at end of file From 89a6a24401b883dcfdec0d69a8237b3e41a42c02 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 5 Apr 2026 22:01:10 +0000 Subject: [PATCH 02/24] reset: revert all previous changes, clean slate identical to main Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com> --- .editorconfig | 3 - .github/CODEOWNERS | 5 - .github/ISSUE_TEMPLATE/bug_report.md | 32 +- .github/ISSUE_TEMPLATE/config.yml | 5 - .github/ISSUE_TEMPLATE/feature_request.md | 4 +- .github/PULL_REQUEST_TEMPLATE.md | 19 - .github/actions/source/compile/action.yml | 2 +- .github/dependabot.yml | 12 - .github/release.yml | 23 - .github/workflows/build.yml | 2 +- .github/workflows/publish-documentation.yml | 21 +- .github/workflows/pull-request.yml | 47 +- .github/workflows/release.yml | 202 +------ CHANGELOG.md | 10 - CODE_OF_CONDUCT.md | 47 -- Directory.Build.props | 3 - PolylineAlgorithm.slnx | 1 - README.md | 81 +-- SECURITY.md | 23 - ....Abstraction.AbstractPolylineDecoder-2.yml | 233 -------- ....Abstraction.AbstractPolylineEncoder-2.yml | 219 -------- ...gorithm.Abstraction.IPolylineDecoder-2.yml | 90 --- ...gorithm.Abstraction.IPolylineEncoder-2.yml | 142 ----- .../0.0/PolylineAlgorithm.Abstraction.yml | 34 -- ...m.Extensions.PolylineDecoderExtensions.yml | 195 ------- ...m.Extensions.PolylineEncoderExtensions.yml | 139 ----- .../0.0/PolylineAlgorithm.Extensions.yml | 19 - ...lineAlgorithm.InvalidPolylineException.yml | 102 ---- .../PolylineAlgorithm.PolylineEncoding.yml | 529 ------------------ ...ylineAlgorithm.PolylineEncodingOptions.yml | 127 ----- ...gorithm.PolylineEncodingOptionsBuilder.yml | 141 ----- api-reference/0.0/PolylineAlgorithm.yml | 38 -- api-reference/0.0/toc.yml | 34 -- api-reference/guide/benchmarks.md | 11 - api-reference/guide/toc.yml | 2 - .../PolylineDecoderBenchmark.cs | 18 +- .../PolylineEncoderBenchmark.cs | 7 +- docs/local-development.md | 21 - docs/workflows.md | 1 - .../NetTopologyPolylineDecoder.cs | 19 +- .../NetTopologyPolylineEncoder.cs | 41 +- ...neAlgorithm.NetTopologySuite.Sample.csproj | 3 +- .../Program.cs | 46 -- ...PolylineAlgorithm.SensorData.Sample.csproj | 16 - .../Program.cs | 49 -- .../Properties/CodeCoverage.cs | 8 - .../SensorDataDecoder.cs | 107 ---- .../SensorDataEncoder.cs | 135 ----- .../SensorReading.cs | 16 - .../Abstraction/AbstractPolylineDecoder.cs | 77 +-- .../Abstraction/AbstractPolylineEncoder.cs | 98 ++-- .../Internal/CoordinateDelta.cs | 88 ++- .../Diagnostics/LogDebugExtensions.cs | 11 +- .../PolylineAlgorithm.csproj | 7 - src/PolylineAlgorithm/PolylineEncoding.cs | 7 +- src/PolylineAlgorithm/PublicAPI.Shipped.txt | 2 +- src/PolylineAlgorithm/PublicAPI.Unshipped.txt | 8 - src/PolylineAlgorithm/README.md | 30 +- .../AbstractPolylineDecoderTests.cs | 12 +- .../AbstractPolylineEncoderTests.cs | 7 +- .../PolylineDecoderExtensionsTests.cs | 12 +- .../PolylineEncoderExtensionsTests.cs | 7 +- .../Internal/CoordinateDeltaTests.cs | 112 ++-- .../Diagnostics/LogDebugExtensionsTests.cs | 35 +- .../RandomValueProvider.cs | 11 +- 65 files changed, 334 insertions(+), 3274 deletions(-) delete mode 100644 .github/CODEOWNERS delete mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/PULL_REQUEST_TEMPLATE.md delete mode 100644 .github/release.yml delete mode 100644 CHANGELOG.md delete mode 100644 CODE_OF_CONDUCT.md delete mode 100644 SECURITY.md delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.yml delete mode 100644 api-reference/0.0/toc.yml delete mode 100644 api-reference/guide/benchmarks.md delete mode 100644 samples/PolylineAlgorithm.NetTopologySuite.Sample/Program.cs delete mode 100644 samples/PolylineAlgorithm.SensorData.Sample/PolylineAlgorithm.SensorData.Sample.csproj delete mode 100644 samples/PolylineAlgorithm.SensorData.Sample/Program.cs delete mode 100644 samples/PolylineAlgorithm.SensorData.Sample/Properties/CodeCoverage.cs delete mode 100644 samples/PolylineAlgorithm.SensorData.Sample/SensorDataDecoder.cs delete mode 100644 samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs delete mode 100644 samples/PolylineAlgorithm.SensorData.Sample/SensorReading.cs diff --git a/.editorconfig b/.editorconfig index 7282c0f7..75d9084f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -274,6 +274,3 @@ dotnet_naming_style.underscore_camel_case.capitalization = camel_case # Public API analyzer dotnet_public_api_analyzer.require_api_files = true - -# RS0017: Symbol removed from public API - error severity (IDE guidance; build enforcement via WarningsAsErrors in .csproj) -dotnet_diagnostic.RS0017.severity = error diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 880b45f7..00000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,5 +0,0 @@ -* @petesramek - -.github/ @petesramek -src/ @petesramek -tests/ @petesramek diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 6236e3a0..dd84ea78 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,8 +1,8 @@ --- name: Bug report about: Create a report to help us improve -title: '[Bug]: ' -labels: 'bug' +title: '' +labels: '' assignees: '' --- @@ -11,22 +11,28 @@ assignees: '' A clear and concise description of what the bug is. **To Reproduce** -Minimal code snippet that reproduces the issue: - -```csharp -// paste reproduction code here -``` +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error **Expected behavior** A clear and concise description of what you expected to happen. -**Actual behavior** -A clear and concise description of what actually happens (include exception messages/stack traces if applicable). +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] -**Environment** - - Package version: [e.g. 2.1.0] - - .NET version: [e.g. net8.0] - - OS: [e.g. Windows 11, Ubuntu 24.04] +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] **Additional context** Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 2afb950d..00000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,5 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: Ask a question - url: https://github.com/petesramek/polyline-algorithm-csharp/discussions - about: Use GitHub Discussions for questions, ideas, or general feedback. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 5c8a425a..bbcbbe7d 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,8 +1,8 @@ --- name: Feature request about: Suggest an idea for this project -title: '[Feature]: ' -labels: 'enhancement' +title: '' +labels: '' assignees: '' --- diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 70eda657..00000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,19 +0,0 @@ -## Summary - - - -## Type of change - -- [ ] Bug fix -- [ ] New feature -- [ ] Breaking change -- [ ] Documentation / samples only - -## Checklist - -- [ ] Unit tests added or updated (`/tests`) -- [ ] Benchmarks added or updated (`/benchmarks`) — if performance-impacting -- [ ] XML doc comments updated for all public API changes -- [ ] `dotnet format` run with no issues -- [ ] README and `/samples` updated — if public API changed -- [ ] PR label added (`breaking` / `feat` / `fix` / `docs`) — for changelog categorization diff --git a/.github/actions/source/compile/action.yml b/.github/actions/source/compile/action.yml index dbe88dd5..0af331ee 100644 --- a/.github/actions/source/compile/action.yml +++ b/.github/actions/source/compile/action.yml @@ -12,7 +12,7 @@ inputs: file-version: description: 'Assembly file version.' required: true - treat-warnings-as-error: + treat-warnins-as-error: description: 'Treat warnings as errors.' required: true project-path: diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b00ae422..02a54502 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,23 +4,11 @@ updates: directory: "/" schedule: interval: "weekly" - labels: - - "dependencies" - assignees: - - "petesramek" - package-ecosystem: "nuget" directory: "/" schedule: interval: "weekly" - labels: - - "dependencies" - assignees: - - "petesramek" - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" - labels: - - "dependencies" - assignees: - - "petesramek" diff --git a/.github/release.yml b/.github/release.yml deleted file mode 100644 index e7b05735..00000000 --- a/.github/release.yml +++ /dev/null @@ -1,23 +0,0 @@ -changelog: - exclude: - labels: - - ignore-for-release - categories: - - title: Breaking Changes - labels: - - breaking - - title: New Features - labels: - - feat - - enhancement - - title: Bug Fixes - labels: - - fix - - bug - - title: Documentation - labels: - - docs - - documentation - - title: Other Changes - labels: - - '*' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5abb7df8..047d4afd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -130,7 +130,7 @@ jobs: assembly-version: ${{ env.assembly-version }} assembly-informational-version: ${{ env.assembly-informational-version }} file-version: ${{ env.file-version }} - treat-warnings-as-error: ${{ needs.workflow-variables.outputs.is-release }} + treat-warnins-as-error: ${{ needs.workflow-variables.outputs.is-release }} test: name: 'Run tests' diff --git a/.github/workflows/publish-documentation.yml b/.github/workflows/publish-documentation.yml index 7f01504d..85d8f21a 100644 --- a/.github/workflows/publish-documentation.yml +++ b/.github/workflows/publish-documentation.yml @@ -96,21 +96,6 @@ jobs: run: | cp -r api-reference/guide api-reference/${{ env.friendly-version }}/guide - - name: 'Download benchmark results' - uses: actions/download-artifact@v8 - with: - pattern: benchmark-* - path: /tmp/benchmarks - merge-multiple: true - - - name: 'Inject benchmark results into guide for v${{ env.friendly-version }}' - shell: bash - run: | - find /tmp/benchmarks -name "*-report-github.md" | sort | xargs -r cat > /tmp/benchmark_results.md - awk '/{benchmarks_section}/{while((getline line < "/tmp/benchmark_results.md") > 0) print line; close("/tmp/benchmark_results.md"); next} {print}' \ - "api-reference/${{ env.friendly-version }}/guide/benchmarks.md" > /tmp/benchmarks.md - mv /tmp/benchmarks.md "api-reference/${{ env.friendly-version }}/guide/benchmarks.md" - - name: 'Discover all versions' id: discover-versions shell: bash @@ -166,15 +151,15 @@ jobs: { echo "## Released Versions" echo "" - echo "| Version | Guide | API Reference | Release Notes |" - echo "|---------|-------|---------------|---------------|" + echo "| Version | Guide | API Reference |" + echo "|---------|-------|---------------|" for ver in $(echo "${{ steps.discover-versions.outputs.versions }}" | tr ',' '\n' | sort -Vr); do if [ "$ver" = "$latest" ]; then label="v${ver} (latest)" else label="v${ver}" fi - echo "| ${label} | [Guide](${ver}/guide/getting-started.html) | [API Reference](${ver}/PolylineAlgorithm.html) | [Release Notes](https://github.com/petesramek/polyline-algorithm-csharp/releases/tag/v${ver}) |" + echo "| ${label} | [Guide](${ver}/guide/getting-started.html) | [API Reference](${ver}/PolylineAlgorithm.html) |" done } > /tmp/versions_section.md awk '/{versions_section}/{while((getline line < "/tmp/versions_section.md") > 0) print line; close("/tmp/versions_section.md"); next} {print}' \ diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index c99f254d..4f8917b0 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -18,8 +18,8 @@ permissions: id-token: write contents: write -concurrency: - group: pull-request-${{ github.head_ref || github.ref }} +concurrency: + group: pull-request-${{ github.head_ref || github.ref }} cancel-in-progress: true env: @@ -120,7 +120,7 @@ jobs: assembly-version: ${{ env.assembly-version }} assembly-informational-version: ${{ env.assembly-informational-version }} file-version: ${{ env.file-version }} - treat-warnings-as-error: ${{ needs.workflow-variables.outputs.is-release }} + treat-warnins-as-error: ${{ needs.workflow-variables.outputs.is-release }} test: name: 'Run tests' @@ -189,7 +189,7 @@ jobs: - name: Pack with .NET run: | dotnet pack ${{ vars.SRC_DEFAULT_GLOB_PATTERN }} --configuration ${{ env.build-configuration }} /p:Platform="${{ env.build-platform }}" /p:PackageVersion=${{ env.release-version }} /p:Version=${{ env.assembly-version }} /p:AssemblyInformationalVersion=${{ env.assembly-informational-version }} /p:FileVersion=${{ env.file-version }} --output ${{ runner.temp }}/${{ env.nuget-packages-directory }} - + - name: Upload Package uses: actions/upload-artifact@v7 with: @@ -222,20 +222,39 @@ jobs: nuget-feed-api-key: ${{ secrets.NUGET_PACKAGE_FEED_API_KEY }} nuget-feed-server: 'AzureArtifacts' working-directory: ${{ runner.temp }}/${{ env.nuget-packages-directory }} - dotnet-sdk-version: ${{ env.dotnet-sdk-version }} + dotnet-sdk-version: ${{ env.dotnet-sdk-version }}' - security: - name: 'Check for vulnerable packages' + benchmark: + if: ${{ github.env.is_release || vars.BENCHMARKDOTNET_RUN_OVERRIDE == 'true' }} + name: Benchmark with .NET CLI on ${{ matrix.os }} needs: [build] - runs-on: ubuntu-latest + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} steps: - name: 'Checkout ${{ github.head_ref || github.ref }}' uses: actions/checkout@v6 - - - name: 'Setup .NET' + - name: Install .NET SDK uses: actions/setup-dotnet@v5 with: - dotnet-version: ${{ env.dotnet-sdk-version }} - - - name: 'Check for vulnerable packages' - run: dotnet list src/PolylineAlgorithm/PolylineAlgorithm.csproj package --vulnerable --include-transitive + dotnet-version: | + 8.x + 10.x + - name: Download Build + uses: actions/download-artifact@v8 + with: + name: build + - name: Benchmark + working-directory: ${{ vars.BENCHMARKDOTNET_WORKING_DIRECTORY }} + run: dotnet run --configuration ${{ env.build-configuration }} /p:Platform=${{ env.build-platform }} --framework ${{ vars.DEFAULT_BUILD_FRAMEWORK }} --runtimes ${{ vars.BENCHMARKDOTNET_RUNTIMES }} --filter ${{ vars.BENCHMARKDOTNET_FILTER }} --artifacts ${{ runner.temp }}/benchmarks/ --exporters GitHub --memory --iterationTime 100 --join + - name: Upload Benchmark Results + uses: actions/upload-artifact@v7 + with: + name: benchmark-${{ matrix.os }} + path: | + ${{ runner.temp }}/benchmarks/**/*-report-github.md + - name: Write Benchmark Summary + shell: bash + run: cat **/*-report-github.md > $GITHUB_STEP_SUMMARY + working-directory: ${{ runner.temp }}/benchmarks/ diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b0bd5699..0d2808a8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -129,7 +129,7 @@ jobs: assembly-version: ${{ env.assembly-version }} assembly-informational-version: ${{ env.assembly-informational-version }} file-version: ${{ env.file-version }} - treat-warnings-as-error: ${{ needs.workflow-variables.outputs.is-release }} + treat-warnins-as-error: ${{ needs.workflow-variables.outputs.is-release }} test: name: 'Run tests' @@ -169,89 +169,6 @@ jobs: - name: Write code coverage report summary run: cat ${{ steps.code-coverage-report.outputs.code-coverage-report-file }} >> $GITHUB_STEP_SUMMARY - update-api-unshipped: - name: 'Update PublicAPI.Unshipped.txt' - needs: [workflow-variables, validate-release] - # Run even when build fails — the build may fail solely because a dropped preview API is still - # listed in Unshipped.txt (RS0017). This job fixes exactly that, so it must not be gated on build. - if: ${{ needs.workflow-variables.outputs.is-preview == 'true' && needs.validate-release.result == 'success' }} - runs-on: ubuntu-latest - steps: - - name: 'Checkout ${{ github.ref }}' - uses: actions/checkout@v6 - - - name: 'Setup .NET' - uses: actions/setup-dotnet@v5 - with: - dotnet-version: ${{ env.dotnet-sdk-version }} - - - name: 'Snapshot PublicAPI.Shipped.txt' - shell: bash - run: cp src/PolylineAlgorithm/PublicAPI.Shipped.txt src/PolylineAlgorithm/PublicAPI.Shipped.txt.bak - - - name: 'Sync PublicAPI.Unshipped.txt (add new + remove dropped preview APIs)' - shell: bash - run: dotnet format analyzers src/PolylineAlgorithm/PolylineAlgorithm.csproj --diagnostics RS0016 RS0017 - - - name: 'Guard against accidental shipped API removal' - shell: bash - run: | - SHIPPED="src/PolylineAlgorithm/PublicAPI.Shipped.txt" - if ! diff -q "$SHIPPED" "$SHIPPED.bak" > /dev/null 2>&1; then - echo "::error::Breaking change detected — a shipped API was removed from PublicAPI.Shipped.txt." - echo "::error::This requires a major version bump. Reverting the unintended change." - cp "$SHIPPED.bak" "$SHIPPED" - exit 1 - fi - rm -f "$SHIPPED.bak" - - - name: 'Configure git identity' - uses: './.github/actions/git/configure-identity' - - - name: 'Commit and push updated API files' - shell: bash - run: | - git add src/PolylineAlgorithm/PublicAPI.Unshipped.txt - git diff --staged --quiet || ( - git commit -m "Sync PublicAPI.Unshipped.txt (add new, remove dropped preview APIs)" && - git pull --rebase origin ${{ github.ref_name }} && - git push - ) - - promote-api-files: - name: 'Promote PublicAPI files (Unshipped -> Shipped)' - needs: [workflow-variables, test, validate-release] - if: ${{ needs.workflow-variables.outputs.is-release == 'true' }} - runs-on: ubuntu-latest - steps: - - name: 'Checkout ${{ github.ref }}' - uses: actions/checkout@v6 - - - name: 'Promote Unshipped.txt into Shipped.txt' - shell: bash - run: | - UNSHIPPED="src/PolylineAlgorithm/PublicAPI.Unshipped.txt" - SHIPPED="src/PolylineAlgorithm/PublicAPI.Shipped.txt" - - # Append every non-blank, non-header line from Unshipped into Shipped - tail -n +2 "$UNSHIPPED" | grep -v '^[[:space:]]*$' >> "$SHIPPED" || true - - # Reset Unshipped to just the nullable-enable header (with BOM to match convention) - printf '\xef\xbb\xbf#nullable enable\n' > "$UNSHIPPED" - - - name: 'Configure git identity' - uses: './.github/actions/git/configure-identity' - - - name: 'Commit and push promoted API files' - shell: bash - run: | - git add src/PolylineAlgorithm/PublicAPI.Shipped.txt src/PolylineAlgorithm/PublicAPI.Unshipped.txt - git diff --staged --quiet || ( - git commit -m "Promote PublicAPI.Unshipped.txt into PublicAPI.Shipped.txt for release" && - git pull --rebase origin ${{ github.ref_name }} && - git push - ) - pack: name: 'Package binaries' needs: [versioning, build, test, validate-release] @@ -290,44 +207,9 @@ jobs: ${{ runner.temp }}/${{ env.nuget-packages-directory }}/**/*.nupkg ${{ runner.temp }}/${{ env.nuget-packages-directory }}/**/*.snupkg - benchmark: - name: Benchmark with .NET CLI on ${{ matrix.os }} - needs: [workflow-variables, build, validate-release] - if: ${{ needs.workflow-variables.outputs.is-release == 'true' || vars.BENCHMARKDOTNET_RUN_OVERRIDE == 'true' }} - strategy: - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - runs-on: ${{ matrix.os }} - steps: - - name: 'Checkout ${{ github.head_ref || github.ref }}' - uses: actions/checkout@v6 - - name: Install .NET SDK - uses: actions/setup-dotnet@v5 - with: - dotnet-version: | - 8.x - 10.x - - name: Download Build - uses: actions/download-artifact@v8 - with: - name: build - - name: Benchmark - working-directory: ${{ vars.BENCHMARKDOTNET_WORKING_DIRECTORY }} - run: dotnet run --configuration ${{ env.build-configuration }} /p:Platform=${{ env.build-platform }} --framework ${{ vars.DEFAULT_BUILD_FRAMEWORK }} --runtimes ${{ vars.BENCHMARKDOTNET_RUNTIMES }} --filter ${{ vars.BENCHMARKDOTNET_FILTER }} --artifacts ${{ runner.temp }}/benchmarks/ --exporters GitHub --memory --iterationTime 100 --join - - name: Upload Benchmark Results - uses: actions/upload-artifact@v7 - with: - name: benchmark-${{ matrix.os }} - path: | - ${{ runner.temp }}/benchmarks/**/*-report-github.md - - name: Write Benchmark Summary - shell: bash - run: cat **/*-report-github.md > $GITHUB_STEP_SUMMARY - working-directory: ${{ runner.temp }}/benchmarks/ - publish-documentation: name: 'Publish documentation' - needs: [pack, benchmark, validate-release, workflow-variables] + needs: [pack, validate-release, workflow-variables] if: ${{ needs.workflow-variables.outputs.is-release == 'true' }} uses: ./.github/workflows/publish-documentation.yml permissions: @@ -337,14 +219,8 @@ jobs: publish-package: name: 'Publish package' - needs: [pack, validate-release, publish-documentation, update-api-unshipped, promote-api-files] - if: | - always() && - needs.pack.result == 'success' && - needs.validate-release.result == 'success' && - (needs.publish-documentation.result == 'success' || needs.publish-documentation.result == 'skipped') && - (needs.promote-api-files.result == 'success' || needs.promote-api-files.result == 'skipped') && - (needs.update-api-unshipped.result == 'success' || needs.update-api-unshipped.result == 'skipped') + needs: [pack, validate-release, publish-documentation] + if: ${{ always() && needs.pack.result == 'success' && needs.validate-release.result == 'success' && (needs.publish-documentation.result == 'success' || needs.publish-documentation.result == 'skipped') }} env: package-artifact-name: ${{ needs.pack.outputs.package-artifact-name }} runs-on: ubuntu-latest @@ -396,68 +272,9 @@ jobs: is-preview: ${{ env.is-preview }} notes-start-tag: ${{ steps.determine-notes-start-tag.outputs.notes-start-tag }} - update-changelog: - name: 'Update CHANGELOG.md' - needs: [workflow-variables, release, versioning] - if: ${{ needs.workflow-variables.outputs.is-release == 'true' }} - runs-on: ubuntu-latest - env: - GH_TOKEN: ${{ github.token }} - release-version: ${{ needs.versioning.outputs.release-version }} - steps: - - name: 'Checkout ${{ github.ref }}' - uses: actions/checkout@v6 - with: - ref: ${{ github.ref }} - - - name: 'Fetch release notes' - shell: bash - run: | - gh release view ${{ env.release-version }} --json body --jq '.body' > /tmp/release-notes.txt - - - name: 'Prepend entry to CHANGELOG.md' - shell: bash - run: | - release_date=$(date -u +%Y-%m-%d) - { - echo "## ${{ env.release-version }} — ${release_date}" - echo "" - cat /tmp/release-notes.txt - echo "" - } > /tmp/new-entry.txt - awk ' - // { - print - print "" - while ((getline line < "/tmp/new-entry.txt") > 0) print line - close("/tmp/new-entry.txt") - next - } - { print } - ' CHANGELOG.md > /tmp/changelog-new.md - mv /tmp/changelog-new.md CHANGELOG.md - - - name: 'Configure git identity' - uses: './.github/actions/git/configure-identity' - - - name: 'Commit and push CHANGELOG.md' - shell: bash - run: | - git add CHANGELOG.md - git diff --staged --quiet || ( - git commit -m "Update CHANGELOG.md for ${{ env.release-version }}" && - git pull --rebase origin ${{ github.ref_name }} && - git push - ) - - - name: 'Write changelog summary' - shell: bash - run: | - echo "✅ CHANGELOG.md updated for **${{ env.release-version }}**." >> $GITHUB_STEP_SUMMARY - merge-to-main: name: 'Merge ${{ github.ref_name }} into main' - needs: [workflow-variables, release, versioning, update-changelog] + needs: [workflow-variables, release, versioning] if: ${{ needs.workflow-variables.outputs.is-release == 'true' }} runs-on: ubuntu-latest permissions: @@ -554,10 +371,17 @@ jobs: git checkout -b "${{ steps.resolve-support-branch.outputs.support-branch }}" git push --set-upstream origin "${{ steps.resolve-support-branch.outputs.support-branch }}" + - name: 'Lock support branch' + if: ${{ steps.check-support-branch.outputs.support-branch-exists == 'false' }} + uses: './.github/actions/github/branch-protection/lock' + with: + branch: ${{ steps.resolve-support-branch.outputs.support-branch }} + token: ${{ secrets.GH_ADMIN_TOKEN }} + - name: 'Write support branch summary' run: | if [[ "${{ steps.check-support-branch.outputs.support-branch-exists }}" == "false" ]]; then - echo "✅ Created support branch **${{ steps.resolve-support-branch.outputs.support-branch }}**." >> $GITHUB_STEP_SUMMARY + echo "✅ Created and locked support branch **${{ steps.resolve-support-branch.outputs.support-branch }}**." >> $GITHUB_STEP_SUMMARY else echo "⏭️ Support branch **${{ steps.resolve-support-branch.outputs.support-branch }}** already exists." >> $GITHUB_STEP_SUMMARY fi diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 9264cdaa..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,10 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), -and release notes are generated automatically from merged pull requests. - -See all releases at: - - diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index d0b9d1d8..00000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,47 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Commitment - -We are committed to providing a welcoming and inspiring community for all. We pledge to create an environment in which every individual feels valued, respected, and free from harassment and discrimination. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -- Using welcoming and inclusive language -- Being respectful of differing opinions, viewpoints, and experiences -- Gracefully accepting constructive criticism -- Focusing on what is best for the community -- Showing empathy towards other community members - -Examples of unacceptable behavior include: - -- The use of sexualized language or imagery and unwelcome sexual attention or advances -- Trolling, insulting/derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or electronic address, without explicit permission -- Other conduct which could reasonably be considered inappropriate in a professional setting - -## Enforcement - -Community leaders are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for behaviors that they deem inappropriate, threatening, offensive, or harmful. - -## Reporting - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the project maintainer responsible for enforcement. All complaints will be reviewed and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the reporter of any incident. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html. - -Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. diff --git a/Directory.Build.props b/Directory.Build.props index 80c3886e..96ebb124 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -6,8 +6,6 @@ enable true en - true - embedded @@ -22,7 +20,6 @@ - diff --git a/PolylineAlgorithm.slnx b/PolylineAlgorithm.slnx index 3c54b2a7..29fa9445 100644 --- a/PolylineAlgorithm.slnx +++ b/PolylineAlgorithm.slnx @@ -7,7 +7,6 @@ - diff --git a/README.md b/README.md index 0555c16f..9dfb8a18 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,6 @@ # PolylineAlgorithm for .NET -[![NuGet](https://img.shields.io/nuget/v/PolylineAlgorithm)](https://www.nuget.org/packages/PolylineAlgorithm) -[![Build](https://github.com/petesramek/polyline-algorithm-csharp/actions/workflows/build.yml/badge.svg)](https://github.com/petesramek/polyline-algorithm-csharp/actions/workflows/build.yml) -[![License: MIT](https://img.shields.io/github/license/petesramek/polyline-algorithm-csharp)](./LICENSE) - -Google's Encoded Polyline Algorithm compresses sequences of geographic coordinates into a compact ASCII string, widely used in mapping APIs. This library provides a fully compliant .NET implementation with extensible, type-safe encoding and decoding APIs. +Lightweight .NET Standard 2.1 library implementing Google-compliant Encoded Polyline Algorithm with strong input validation, modern API patterns, and extensibility for custom coordinate types. ## Table of Contents @@ -21,16 +17,15 @@ Google's Encoded Polyline Algorithm compresses sequences of geographic coordinat ## Features - Fully compliant Google Encoded Polyline Algorithm for .NET Standard 2.1+ -- Extensible APIs — implement your own encoder/decoder for any coordinate or polyline type -- Robust input validation with descriptive exceptions for malformed or out-of-range data +- Extensible encoding and decoding APIs for custom coordinate and polyline types (`IPolylineEncoder`, `IPolylineDecoder`, `AbstractPolylineEncoder`, `AbstractPolylineDecoder`) +- Extension methods for encoding from `List` and arrays (`PolylineEncoderExtensions`) +- Robust input validation with descriptive exceptions for malformed/invalid data - Advanced configuration via `PolylineEncodingOptions` (precision, buffer size, logging) -- Extension methods for encoding directly from `List` and arrays -- Logging and diagnostic support via `Microsoft.Extensions.Logging` -- Low-level utilities for normalization, validation, and bit-level operations via static `PolylineEncoding` class -- Thread-safe, stateless APIs +- Logging and diagnostic support for CI/CD and developer diagnostics via `Microsoft.Extensions.Logging` +- Low-level utilities for normalization, validation, encoding and decoding via static `PolylineEncoding` class - Thorough unit tests and benchmarks for correctness and performance - Auto-generated API documentation ([API Reference](https://petesramek.github.io/polyline-algorithm-csharp/)) -- Supports .NET Core, .NET 5+, Xamarin, Unity, Blazor, and any platform targeting `netstandard2.1` +- Support for .NET Core, .NET 5+, Xamarin, Unity, Blazor, and other platforms supporting `netstandard2.1` ## Installation @@ -48,19 +43,7 @@ Install-Package PolylineAlgorithm ## Usage -The library provides abstract base classes to implement your own encoder and decoder for any coordinate and polyline type. Inherit from `AbstractPolylineEncoder` or `AbstractPolylineDecoder`, override the coordinate accessors, then call `Encode` or `Decode`. - -### Quick Start - -```csharp -// 1. Implement a minimal encoder (see full example below) -var encoder = new MyPolylineEncoder(); -string encoded = encoder.Encode(coordinates); // e.g. "yseiHoc_MwacOjnwM" - -// 2. Implement a minimal decoder (see full example below) -var decoder = new MyPolylineDecoder(); -IEnumerable<(double Latitude, double Longitude)> decoded = decoder.Decode(encoded); -``` +The library provides abstract base classes to implement your own encoder and decoder for any coordinate and polyline type. ### Custom encoder and decoder @@ -73,9 +56,23 @@ using PolylineAlgorithm; using PolylineAlgorithm.Abstraction; public sealed class MyPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - protected override double GetLatitude((double Latitude, double Longitude) coordinate) => coordinate.Latitude; - protected override double GetLongitude((double Latitude, double Longitude) coordinate) => coordinate.Longitude; - protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); + public MyPolylineEncoder() + : base() { } + + public MyPolylineEncoder(PolylineEncodingOptions options) + : base(options) { } + + protected override double GetLatitude((double Latitude, double Longitude) coordinate) { + return coordinate.Latitude; + } + + protected override double GetLongitude((double Latitude, double Longitude) coordinate) { + return coordinate.Longitude; + } + + protected override string CreatePolyline(ReadOnlyMemory polyline) { + return polyline.ToString(); + } } ``` @@ -105,8 +102,19 @@ using PolylineAlgorithm; using PolylineAlgorithm.Abstraction; public sealed class MyPolylineDecoder : AbstractPolylineDecoder { - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); - protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); + public MyPolylineDecoder() + : base() { } + + public MyPolylineDecoder(PolylineEncodingOptions options) + : base(options) { } + + protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) { + return (latitude, longitude); + } + + protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { + return polyline.AsMemory(); + } } ``` @@ -128,13 +136,8 @@ Full API docs and guides (auto-generated from source) are available at [API Refe ## Benchmarks -- See [`/benchmarks`](./benchmarks) in the repo for benchmark projects. -- Run benchmarks with: - ```shell - dotnet run --project benchmarks/PolylineAlgorithm.Benchmarks --configuration Release - ``` -- For guidance on writing and interpreting benchmarks, see [docs/benchmarks.md](./docs/benchmarks.md). -- Contributors: update benchmarks and document results for performance-impacting PRs. +- See `/benchmarks` in the repo for performance evaluation. +- Contributors: Update benchmarks and document results for performance-impacting PRs. ## FAQ @@ -170,13 +173,13 @@ A: Currently, only batch encode/decode is supported. For streaming scenarios, im ## Contributing -- Follow code style and PR instructions in [CONTRIBUTING.md](./CONTRIBUTING.md). +- Follow code style and PR instructions in [AGENTS.md](./AGENTS.md). - Ensure all features are covered by tests and XML doc comments. - For questions or suggestions, open an issue and use the provided templates. ## Support -Have a question, bug, or feature request? [Open an issue](https://github.com/petesramek/polyline-algorithm-csharp/issues/new/choose) — bug report and feature request templates are available to guide you. +Have a question, bug, or feature request? [Open an issue!](https://github.com/petesramek/polyline-algorithm-csharp/issues) --- diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index 8ca1471a..00000000 --- a/SECURITY.md +++ /dev/null @@ -1,23 +0,0 @@ -# Security Policy - -## Supported Versions - -| Version | Supported | -| ------- | --------- | -| Latest | ✅ | -| Older | ❌ | - -Only the latest published version receives security fixes. If you are on an older version, please upgrade. - -## Reporting a Vulnerability - -**Please do not open a public GitHub issue for security vulnerabilities.** - -Report security issues privately via [GitHub Security Advisories](https://github.com/petesramek/polyline-algorithm-csharp/security/advisories/new). - -Include: -- A description of the vulnerability -- Steps to reproduce or a proof-of-concept -- Potential impact assessment - -You can expect an initial response within 5 business days. Once confirmed, a fix will be prioritized and a patch release issued. You will be credited in the release notes unless you prefer to remain anonymous. diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml deleted file mode 100644 index b5693066..00000000 --- a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml +++ /dev/null @@ -1,233 +0,0 @@ -### YamlMime:ApiPage -title: Class AbstractPolylineDecoder -body: -- api1: Class AbstractPolylineDecoder - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2 - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L22 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2 - commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2 -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Abstraction - url: PolylineAlgorithm.Abstraction.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates. -- code: 'public abstract class AbstractPolylineDecoder : IPolylineDecoder' -- h4: Type Parameters -- parameters: - - name: TPolyline - description: The type that represents the encoded polyline input. - - name: TCoordinate - description: The type that represents a decoded geographic coordinate. -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: AbstractPolylineDecoder - url: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.html -- h4: Implements -- list: - - text: IPolylineDecoder - url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.MemberwiseClone() - url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Remarks -- markdown: >- - Derive from this class to implement a decoder for a specific polyline type. Override - - and to provide type-specific behavior. -- h2: Constructors -- api3: AbstractPolylineDecoder() - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L28 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor -- markdown: Initializes a new instance of the class with default encoding options. -- code: protected AbstractPolylineDecoder() -- api3: AbstractPolylineDecoder(PolylineEncodingOptions) - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L40 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) -- markdown: Initializes a new instance of the class with the specified encoding options. -- code: protected AbstractPolylineDecoder(PolylineEncodingOptions options) -- h4: Parameters -- parameters: - - name: options - type: - - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html - description: The to use for encoding operations. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when options is null. -- h2: Properties -- api3: Options - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Options - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L54 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options - commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options -- markdown: Gets the encoding options used by this polyline decoder. -- code: public PolylineEncodingOptions Options { get; } -- h4: Property Value -- parameters: - - type: - - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html -- h2: Methods -- api3: CreateCoordinate(double, double) - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_CreateCoordinate_System_Double_System_Double_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L202 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateCoordinate(System.Double,System.Double) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateCoordinate(System.Double,System.Double) -- markdown: Creates a TCoordinate instance from the specified latitude and longitude values. -- code: protected abstract TCoordinate CreateCoordinate(double latitude, double longitude) -- h4: Parameters -- parameters: - - name: latitude - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The latitude component of the coordinate, in degrees. - - name: longitude - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The longitude component of the coordinate, in degrees. -- h4: Returns -- parameters: - - type: - - TCoordinate - description: A TCoordinate instance representing the specified geographic coordinate. -- api3: Decode(TPolyline, CancellationToken) - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L81 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) -- markdown: >- - Decodes an encoded TPolyline into a sequence of TCoordinate instances, - - with support for cancellation. -- code: public IEnumerable Decode(TPolyline polyline, CancellationToken cancellationToken = default) -- h4: Parameters -- parameters: - - name: polyline - type: - - TPolyline - description: The TPolyline instance containing the encoded polyline string to decode. - - name: cancellationToken - type: - - text: CancellationToken - url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken - description: A that can be used to cancel the decoding operation. - optional: true -- h4: Returns -- parameters: - - type: - - text: IEnumerable - url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 - - < - - TCoordinate - - '>' - description: An of TCoordinate representing the decoded latitude and longitude pairs. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when polyline is null. - - type: - - text: ArgumentException - url: https://learn.microsoft.com/dotnet/api/system.argumentexception - description: Thrown when polyline is empty. - - type: - - text: InvalidPolylineException - url: PolylineAlgorithm.InvalidPolylineException.html - description: Thrown when the polyline format is invalid or malformed at a specific position. - - type: - - text: OperationCanceledException - url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception - description: Thrown when cancellationToken is canceled during decoding. -- api3: GetReadOnlyMemory(in TPolyline) - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_GetReadOnlyMemory__0__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L187 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@) -- markdown: Extracts the underlying read-only memory region of characters from the specified polyline instance. -- code: protected abstract ReadOnlyMemory GetReadOnlyMemory(in TPolyline polyline) -- h4: Parameters -- parameters: - - name: polyline - type: - - TPolyline - description: The TPolyline instance from which to extract the character sequence. -- h4: Returns -- parameters: - - type: - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: A of representing the encoded polyline characters. -- api3: ValidateFormat(ReadOnlyMemory, ILogger?) - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_ValidateFormat_System_ReadOnlyMemory_System_Char__Microsoft_Extensions_Logging_ILogger_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L167 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger) -- markdown: Validates the format of the polyline character sequence, ensuring all characters are within the allowed range. -- code: protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? logger) -- h4: Parameters -- parameters: - - name: sequence - type: - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: The read-only memory region of characters representing the polyline to validate. - - name: logger - type: - - text: ILogger - url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger - - '?' - description: An optional used to log a warning when format validation fails. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentException - url: https://learn.microsoft.com/dotnet/api/system.argumentexception - description: Thrown when the polyline contains characters outside the valid encoding range or has an invalid block structure. -languageId: csharp -metadata: - description: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates. diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml deleted file mode 100644 index 64e97b11..00000000 --- a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml +++ /dev/null @@ -1,219 +0,0 @@ -### YamlMime:ApiPage -title: Class AbstractPolylineEncoder -body: -- api1: Class AbstractPolylineEncoder - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2 - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L27 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2 - commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2 -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Abstraction - url: PolylineAlgorithm.Abstraction.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings. -- code: 'public abstract class AbstractPolylineEncoder : IPolylineEncoder' -- h4: Type Parameters -- parameters: - - name: TCoordinate - description: The type that represents a geographic coordinate to encode. - - name: TPolyline - description: The type that represents the encoded polyline output. -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: AbstractPolylineEncoder - url: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.html -- h4: Implements -- list: - - text: IPolylineEncoder - url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.MemberwiseClone() - url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h4: Extension Methods -- list: - - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, List) - url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__ - - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, TCoordinate[]) - url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___ -- h2: Remarks -- markdown: >- - Derive from this class to implement an encoder for a specific coordinate and polyline type. Override - - , , and to provide type-specific behavior. -- h2: Constructors -- api3: AbstractPolylineEncoder() - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L33 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor -- markdown: Initializes a new instance of the class with default encoding options. -- code: protected AbstractPolylineEncoder() -- api3: AbstractPolylineEncoder(PolylineEncodingOptions) - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L43 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) -- markdown: Initializes a new instance of the class with the specified encoding options. -- code: protected AbstractPolylineEncoder(PolylineEncodingOptions options) -- h4: Parameters -- parameters: - - name: options - type: - - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html - description: The to use for encoding operations. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when options is null -- h2: Properties -- api3: Options - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Options - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L57 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options - commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options -- markdown: Gets the encoding options used by this polyline encoder. -- code: public PolylineEncodingOptions Options { get; } -- h4: Property Value -- parameters: - - type: - - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html -- h2: Methods -- api3: CreatePolyline(ReadOnlyMemory) - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_CreatePolyline_System_ReadOnlyMemory_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L174 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char}) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char}) -- markdown: Creates a polyline instance from the provided read-only sequence of characters. -- code: protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline) -- h4: Parameters -- parameters: - - name: polyline - type: - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: A containing the encoded polyline characters. -- h4: Returns -- parameters: - - type: - - TPolyline - description: An instance of TPolyline representing the encoded polyline. -- api3: Encode(ReadOnlySpan, CancellationToken) - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L80 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) -- markdown: Encodes a collection of TCoordinate instances into an encoded TPolyline string. -- code: >- - [SuppressMessage("Design", "MA0051:Method is too long", Justification = "Method contains local methods. Actual method only 55 lines.")] - - public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default) -- h4: Parameters -- parameters: - - name: coordinates - type: - - text: ReadOnlySpan - url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 - - < - - TCoordinate - - '>' - description: The collection of TCoordinate objects to encode. - - name: cancellationToken - type: - - text: CancellationToken - url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken - description: A that can be used to cancel the encoding operation. - optional: true -- h4: Returns -- parameters: - - type: - - TPolyline - description: An instance of TPolyline representing the encoded coordinates. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when coordinates is null. - - type: - - text: ArgumentException - url: https://learn.microsoft.com/dotnet/api/system.argumentexception - description: Thrown when coordinates is an empty enumeration. - - type: - - text: InvalidOperationException - url: https://learn.microsoft.com/dotnet/api/system.invalidoperationexception - description: Thrown when the internal encoding buffer cannot accommodate the encoded value. -- api3: GetLatitude(TCoordinate) - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetLatitude__0_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L194 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLatitude(`0) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLatitude(`0) -- markdown: Extracts the latitude value from the specified coordinate. -- code: protected abstract double GetLatitude(TCoordinate current) -- h4: Parameters -- parameters: - - name: current - type: - - TCoordinate - description: The coordinate from which to extract the latitude. -- h4: Returns -- parameters: - - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The latitude value as a . -- api3: GetLongitude(TCoordinate) - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetLongitude__0_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L184 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLongitude(`0) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLongitude(`0) -- markdown: Extracts the longitude value from the specified coordinate. -- code: protected abstract double GetLongitude(TCoordinate current) -- h4: Parameters -- parameters: - - name: current - type: - - TCoordinate - description: The coordinate from which to extract the longitude. -- h4: Returns -- parameters: - - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The longitude value as a . -languageId: csharp -metadata: - description: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings. diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml deleted file mode 100644 index 733987cb..00000000 --- a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml +++ /dev/null @@ -1,90 +0,0 @@ -### YamlMime:ApiPage -title: Interface IPolylineDecoder -body: -- api1: Interface IPolylineDecoder - id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2 - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L22 - metadata: - uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2 - commentId: T:PolylineAlgorithm.Abstraction.IPolylineDecoder`2 -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Abstraction - url: PolylineAlgorithm.Abstraction.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates. -- code: public interface IPolylineDecoder -- h4: Type Parameters -- parameters: - - name: TPolyline - description: >- - The type that represents the encoded polyline input. Common implementations use , - - but custom wrapper types are allowed to carry additional metadata. - - name: TValue - description: >- - The coordinate type returned by the decoder. Typical implementations return a struct or class that - - contains latitude and longitude (for example a LatLng type or a ValueTuple<double,double>). -- h2: Methods -- api3: Decode(TPolyline, CancellationToken) - id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L48 - metadata: - uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) - commentId: M:PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) -- markdown: >- - Decodes the specified encoded polyline into an ordered sequence of geographic coordinates. - - The sequence preserves the original vertex order encoded by the polyline. -- code: IEnumerable Decode(TPolyline polyline, CancellationToken cancellationToken = default) -- h4: Parameters -- parameters: - - name: polyline - type: - - TPolyline - description: >- - The TPolyline instance containing the encoded polyline to decode. - - Implementations SHOULD validate the input and may throw - - or for invalid formats. - - name: cancellationToken - type: - - text: CancellationToken - url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken - description: >- - A to observe while decoding. If cancellation is requested, - - implementations SHOULD stop work and throw an . - optional: true -- h4: Returns -- parameters: - - type: - - text: IEnumerable - url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 - - < - - TValue - - '>' - description: >- - An of TValue representing the decoded - - latitude/longitude pairs (or equivalent coordinates) in the same order they were encoded. -- h4: Remarks -- markdown: >- - Implementations commonly follow the Google Encoded Polyline Algorithm Format, but this interface - - does not mandate a specific encoding. Consumers should rely on a concrete decoder's documentation - - to understand the exact encoding supported. -- h4: Exceptions -- parameters: - - type: - - text: OperationCanceledException - url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception - description: Thrown when the provided cancellationToken requests cancellation. -languageId: csharp -metadata: - description: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates. diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml deleted file mode 100644 index 341a9de7..00000000 --- a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml +++ /dev/null @@ -1,142 +0,0 @@ -### YamlMime:ApiPage -title: Interface IPolylineEncoder -body: -- api1: Interface IPolylineEncoder - id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2 - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L36 - metadata: - uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2 - commentId: T:PolylineAlgorithm.Abstraction.IPolylineEncoder`2 -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Abstraction - url: PolylineAlgorithm.Abstraction.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: >- - Contract for encoding a sequence of geographic coordinates into an encoded polyline representation. - - Implementations interpret the generic TValue type and produce an encoded - - representation of those coordinates as TPolyline. -- code: public interface IPolylineEncoder -- h4: Type Parameters -- parameters: - - name: TValue - description: >- - The concrete coordinate representation used by the encoder (for example a struct or class containing - - Latitude and Longitude values). Implementations must document the expected shape, - - units (typically decimal degrees), and any required fields for TValue. - - Common shapes: - - - A struct or class with two double properties named Latitude and Longitude. - - - A tuple-like type (for example ValueTuple<double,double>) where the encoder documents - which element represents latitude and longitude. - - name: TPolyline - description: >- - The encoded polyline representation returned by the encoder (for example string, - - ReadOnlyMemory<char>, or a custom wrapper type). Concrete implementations should document - - the chosen representation and any memory / ownership expectations. -- h4: Extension Methods -- list: - - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, List) - url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__ - - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, TValue[]) - url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___ -- h2: Remarks -- markdown: >- - - This interface is intentionally minimal to allow different encoding strategies (Google encoded polyline, - precision/scale variants, or custom compressed formats) to be expressed behind a common contract. - - Implementations should document: - - Coordinate precision and rounding rules (for example 1e-5 for 5-decimal precision). - - Coordinate ordering and whether altitude or additional dimensions are supported. - - Thread-safety guarantees: whether instances are safe to reuse concurrently or must be instantiated per-call. - - Implementations are encouraged to be memory-efficient; the API accepts a - to avoid forced allocations when callers already have contiguous memory. -- h2: Methods -- api3: Encode(ReadOnlySpan, CancellationToken) - id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L76 - metadata: - uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) - commentId: M:PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) -- markdown: >- - Encodes a sequence of geographic coordinates into an encoded polyline representation. - - The order of coordinates in coordinates is preserved in the encoded result. -- code: TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default) -- h4: Parameters -- parameters: - - name: coordinates - type: - - text: ReadOnlySpan - url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 - - < - - TValue - - '>' - description: >- - The collection of TValue instances to encode into a polyline. - - The span may be empty; implementations should return an appropriate empty encoded representation - - (for example an empty string or an empty memory slice) rather than null. - - name: cancellationToken - type: - - text: CancellationToken - url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken - description: >- - A that can be used to cancel the encoding operation. - - Implementations should observe this token and throw - - when cancellation is requested. For fast, in-memory encoders cancellation may be best-effort. - optional: true -- h4: Returns -- parameters: - - type: - - TPolyline - description: >- - A TPolyline containing the encoded polyline that represents the input coordinates. - - The exact format and any delimiting/terminating characters are implementation-specific and must be - - documented by concrete encoder types. -- h4: Examples -- markdown: >- -
// Example pseudocode for typical usage with a string-based encoder:
-
-    var coords = new[] {
-        new Coordinate { Latitude = 47.6219, Longitude = -122.3503 },
-        new Coordinate { Latitude = 47.6220, Longitude = -122.3504 }
-    };
-
-    IPolylineEncoder<Coordinate,string> encoder = new GoogleEncodedPolylineEncoder();
-
-    string encoded = encoder.Encode(coords, CancellationToken.None);
-- h4: Remarks -- markdown: >- - - Implementations should validate input as appropriate and document any preconditions (for example - if coordinates must be within [-90,90] latitude and [-180,180] longitude). - - For large input sequences, implementations may provide streaming or incremental encoders; those - variants can still implement this interface by materializing the final encoded result. -- h4: Exceptions -- parameters: - - type: - - text: OperationCanceledException - url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception - description: Thrown if the operation is canceled via cancellationToken. -languageId: csharp -metadata: - description: >- - Contract for encoding a sequence of geographic coordinates into an encoded polyline representation. - - Implementations interpret the generic TValue type and produce an encoded - - representation of those coordinates as TPolyline. diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.yml deleted file mode 100644 index e9de48f7..00000000 --- a/api-reference/0.0/PolylineAlgorithm.Abstraction.yml +++ /dev/null @@ -1,34 +0,0 @@ -### YamlMime:ApiPage -title: Namespace PolylineAlgorithm.Abstraction -body: -- api1: Namespace PolylineAlgorithm.Abstraction - id: PolylineAlgorithm_Abstraction - metadata: - uid: PolylineAlgorithm.Abstraction - commentId: N:PolylineAlgorithm.Abstraction -- h3: Classes -- parameters: - - type: - text: AbstractPolylineDecoder - url: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.html - description: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates. - - type: - text: AbstractPolylineEncoder - url: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.html - description: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings. -- h3: Interfaces -- parameters: - - type: - text: IPolylineDecoder - url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html - description: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates. - - type: - text: IPolylineEncoder - url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html - description: >- - Contract for encoding a sequence of geographic coordinates into an encoded polyline representation. - - Implementations interpret the generic TValue type and produce an encoded - - representation of those coordinates as TPolyline. -languageId: csharp diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml deleted file mode 100644 index 8356b63c..00000000 --- a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml +++ /dev/null @@ -1,195 +0,0 @@ -### YamlMime:ApiPage -title: Class PolylineDecoderExtensions -body: -- api1: Class PolylineDecoderExtensions - id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L16 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions - commentId: T:PolylineAlgorithm.Extensions.PolylineDecoderExtensions -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Extensions - url: PolylineAlgorithm.Extensions.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Provides extension methods for the interface to facilitate decoding encoded polylines. -- code: public static class PolylineDecoderExtensions -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: PolylineDecoderExtensions - url: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.MemberwiseClone() - url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Methods -- api3: Decode(IPolylineDecoder, char[]) - id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_String___0__System_Char___ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L33 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.Char[]) - commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.Char[]) -- markdown: Decodes an encoded polyline represented as a character array into a sequence of geographic coordinates. -- code: public static IEnumerable Decode(this IPolylineDecoder decoder, char[] polyline) -- h4: Parameters -- parameters: - - name: decoder - type: - - text: IPolylineDecoder - url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html - - < - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - - ',' - - " " - - TValue - - '>' - description: The instance used to perform the decoding operation. - - name: polyline - type: - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '[' - - ']' - description: The encoded polyline as a character array to decode. The array is converted to a string internally. -- h4: Returns -- parameters: - - type: - - text: IEnumerable - url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 - - < - - TValue - - '>' - description: An of TValue containing the decoded coordinate pairs. -- h4: Type Parameters -- parameters: - - name: TValue - description: The coordinate type returned by the decoder. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when decoder or polyline is null. -- api3: Decode(IPolylineDecoder, ReadOnlyMemory) - id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_String___0__System_ReadOnlyMemory_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L61 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.ReadOnlyMemory{System.Char}) - commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.ReadOnlyMemory{System.Char}) -- markdown: Decodes an encoded polyline represented as a read-only memory of characters into a sequence of geographic coordinates. -- code: public static IEnumerable Decode(this IPolylineDecoder decoder, ReadOnlyMemory polyline) -- h4: Parameters -- parameters: - - name: decoder - type: - - text: IPolylineDecoder - url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html - - < - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - - ',' - - " " - - TValue - - '>' - description: The instance used to perform the decoding operation. - - name: polyline - type: - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: The encoded polyline as a read-only memory of characters to decode. The memory is converted to a string internally. -- h4: Returns -- parameters: - - type: - - text: IEnumerable - url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 - - < - - TValue - - '>' - description: An of TValue containing the decoded coordinate pairs. -- h4: Type Parameters -- parameters: - - name: TValue - description: The coordinate type returned by the decoder. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when decoder is null. -- api3: Decode(IPolylineDecoder, TValue>, string) - id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_ReadOnlyMemory_System_Char____0__System_String_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L86 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.ReadOnlyMemory{System.Char},``0},System.String) - commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.ReadOnlyMemory{System.Char},``0},System.String) -- markdown: >- - Decodes an encoded polyline string into a sequence of geographic coordinates, - - using a decoder that accepts of . -- code: public static IEnumerable Decode(this IPolylineDecoder, TValue> decoder, string polyline) -- h4: Parameters -- parameters: - - name: decoder - type: - - text: IPolylineDecoder - url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html - - < - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - - ',' - - " " - - TValue - - '>' - description: The instance used to perform the decoding operation. - - name: polyline - type: - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - description: The encoded polyline string to decode. The string is converted to internally. -- h4: Returns -- parameters: - - type: - - text: IEnumerable - url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 - - < - - TValue - - '>' - description: An of TValue containing the decoded coordinate pairs. -- h4: Type Parameters -- parameters: - - name: TValue - description: The coordinate type returned by the decoder. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when decoder or polyline is null. -languageId: csharp -metadata: - description: Provides extension methods for the interface to facilitate decoding encoded polylines. diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml deleted file mode 100644 index e5296518..00000000 --- a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml +++ /dev/null @@ -1,139 +0,0 @@ -### YamlMime:ApiPage -title: Class PolylineEncoderExtensions -body: -- api1: Class PolylineEncoderExtensions - id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L19 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions - commentId: T:PolylineAlgorithm.Extensions.PolylineEncoderExtensions -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Extensions - url: PolylineAlgorithm.Extensions.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines. -- code: public static class PolylineEncoderExtensions -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: PolylineEncoderExtensions - url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.MemberwiseClone() - url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Methods -- api3: Encode(IPolylineEncoder, List) - id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L37 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},System.Collections.Generic.List{``0}) - commentId: M:PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},System.Collections.Generic.List{``0}) -- markdown: Encodes a of TCoordinate instances into an encoded polyline. -- code: >- - [SuppressMessage("Design", "CA1002:Do not expose generic lists", Justification = "We need a list as we do need to marshal it as span.")] - - [SuppressMessage("Design", "MA0016:Prefer using collection abstraction instead of implementation", Justification = "We need a list as we do need to marshal it as span.")] - - public static TPolyline Encode(this IPolylineEncoder encoder, List coordinates) -- h4: Parameters -- parameters: - - name: encoder - type: - - text: IPolylineEncoder - url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html - - < - - TCoordinate - - ',' - - " " - - TPolyline - - '>' - description: The instance used to perform the encoding operation. - - name: coordinates - type: - - text: List - url: https://learn.microsoft.com/dotnet/api/system.collections.generic.list-1 - - < - - TCoordinate - - '>' - description: The list of TCoordinate objects to encode. -- h4: Returns -- parameters: - - type: - - TPolyline - description: A TPolyline instance representing the encoded polyline for the provided coordinates. -- h4: Type Parameters -- parameters: - - name: TCoordinate - description: The type that represents a geographic coordinate to encode. - - name: TPolyline - description: The type that represents the encoded polyline output. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when encoder or coordinates is null. -- api3: Encode(IPolylineEncoder, TCoordinate[]) - id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L73 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},``0[]) - commentId: M:PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},``0[]) -- markdown: Encodes an array of TCoordinate instances into an encoded polyline. -- code: public static TPolyline Encode(this IPolylineEncoder encoder, TCoordinate[] coordinates) -- h4: Parameters -- parameters: - - name: encoder - type: - - text: IPolylineEncoder - url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html - - < - - TCoordinate - - ',' - - " " - - TPolyline - - '>' - description: The instance used to perform the encoding operation. - - name: coordinates - type: - - TCoordinate - - '[' - - ']' - description: The array of TCoordinate objects to encode. -- h4: Returns -- parameters: - - type: - - TPolyline - description: A TPolyline instance representing the encoded polyline for the provided coordinates. -- h4: Type Parameters -- parameters: - - name: TCoordinate - description: The type that represents a geographic coordinate to encode. - - name: TPolyline - description: The type that represents the encoded polyline output. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when encoder or coordinates is null. -languageId: csharp -metadata: - description: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines. diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.yml deleted file mode 100644 index c39da0ca..00000000 --- a/api-reference/0.0/PolylineAlgorithm.Extensions.yml +++ /dev/null @@ -1,19 +0,0 @@ -### YamlMime:ApiPage -title: Namespace PolylineAlgorithm.Extensions -body: -- api1: Namespace PolylineAlgorithm.Extensions - id: PolylineAlgorithm_Extensions - metadata: - uid: PolylineAlgorithm.Extensions - commentId: N:PolylineAlgorithm.Extensions -- h3: Classes -- parameters: - - type: - text: PolylineDecoderExtensions - url: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.html - description: Provides extension methods for the interface to facilitate decoding encoded polylines. - - type: - text: PolylineEncoderExtensions - url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html - description: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines. -languageId: csharp diff --git a/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml b/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml deleted file mode 100644 index 2c4e3cc1..00000000 --- a/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml +++ /dev/null @@ -1,102 +0,0 @@ -### YamlMime:ApiPage -title: Class InvalidPolylineException -body: -- api1: Class InvalidPolylineException - id: PolylineAlgorithm_InvalidPolylineException - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/InvalidPolylineException.cs#L17 - metadata: - uid: PolylineAlgorithm.InvalidPolylineException - commentId: T:PolylineAlgorithm.InvalidPolylineException -- facts: - - name: Namespace - value: - text: PolylineAlgorithm - url: PolylineAlgorithm.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Exception thrown when a polyline is determined to be malformed or invalid during processing. -- code: 'public sealed class InvalidPolylineException : Exception, ISerializable' -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: Exception - url: https://learn.microsoft.com/dotnet/api/system.exception - - text: InvalidPolylineException - url: PolylineAlgorithm.InvalidPolylineException.html -- h4: Implements -- list: - - text: ISerializable - url: https://learn.microsoft.com/dotnet/api/system.runtime.serialization.iserializable -- h4: Inherited Members -- list: - - text: Exception.GetBaseException() - url: https://learn.microsoft.com/dotnet/api/system.exception.getbaseexception - - text: Exception.GetObjectData(SerializationInfo, StreamingContext) - url: https://learn.microsoft.com/dotnet/api/system.exception.getobjectdata - - text: Exception.GetType() - url: https://learn.microsoft.com/dotnet/api/system.exception.gettype - - text: Exception.ToString() - url: https://learn.microsoft.com/dotnet/api/system.exception.tostring - - text: Exception.Data - url: https://learn.microsoft.com/dotnet/api/system.exception.data - - text: Exception.HelpLink - url: https://learn.microsoft.com/dotnet/api/system.exception.helplink - - text: Exception.HResult - url: https://learn.microsoft.com/dotnet/api/system.exception.hresult - - text: Exception.InnerException - url: https://learn.microsoft.com/dotnet/api/system.exception.innerexception - - text: Exception.Message - url: https://learn.microsoft.com/dotnet/api/system.exception.message - - text: Exception.Source - url: https://learn.microsoft.com/dotnet/api/system.exception.source - - text: Exception.StackTrace - url: https://learn.microsoft.com/dotnet/api/system.exception.stacktrace - - text: Exception.TargetSite - url: https://learn.microsoft.com/dotnet/api/system.exception.targetsite - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Remarks -- markdown: This exception is used internally to indicate that a polyline string does not conform to the expected format or contains errors. -- h2: Constructors -- api3: InvalidPolylineException() - id: PolylineAlgorithm_InvalidPolylineException__ctor - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/InvalidPolylineException.cs#L22 - metadata: - uid: PolylineAlgorithm.InvalidPolylineException.#ctor - commentId: M:PolylineAlgorithm.InvalidPolylineException.#ctor -- markdown: Initializes a new instance of the class. -- code: public InvalidPolylineException() -- api3: InvalidPolylineException(string, Exception) - id: PolylineAlgorithm_InvalidPolylineException__ctor_System_String_System_Exception_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/InvalidPolylineException.cs#L43 - metadata: - uid: PolylineAlgorithm.InvalidPolylineException.#ctor(System.String,System.Exception) - commentId: M:PolylineAlgorithm.InvalidPolylineException.#ctor(System.String,System.Exception) -- markdown: Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. -- code: public InvalidPolylineException(string message, Exception innerException) -- h4: Parameters -- parameters: - - name: message - type: - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - description: The error message that explains the reason for the exception. - - name: innerException - type: - - text: Exception - url: https://learn.microsoft.com/dotnet/api/system.exception - description: The exception that is the cause of the current exception, or a null reference if no inner exception is specified. -languageId: csharp -metadata: - description: Exception thrown when a polyline is determined to be malformed or invalid during processing. diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml deleted file mode 100644 index 1add8147..00000000 --- a/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml +++ /dev/null @@ -1,529 +0,0 @@ -### YamlMime:ApiPage -title: Class PolylineEncoding -body: -- api1: Class PolylineEncoding - id: PolylineAlgorithm_PolylineEncoding - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L23 - metadata: - uid: PolylineAlgorithm.PolylineEncoding - commentId: T:PolylineAlgorithm.PolylineEncoding -- facts: - - name: Namespace - value: - text: PolylineAlgorithm - url: PolylineAlgorithm.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: >- - Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing - - geographic coordinate values. -- code: public static class PolylineEncoding -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: PolylineEncoding - url: PolylineAlgorithm.PolylineEncoding.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.MemberwiseClone() - url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Remarks -- markdown: >- - The class includes functionality for working with encoded polyline - data, such as reading and writing encoded values, as well as methods for normalizing and de-normalizing geographic - coordinates. It also provides validation utilities to ensure values conform to expected ranges for latitude and - longitude. -- h2: Methods -- api3: Denormalize(int, uint) - id: PolylineAlgorithm_PolylineEncoding_Denormalize_System_Int32_System_UInt32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L122 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32) - commentId: M:PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32) -- markdown: Converts a normalized integer coordinate value back to its floating-point representation based on the specified precision. -- code: public static double Denormalize(int value, uint precision = 5) -- h4: Parameters -- parameters: - - name: value - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: The integer value to denormalize. Typically produced by the method. - - name: precision - type: - - text: uint - url: https://learn.microsoft.com/dotnet/api/system.uint32 - description: The number of decimal places used during normalization. Default is 5, matching standard polyline encoding precision. - optional: true -- h4: Returns -- parameters: - - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The denormalized floating-point coordinate value. -- h4: Remarks -- markdown: >- -

- - This method reverses the normalization performed by . It takes an integer value and converts it - - to a double by dividing it by 10 raised to the power of the specified precision. If precision is 0, - - the value is returned as a double without division. - -

- -

- - The calculation is performed inside a checked block to ensure that any arithmetic overflow is detected - - and an is thrown. - -

- -

- - For example, with a precision of 5: - - -

  • A value of 3778903 becomes 37.78903
  • A value of -12241230 becomes -122.4123
- -

- -

- - If the input value is 0, the method returns 0.0 immediately. - -

-- h4: Exceptions -- parameters: - - type: - - text: OverflowException - url: https://learn.microsoft.com/dotnet/api/system.overflowexception - description: Thrown if the arithmetic operation overflows during conversion. -- api3: GetRequiredBufferSize(int) - id: PolylineAlgorithm_PolylineEncoding_GetRequiredBufferSize_System_Int32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L298 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32) - commentId: M:PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32) -- markdown: Calculates the number of characters required to encode a delta value in polyline format. -- code: public static int GetRequiredBufferSize(int delta) -- h4: Parameters -- parameters: - - name: delta - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: >- - The integer delta value to calculate the encoded size for. This value typically represents the difference between - - consecutive coordinate values in polyline encoding. -- h4: Returns -- parameters: - - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: The number of characters required to encode the specified delta value. The minimum return value is 1. -- h4: Remarks -- markdown: >- -

- - This method determines how many characters will be needed to represent an integer delta value when encoded - - using the polyline encoding algorithm. It performs the same zigzag encoding transformation as - - but only calculates the required buffer size without actually writing any data. - -

- -

- - The calculation process: - - -

  1. Applies zigzag encoding: left-shifts the value by 1 bit, then inverts all bits if the original value was negative
  2. Counts how many 5-bit chunks are needed to represent the encoded value
  3. Each chunk requires one character, with a minimum of 1 character for any value
- -

- -

- - This method is useful for pre-allocating buffers of the correct size before encoding polyline data, helping to avoid - - buffer overflow checks during the actual encoding process. - -

- -

- - The method uses a long internally to prevent overflow during the left-shift operation on large negative values. - -

-- h4: See Also -- list: - - - text: PolylineEncoding - url: PolylineAlgorithm.PolylineEncoding.html - - . - - text: TryWriteValue - url: PolylineAlgorithm.PolylineEncoding.html#PolylineAlgorithm_PolylineEncoding_TryWriteValue_System_Int32_System_Span_System_Char__System_Int32__ - - ( - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - - ',' - - " " - - text: Span - url: https://learn.microsoft.com/dotnet/api/system.span-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - - ',' - - " " - - ref - - " " - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - - ) -- api3: Normalize(double, uint) - id: PolylineAlgorithm_PolylineEncoding_Normalize_System_Double_System_UInt32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L61 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32) - commentId: M:PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32) -- markdown: Normalizes a geographic coordinate value to an integer representation based on the specified precision. -- code: public static int Normalize(double value, uint precision = 5) -- h4: Parameters -- parameters: - - name: value - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The numeric value to normalize. Must be a finite number (not NaN or infinity). - - name: precision - type: - - text: uint - url: https://learn.microsoft.com/dotnet/api/system.uint32 - description: >- - The number of decimal places of precision to preserve in the normalized value. - - The value is multiplied by 10^precision before rounding. - - Default is 5, which is standard for polyline encoding. - optional: true -- h4: Returns -- parameters: - - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: An integer representing the normalized value. Returns 0 if the input value is 0.0. -- h4: Remarks -- markdown: >- -

- - This method converts a floating-point coordinate value into a normalized integer by multiplying it by 10 raised - - to the power of the specified precision, then truncating the result to an integer. - -

- -

- - For example, with the default precision of 5: - - -

  • A value of 37.78903 becomes 3778903
  • A value of -122.4123 becomes -12241230
- -

- -

- - The method validates that the input value is finite (not NaN or infinity) before performing normalization. - - If the precision is 0, the value is rounded without multiplication. - -

-- h4: Exceptions -- parameters: - - type: - - text: ArgumentOutOfRangeException - url: https://learn.microsoft.com/dotnet/api/system.argumentoutofrangeexception - description: Thrown when value is not a finite number (NaN or infinity). - - type: - - text: OverflowException - url: https://learn.microsoft.com/dotnet/api/system.overflowexception - description: Thrown when the normalized result exceeds the range of a 32-bit signed integer during the conversion from double to int. -- api3: TryReadValue(ref int, ReadOnlyMemory, ref int) - id: PolylineAlgorithm_PolylineEncoding_TryReadValue_System_Int32__System_ReadOnlyMemory_System_Char__System_Int32__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L169 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@) - commentId: M:PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@) -- markdown: Attempts to read an encoded integer value from a polyline buffer, updating the specified delta and position. -- code: public static bool TryReadValue(ref int delta, ReadOnlyMemory buffer, ref int position) -- h4: Parameters -- parameters: - - name: delta - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: Reference to the integer accumulator that will be updated with the decoded value. - - name: buffer - type: - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: The buffer containing polyline-encoded characters. - - name: position - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: Reference to the current position in the buffer. This value is updated as characters are read. -- h4: Returns -- parameters: - - type: - - text: bool - url: https://learn.microsoft.com/dotnet/api/system.boolean - description: true if a value was successfully read and decoded; false if the buffer ended before a complete value was read. -- h4: Remarks -- markdown: >- -

- - This method decodes a value from a polyline-encoded character buffer, starting at the given position. It reads - - characters sequentially, applying the polyline decoding algorithm, and updates the delta with - - the decoded value. The position is advanced as characters are processed. - -

- -

- - The decoding process continues until a character with a value less than the algorithm's space constant is encountered, - - which signals the end of the encoded value. If the buffer is exhausted before a complete value is read, the method returns false. - -

- -

- - The decoded value is added to delta using zigzag decoding, which handles both positive and negative values. - -

-- api3: TryWriteValue(int, Span, ref int) - id: PolylineAlgorithm_PolylineEncoding_TryWriteValue_System_Int32_System_Span_System_Char__System_Int32__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L237 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@) - commentId: M:PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@) -- markdown: Attempts to write an encoded integer value to a polyline buffer, updating the specified position. -- code: public static bool TryWriteValue(int delta, Span buffer, ref int position) -- h4: Parameters -- parameters: - - name: delta - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: >- - The integer value to encode and write to the buffer. This value typically represents the difference between consecutive - - coordinate values in polyline encoding. - - name: buffer - type: - - text: Span - url: https://learn.microsoft.com/dotnet/api/system.span-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: The destination buffer where the encoded characters will be written. Must have sufficient capacity to hold the encoded value. - - name: position - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: >- - Reference to the current position in the buffer. This value is updated as characters are written to reflect the new position - - after encoding is complete. -- h4: Returns -- parameters: - - type: - - text: bool - url: https://learn.microsoft.com/dotnet/api/system.boolean - description: >- - true if the value was successfully encoded and written to the buffer; false if the buffer - - does not have sufficient remaining capacity to hold the encoded value. -- h4: Remarks -- markdown: >- -

- - This method encodes an integer delta value into a polyline-encoded format and writes it to the provided character buffer, - - starting at the given position. It applies zigzag encoding followed by the polyline encoding algorithm to represent - - both positive and negative values efficiently. - -

- -

- - The encoding process first converts the value using zigzag encoding (left shift by 1, with bitwise inversion for negative values), - - then writes it as a sequence of characters. Each character encodes 5 bits of data, with continuation bits indicating whether - - more characters follow. The position is advanced as characters are written. - -

- -

- - Before writing, the method validates that sufficient space is available in the buffer by calling . - - If the buffer does not have enough remaining capacity, the method returns false without modifying the buffer or position. - -

- -

- - This method is the inverse of and can be used to encode coordinate deltas for polyline serialization. - -

-- api3: ValidateBlockLength(ReadOnlySpan) - id: PolylineAlgorithm_PolylineEncoding_ValidateBlockLength_System_ReadOnlySpan_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L438 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char}) - commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char}) -- markdown: Validates the block structure of a polyline segment, ensuring each encoded value does not exceed 7 characters and the polyline ends correctly. -- code: public static void ValidateBlockLength(ReadOnlySpan polyline) -- h4: Parameters -- parameters: - - name: polyline - type: - - text: ReadOnlySpan - url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: A span representing the polyline segment to validate. -- h4: Remarks -- markdown: >- -

- - Iterates through the polyline, counting the length of each block (a sequence of characters representing an encoded value). - - Throws an if any block exceeds 7 characters or if the polyline does not end with a valid block terminator. - -

-- h4: Exceptions -- parameters: - - type: - - text: ArgumentException - url: https://learn.microsoft.com/dotnet/api/system.argumentexception - description: Thrown when a block exceeds 7 characters or the polyline does not end with a valid block terminator. -- api3: ValidateCharRange(ReadOnlySpan) - id: PolylineAlgorithm_PolylineEncoding_ValidateCharRange_System_ReadOnlySpan_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L392 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char}) - commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char}) -- markdown: Validates that all characters in the polyline segment are within the allowed ASCII range for polyline encoding. -- code: public static void ValidateCharRange(ReadOnlySpan polyline) -- h4: Parameters -- parameters: - - name: polyline - type: - - text: ReadOnlySpan - url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: A span representing the polyline segment to validate. -- h4: Remarks -- markdown: >- -

- - Uses SIMD vectorization for efficient validation of large spans. Falls back to scalar checks for any block where an invalid character is detected. - -

- -

- - The valid range is from '?' (63) to '_' (95), inclusive. If an invalid character is found, an is thrown. - -

-- h4: Exceptions -- parameters: - - type: - - text: ArgumentException - url: https://learn.microsoft.com/dotnet/api/system.argumentexception - description: Thrown when an invalid character is found in the polyline segment. -- api3: ValidateFormat(ReadOnlySpan) - id: PolylineAlgorithm_PolylineEncoding_ValidateFormat_System_ReadOnlySpan_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L370 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char}) - commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char}) -- markdown: Validates the format of a polyline segment, ensuring all characters are valid and block structure is correct. -- code: public static void ValidateFormat(ReadOnlySpan polyline) -- h4: Parameters -- parameters: - - name: polyline - type: - - text: ReadOnlySpan - url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: A span representing the polyline segment to validate. -- h4: Remarks -- markdown: >- -

- - This method performs two levels of validation on the provided polyline segment: - -

- -
  1. - Character Range Validation: Checks that every character in the polyline is within the valid ASCII range for polyline encoding ('?' [63] to '_' [95], inclusive). - Uses SIMD acceleration for efficient validation of large segments. -
  2. - Block Structure Validation: Ensures that each encoded value (block) does not exceed 7 characters and that the polyline ends with a valid block terminator. -
-

- - If an invalid character or block structure is detected, an is thrown with details about the error. - -

-- h4: Exceptions -- parameters: - - type: - - text: ArgumentException - url: https://learn.microsoft.com/dotnet/api/system.argumentexception - description: Thrown when an invalid character is found or the block structure is invalid. -languageId: csharp -metadata: - description: >- - Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing - - geographic coordinate values. diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml deleted file mode 100644 index 1947eac1..00000000 --- a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml +++ /dev/null @@ -1,127 +0,0 @@ -### YamlMime:ApiPage -title: Class PolylineEncodingOptions -body: -- api1: Class PolylineEncodingOptions - id: PolylineAlgorithm_PolylineEncodingOptions - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L29 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptions - commentId: T:PolylineAlgorithm.PolylineEncodingOptions -- facts: - - name: Namespace - value: - text: PolylineAlgorithm - url: PolylineAlgorithm.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Provides configuration options for polyline encoding operations. -- code: public sealed class PolylineEncodingOptions -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Remarks -- markdown: >- -

- - This class allows you to configure various aspects of polyline encoding, including: - -

- -
  • The level for coordinate encoding
  • The for memory allocation strategy
  • The for diagnostic logging
- -

- - All properties have internal setters and should be configured through a builder or factory pattern. - -

-- h2: Properties -- api3: LoggerFactory - id: PolylineAlgorithm_PolylineEncodingOptions_LoggerFactory - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L41 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory - commentId: P:PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory -- markdown: Gets the logger factory used for diagnostic logging during encoding operations. -- code: public ILoggerFactory LoggerFactory { get; } -- h4: Property Value -- parameters: - - type: - - text: ILoggerFactory - url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggerfactory -- h4: Remarks -- markdown: >- - The default logger factory is , which does not log any messages. - - To enable logging, provide a custom implementation. -- api3: Precision - id: PolylineAlgorithm_PolylineEncodingOptions_Precision - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L60 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptions.Precision - commentId: P:PolylineAlgorithm.PolylineEncodingOptions.Precision -- markdown: Gets the precision level used for encoding coordinate values. -- code: public uint Precision { get; } -- h4: Property Value -- parameters: - - type: - - text: uint - url: https://learn.microsoft.com/dotnet/api/system.uint32 -- h4: Remarks -- markdown: >- -

- - The precision determines the number of decimal places to which each coordinate value (latitude or longitude) - - is multiplied and truncated (not rounded) before encoding. For example, a precision of 5 means each coordinate is multiplied by 10^5 - - and truncated to an integer before encoding. - -

- -

- - This setting does not directly correspond to a physical distance or accuracy in meters, but rather controls - - the granularity of the encoded values. - -

-- api3: StackAllocLimit - id: PolylineAlgorithm_PolylineEncodingOptions_StackAllocLimit - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L73 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit - commentId: P:PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit -- markdown: Gets the maximum buffer size (in characters) that can be allocated on the stack for encoding operations. -- code: public int StackAllocLimit { get; } -- h4: Property Value -- parameters: - - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 -- h4: Remarks -- markdown: >- - When the required buffer size for encoding exceeds this limit, memory will be allocated on the heap instead of the stack. - - This setting specifically applies to stack allocation of character arrays (stackalloc char[]) used during polyline encoding, - - balancing performance and stack safety. -languageId: csharp -metadata: - description: Provides configuration options for polyline encoding operations. diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml deleted file mode 100644 index 66ae63b8..00000000 --- a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml +++ /dev/null @@ -1,141 +0,0 @@ -### YamlMime:ApiPage -title: Class PolylineEncodingOptionsBuilder -body: -- api1: Class PolylineEncodingOptionsBuilder - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L15 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder - commentId: T:PolylineAlgorithm.PolylineEncodingOptionsBuilder -- facts: - - name: Namespace - value: - text: PolylineAlgorithm - url: PolylineAlgorithm.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Provides a builder for configuring options for polyline encoding operations. -- code: public sealed class PolylineEncodingOptionsBuilder -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Methods -- api3: Build() - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Build - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L38 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build - commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build -- markdown: Builds a new instance using the configured options. -- code: public PolylineEncodingOptions Build() -- h4: Returns -- parameters: - - type: - - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html - description: A configured instance. -- api3: Create() - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Create - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L28 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create - commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create -- markdown: Creates a new instance for the specified coordinate type. -- code: public static PolylineEncodingOptionsBuilder Create() -- h4: Returns -- parameters: - - type: - - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html - description: An instance for configuring polyline encoding options. -- api3: WithLoggerFactory(ILoggerFactory) - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithLoggerFactory_Microsoft_Extensions_Logging_ILoggerFactory_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L97 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory) - commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory) -- markdown: Configures the to be used for logging during polyline encoding operations. -- code: public PolylineEncodingOptionsBuilder WithLoggerFactory(ILoggerFactory loggerFactory) -- h4: Parameters -- parameters: - - name: loggerFactory - type: - - text: ILoggerFactory - url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggerfactory - description: The instance to use for logging. If null, a will be used instead. -- h4: Returns -- parameters: - - type: - - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html - description: The current instance for method chaining. -- api3: WithPrecision(uint) - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithPrecision_System_UInt32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L82 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32) - commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32) -- markdown: Sets the coordinate encoding precision. -- code: public PolylineEncodingOptionsBuilder WithPrecision(uint precision) -- h4: Parameters -- parameters: - - name: precision - type: - - text: uint - url: https://learn.microsoft.com/dotnet/api/system.uint32 - description: The number of decimal places to use for encoding coordinate values. Default is 5. -- h4: Returns -- parameters: - - type: - - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html - description: The current instance for method chaining. -- api3: WithStackAllocLimit(int) - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithStackAllocLimit_System_Int32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L61 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32) - commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32) -- markdown: Configures the buffer size used for stack allocation during polyline encoding operations. -- code: public PolylineEncodingOptionsBuilder WithStackAllocLimit(int stackAllocLimit) -- h4: Parameters -- parameters: - - name: stackAllocLimit - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: The maximum buffer size to use for stack allocation. Must be greater than or equal to 1. -- h4: Returns -- parameters: - - type: - - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html - description: The current instance for method chaining. -- h4: Remarks -- markdown: This method allows customization of the internal buffer size for encoding, which can impact performance and memory usage. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentOutOfRangeException - url: https://learn.microsoft.com/dotnet/api/system.argumentoutofrangeexception - description: Thrown if stackAllocLimit is less than 1. -languageId: csharp -metadata: - description: Provides a builder for configuring options for polyline encoding operations. diff --git a/api-reference/0.0/PolylineAlgorithm.yml b/api-reference/0.0/PolylineAlgorithm.yml deleted file mode 100644 index b60dc3c0..00000000 --- a/api-reference/0.0/PolylineAlgorithm.yml +++ /dev/null @@ -1,38 +0,0 @@ -### YamlMime:ApiPage -title: Namespace PolylineAlgorithm -body: -- api1: Namespace PolylineAlgorithm - id: PolylineAlgorithm - metadata: - uid: PolylineAlgorithm - commentId: N:PolylineAlgorithm -- h3: Namespaces -- parameters: - - type: - text: PolylineAlgorithm.Abstraction - url: PolylineAlgorithm.Abstraction.html - - type: - text: PolylineAlgorithm.Extensions - url: PolylineAlgorithm.Extensions.html -- h3: Classes -- parameters: - - type: - text: InvalidPolylineException - url: PolylineAlgorithm.InvalidPolylineException.html - description: Exception thrown when a polyline is determined to be malformed or invalid during processing. - - type: - text: PolylineEncoding - url: PolylineAlgorithm.PolylineEncoding.html - description: >- - Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing - - geographic coordinate values. - - type: - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html - description: Provides configuration options for polyline encoding operations. - - type: - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html - description: Provides a builder for configuring options for polyline encoding operations. -languageId: csharp diff --git a/api-reference/0.0/toc.yml b/api-reference/0.0/toc.yml deleted file mode 100644 index d1ffc58a..00000000 --- a/api-reference/0.0/toc.yml +++ /dev/null @@ -1,34 +0,0 @@ -### YamlMime:TableOfContent -- name: PolylineAlgorithm - href: PolylineAlgorithm.yml - items: - - name: Classes - - name: InvalidPolylineException - href: PolylineAlgorithm.InvalidPolylineException.yml - - name: PolylineEncoding - href: PolylineAlgorithm.PolylineEncoding.yml - - name: PolylineEncodingOptions - href: PolylineAlgorithm.PolylineEncodingOptions.yml - - name: PolylineEncodingOptionsBuilder - href: PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml -- name: PolylineAlgorithm.Abstraction - href: PolylineAlgorithm.Abstraction.yml - items: - - name: Classes - - name: AbstractPolylineDecoder - href: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml - - name: AbstractPolylineEncoder - href: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml - - name: Interfaces - - name: IPolylineDecoder - href: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml - - name: IPolylineEncoder - href: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml -- name: PolylineAlgorithm.Extensions - href: PolylineAlgorithm.Extensions.yml - items: - - name: Classes - - name: PolylineDecoderExtensions - href: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml - - name: PolylineEncoderExtensions - href: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml diff --git a/api-reference/guide/benchmarks.md b/api-reference/guide/benchmarks.md deleted file mode 100644 index 47b453f9..00000000 --- a/api-reference/guide/benchmarks.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Benchmarks ---- -# Benchmarks - -Performance benchmarks for **PolylineAlgorithm for .NET** measured using [BenchmarkDotNet](https://benchmarkdotnet.org/). - -> [!NOTE] -> Benchmarks are generated automatically during the release process. Results may vary depending on hardware and runtime version. - -{benchmarks_section} diff --git a/api-reference/guide/toc.yml b/api-reference/guide/toc.yml index e9d9e716..015a9943 100644 --- a/api-reference/guide/toc.yml +++ b/api-reference/guide/toc.yml @@ -8,5 +8,3 @@ href: sample.md - name: FAQ href: faq.md -- name: Benchmarks - href: benchmarks.md diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs index b6b54081..f28c8141 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs @@ -93,10 +93,8 @@ public void PolylineDecoder_Decode_Memory() { } private sealed class StringPolylineDecoder : AbstractPolylineDecoder { - protected override int ValuesPerItem => 2; - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); + protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) { + return (latitude, longitude); } protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { @@ -105,10 +103,8 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { } private sealed class CharArrayPolylineDecoder : AbstractPolylineDecoder { - protected override int ValuesPerItem => 2; - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); + protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) { + return (latitude, longitude); } protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) { @@ -117,10 +113,8 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) { } private sealed class MemoryCharPolylineDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { - protected override int ValuesPerItem => 2; - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); + protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) { + return (latitude, longitude); } protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) { diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs index c4b9d5a8..e0b97c5c 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs @@ -85,11 +85,8 @@ public void PolylineEncoder_Encode_List() { } private sealed class StringPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - protected override int ValuesPerItem => 2; protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override void GetValues((double Latitude, double Longitude) item, Span destination) { - destination[0] = item.Latitude; - destination[1] = item.Longitude; - } + protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude; + protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude; } } diff --git a/docs/local-development.md b/docs/local-development.md index ab2da8ab..48fa5f76 100644 --- a/docs/local-development.md +++ b/docs/local-development.md @@ -72,24 +72,3 @@ The CI `format` job also runs `dotnet format` automatically on every push to non ## Editor Configuration Code style rules are stored in `.editorconfig` at the repository root. Any compliant IDE (Visual Studio, VS Code with C# Dev Kit, Rider) will pick these up automatically. - -## Required Repository Secrets and Variables - -The CI/CD workflows rely on the following GitHub repository secrets and variables. - -### Secrets - -| Name | Description | -|------|-------------| -| `NUGET_PACKAGE_FEED_API_KEY` | API key for the Azure Artifacts NuGet feed | - -### Variables - -| Name | Description | -|------|-------------| -| `NUGET_PACKAGE_FEED_URL` | NuGet feed URL | -| `BENCHMARKDOTNET_RUN_OVERRIDE` | Set to `true` to force benchmarks to run on non-release PRs | -| `BENCHMARKDOTNET_RUNTIMES` | Runtimes to benchmark (e.g. `net8.0 net10.0`) | -| `BENCHMARKDOTNET_FILTER` | Benchmark filter pattern (e.g. `*`) | -| `DEFAULT_BUILD_FRAMEWORK` | Default target framework for builds (e.g. `net10.0`) | -| `SRC_DEFAULT_GLOB_PATTERN` | Glob pattern for source project files (e.g. `**/PolylineAlgorithm.csproj`) | diff --git a/docs/workflows.md b/docs/workflows.md index 8782270f..4c864783 100644 --- a/docs/workflows.md +++ b/docs/workflows.md @@ -87,7 +87,6 @@ Version bumping runs independently via `bump-version.yml` (manual trigger). | `pack` | `versioning`, `build` | Packages binaries | | `publish-package` | `pack` | Publishes to NuGet.org (Production environment) | | `create-release` | `versioning`, `publish-package` | Creates a git tag + GitHub release with auto-generated notes | -| `update-changelog` | `release` | Fetches release notes and prepends a new entry to `CHANGELOG.md` — stable releases only | | `generate-docs` | `versioning` | Builds DocFX site | | `publish-docs` | `generate-docs` | Deploys to GitHub Pages | diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs index dd05ca88..82899203 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs @@ -12,23 +12,16 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; /// /// Polyline decoder using NetTopologySuite. /// -internal sealed class NetTopologyPolylineDecoder : AbstractPolylineDecoder { +public sealed class NetTopologyPolylineDecoder : AbstractPolylineDecoder { /// - /// Gets the number of encoded values per item: latitude (index 0) and longitude (index 1). + /// Creates a NetTopologySuite point from latitude and longitude. /// - protected override int ValuesPerItem => 2; - - /// - /// Creates a NetTopologySuite point from the decoded values. - /// - /// - /// A memory region containing two values: index 0 is latitude, index 1 is longitude. - /// + /// Latitude value. + /// Longitude value. /// Point instance. - protected override Point CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; + protected override Point CreateCoordinate(double latitude, double longitude) { // NetTopologySuite Point: x = longitude, y = latitude - return new Point(span[1], span[0]); + return new Point(longitude, latitude); } /// diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs index 5a7b5529..649547bd 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs @@ -7,17 +7,11 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; using global::NetTopologySuite.Geometries; using PolylineAlgorithm.Abstraction; -using System; /// /// Polyline encoder using NetTopologySuite's Point type. /// -internal sealed class NetTopologyPolylineEncoder : AbstractPolylineEncoder { - /// - /// Gets the number of values per item: latitude (index 0) and longitude (index 1). - /// - protected override int ValuesPerItem => 2; - +public sealed class NetTopologyPolylineEncoder : AbstractPolylineEncoder { /// /// Creates encoded polyline string from memory. /// @@ -32,15 +26,30 @@ protected override string CreatePolyline(ReadOnlyMemory polyline) { } /// - /// Fills destination with latitude (index 0) and longitude (index 1) from the point. + /// Gets latitude from point. /// - /// Point instance. - /// Span of length 2 to fill. - protected override void GetValues(Point item, Span destination) { - ArgumentNullException.ThrowIfNull(item); - - // NetTopologySuite Point: Y = latitude, X = longitude - destination[0] = item.Y; - destination[1] = item.X; + /// Point instance. + /// Latitude value. + protected override double GetLatitude(Point current) { + if (current is null) { + throw new ArgumentNullException(nameof(current)); + } + + // NetTopologySuite Point: Y = latitude + return current.Y; + } + + /// + /// Gets longitude from point. + /// + /// Point instance. + /// Longitude value. + protected override double GetLongitude(Point current) { + if (current is null) { + throw new ArgumentNullException(nameof(current)); + } + + // NetTopologySuite Point: X = longitude + return current.X; } } \ No newline at end of file diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/PolylineAlgorithm.NetTopologySuite.Sample.csproj b/samples/PolylineAlgorithm.NetTopologySuite.Sample/PolylineAlgorithm.NetTopologySuite.Sample.csproj index fef82026..57d5f7c1 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/PolylineAlgorithm.NetTopologySuite.Sample.csproj +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/PolylineAlgorithm.NetTopologySuite.Sample.csproj @@ -1,8 +1,7 @@  - Exe - net10.0 + netstandard2.1 diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/Program.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/Program.cs deleted file mode 100644 index ca9a8a6f..00000000 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/Program.cs +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright © Pete Sramek. All rights reserved. -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -using NetTopologySuite.Geometries; -using PolylineAlgorithm.NetTopologySuite.Sample; - -public class Program { - public static void Main(string[] args) { - // Sample route: Seattle → Bellevue → Redmond - var points = new Point[] - { - new(x: -122.3503, y: 47.6219), // Seattle (x = longitude, y = latitude) - new(x: -122.2015, y: 47.6101), // Bellevue - new(x: -122.1215, y: 47.6740), // Redmond - }; - - var encoder = new NetTopologyPolylineEncoder(); - var decoder = new NetTopologyPolylineDecoder(); - - // Encode - string encoded = encoder.Encode(points); - - Console.WriteLine("=== NetTopologySuite Polyline Sample ==="); - Console.WriteLine(); - Console.WriteLine("Input points (longitude, latitude):"); - - foreach (Point p in points) { - Console.WriteLine($" ({p.X}, {p.Y})"); - } - - Console.WriteLine(); - Console.WriteLine($"Encoded polyline: {encoded}"); - Console.WriteLine(); - - // Decode - IEnumerable decoded = decoder.Decode(encoded); - - Console.WriteLine("Decoded points (longitude, latitude):"); - - foreach (Point p in decoded) { - Console.WriteLine($" ({p.X}, {p.Y})"); - } - } -} \ No newline at end of file diff --git a/samples/PolylineAlgorithm.SensorData.Sample/PolylineAlgorithm.SensorData.Sample.csproj b/samples/PolylineAlgorithm.SensorData.Sample/PolylineAlgorithm.SensorData.Sample.csproj deleted file mode 100644 index 3e1bcb63..00000000 --- a/samples/PolylineAlgorithm.SensorData.Sample/PolylineAlgorithm.SensorData.Sample.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - Exe - net10.0 - - - - false - - - - - - - diff --git a/samples/PolylineAlgorithm.SensorData.Sample/Program.cs b/samples/PolylineAlgorithm.SensorData.Sample/Program.cs deleted file mode 100644 index e14977f9..00000000 --- a/samples/PolylineAlgorithm.SensorData.Sample/Program.cs +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright © Pete Sramek. All rights reserved. -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -using PolylineAlgorithm.SensorData.Sample; - -public static class Program { - public static void Main(string[] args) { - // Sample temperature readings from a sensor over six seconds - var readings = new SensorReading[] - { - new(DateTimeOffset.UtcNow, 23.5), - new(DateTimeOffset.UtcNow.AddSeconds(1), 23.7), - new(DateTimeOffset.UtcNow.AddSeconds(2), 24.1), - new(DateTimeOffset.UtcNow.AddSeconds(3), 25.0), - new(DateTimeOffset.UtcNow.AddSeconds(4), 24.8), - new(DateTimeOffset.UtcNow.AddSeconds(5), 24.8), - new(DateTimeOffset.UtcNow.AddSeconds(6), 22.3), - }; - - var encoder = new SensorDataEncoder(); - var decoder = new SensorDataDecoder(); - - // Encode - string encoded = encoder.Encode(readings); - - Console.WriteLine("=== Sensor Data Polyline Sample ==="); - Console.WriteLine(); - Console.WriteLine("Input readings:"); - - foreach (SensorReading r in readings) { - Console.WriteLine($" [{r.Timestamp:HH:mm:ss}] {r.Temperature:F1} °C"); - } - - Console.WriteLine(); - Console.WriteLine($"Encoded polyline: {encoded}"); - Console.WriteLine(); - - // Decode (timestamps and temperatures are both recovered) - IEnumerable decoded = decoder.Decode(encoded); - - Console.WriteLine("Decoded readings:"); - - foreach (SensorReading r in decoded) { - Console.WriteLine($" [{r.Timestamp:HH:mm:ss}] {r.Temperature:F1} °C"); - } - } -} \ No newline at end of file diff --git a/samples/PolylineAlgorithm.SensorData.Sample/Properties/CodeCoverage.cs b/samples/PolylineAlgorithm.SensorData.Sample/Properties/CodeCoverage.cs deleted file mode 100644 index e3468ef6..00000000 --- a/samples/PolylineAlgorithm.SensorData.Sample/Properties/CodeCoverage.cs +++ /dev/null @@ -1,8 +0,0 @@ -// -// Copyright © Pete Sramek. All rights reserved. -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -using System.Diagnostics.CodeAnalysis; - -[assembly: ExcludeFromCodeCoverage] diff --git a/samples/PolylineAlgorithm.SensorData.Sample/SensorDataDecoder.cs b/samples/PolylineAlgorithm.SensorData.Sample/SensorDataDecoder.cs deleted file mode 100644 index 9c63d647..00000000 --- a/samples/PolylineAlgorithm.SensorData.Sample/SensorDataDecoder.cs +++ /dev/null @@ -1,107 +0,0 @@ -// -// Copyright © Pete Sramek. All rights reserved. -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace PolylineAlgorithm.SensorData.Sample; - -using PolylineAlgorithm.Abstraction; -using System.Collections.Generic; -using System.Threading; - -/// -/// Decodes a compact polyline string produced by back into a sequence -/// of values. -/// -/// -/// -/// This class demonstrates implementing for a custom -/// scalar type, following the same structural pattern as . -/// -/// -/// Each encoded pair consists of a delta-compressed Unix timestamp (seconds since Unix epoch, precision 0) -/// followed by a delta-compressed temperature value (at ). -/// Both are recovered and used to reconstruct the original . -/// -/// -[System.Diagnostics.CodeAnalysis.SuppressMessage("Sonar", "S4456:Parameter validation in yielding methods should be wrapped", Justification = "Inlined by design to demonstrate a simple iterator without a wrapper method.")] -internal sealed class SensorDataDecoder : IPolylineDecoder { - /// - /// Initializes a new instance of the class with default encoding options. - /// - public SensorDataDecoder() - : this(new PolylineEncodingOptions()) { } - - /// - /// Initializes a new instance of the class with the specified encoding options. - /// - /// - /// The to use for decoding operations. - /// The value must match the precision used during encoding. - /// - /// - /// Thrown when is . - /// - public SensorDataDecoder(PolylineEncodingOptions options) { - ArgumentNullException.ThrowIfNull(options); - - Options = options; - } - - /// - /// Gets the encoding options used by this decoder. - /// - public PolylineEncodingOptions Options { get; } - - /// - /// Decodes a polyline string back into a sequence of values. - /// - /// - /// The polyline-encoded string produced by . - /// - /// - /// A that can be used to cancel the decoding operation. - /// - /// - /// An of whose - /// and values - /// are recovered from the encoded string. - /// - /// - /// Thrown when is . - /// - /// - /// Thrown when is empty. - /// - /// - /// Thrown when requests cancellation. - /// - public IEnumerable Decode(string polyline, CancellationToken cancellationToken = default) { - ArgumentNullException.ThrowIfNull(polyline); - - if (polyline.Length < 1) { - throw new ArgumentException("Encoded polyline must not be empty.", nameof(polyline)); - } - - ReadOnlyMemory memory = polyline.AsMemory(); - int position = 0; - // Mirror the encoder's base epoch so the first delta decodes back to the correct Unix seconds. - int accumulatedTimestamp = SensorDataEncoder.TimestampBaseEpochSeconds; - int accumulatedTemperature = 0; - - while (position < memory.Length) { - cancellationToken.ThrowIfCancellationRequested(); - - // Read Unix timestamp delta (precision 0) then temperature delta. - if (!PolylineEncoding.TryReadValue(ref accumulatedTimestamp, memory, ref position) - || !PolylineEncoding.TryReadValue(ref accumulatedTemperature, memory, ref position)) { - yield break; - } - - long unixSeconds = (long)PolylineEncoding.Denormalize(accumulatedTimestamp, precision: 0); - double temperature = PolylineEncoding.Denormalize(accumulatedTemperature, Options.Precision); - - yield return new SensorReading(DateTimeOffset.FromUnixTimeSeconds(unixSeconds), temperature); - } - } -} diff --git a/samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs b/samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs deleted file mode 100644 index be199e4d..00000000 --- a/samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs +++ /dev/null @@ -1,135 +0,0 @@ -// -// Copyright © Pete Sramek. All rights reserved. -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace PolylineAlgorithm.SensorData.Sample; - -using PolylineAlgorithm.Abstraction; -using System.Buffers; -using System.Threading; - -/// -/// Encodes a sequence of values into a compact polyline string -/// using the polyline delta-encoding algorithm applied to both the -/// and fields. -/// -/// -/// -/// This class demonstrates implementing for a custom -/// scalar type, following the same structural pattern as . -/// -/// -/// Because sensor readings carry two numeric dimensions (timestamp and temperature), the base class designed -/// for geographic coordinate pairs is not used. Instead, static -/// helpers are called directly to perform normalisation, delta computation, and character-level encoding. -/// -/// -/// Each reading is encoded as a pair of delta-compressed values: -/// the Unix timestamp in seconds (precision 0) followed by the temperature (at ). -/// -/// -internal sealed class SensorDataEncoder : IPolylineEncoder { - // 2020-01-01 00:00:00 UTC in Unix seconds. Used as the delta-encoding base for timestamps - // so that the first absolute delta stays within the int32 safe range of the polyline algorithm. - internal const int TimestampBaseEpochSeconds = 1_577_836_800; - - /// - /// Initializes a new instance of the class with default encoding options. - /// - public SensorDataEncoder() - : this(new PolylineEncodingOptions()) { } - - /// - /// Initializes a new instance of the class with the specified encoding options. - /// - /// - /// The to use for encoding operations. - /// - /// - /// Thrown when is . - /// - public SensorDataEncoder(PolylineEncodingOptions options) { - ArgumentNullException.ThrowIfNull(options); - - Options = options; - } - - /// - /// Gets the encoding options used by this encoder. - /// - public PolylineEncodingOptions Options { get; } - - /// - /// Encodes a sequence of values into a polyline string. - /// - /// - /// The sensor readings to encode. Each reading contributes a delta-compressed Unix timestamp - /// (seconds since Unix epoch, precision 0) and a delta-compressed temperature value. - /// Must contain at least one element. - /// - /// - /// A that can be used to cancel the encoding operation. - /// - /// - /// A polyline-encoded string representing the delta-compressed timestamp and temperature series. - /// - /// - /// Thrown when is empty. - /// - /// - /// Thrown when requests cancellation. - /// - public string Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default) { - if (coordinates.Length < 1) { - throw new ArgumentException("Sequence must contain at least one element.", nameof(coordinates)); - } - - // Maximum number of ASCII characters required to encode a single 32-bit delta value - // using the polyline algorithm (ceil(32 bits / 5 bits per chunk) + sign bit = 7). - const int MaxEncodedCharsPerValue = 7; - - // Each reading encodes two values: Unix timestamp (precision 0) + temperature. - // The polyline algorithm uses signed int32 internally, limiting safe absolute values to ~1.07B. - // Current Unix time in seconds (~1.74B) exceeds this. We therefore delta-encode relative to - // 2020-01-01 00:00:00 UTC (= 1 577 836 800 s), keeping the initial delta well within range. - int previousTimestampNormalized = TimestampBaseEpochSeconds; - int previousTemperatureNormalized = 0; - int position = 0; - int length = coordinates.Length * 2 * MaxEncodedCharsPerValue; - - char[]? temp = length <= Options.StackAllocLimit - ? null - : ArrayPool.Shared.Rent(length); - - Span buffer = temp is null ? stackalloc char[length] : temp.AsSpan(0, length); - - try { - for (int i = 0; i < coordinates.Length; i++) { - cancellationToken.ThrowIfCancellationRequested(); - - // Encode Unix timestamp in whole seconds (precision 0). - int normalizedTimestamp = PolylineEncoding.Normalize((double)coordinates[i].Timestamp.ToUnixTimeSeconds(), precision: 0); - int timestampDelta = normalizedTimestamp - previousTimestampNormalized; - - // Encode temperature at the configured precision. - int normalizedTemperature = PolylineEncoding.Normalize(coordinates[i].Temperature, Options.Precision); - int temperatureDelta = normalizedTemperature - previousTemperatureNormalized; - - if (!PolylineEncoding.TryWriteValue(timestampDelta, buffer, ref position) - || !PolylineEncoding.TryWriteValue(temperatureDelta, buffer, ref position)) { - throw new InvalidOperationException("Encoding buffer is too small to hold the encoded value."); - } - - previousTimestampNormalized = normalizedTimestamp; - previousTemperatureNormalized = normalizedTemperature; - } - - return buffer[..position].ToString(); - } finally { - if (temp is not null) { - ArrayPool.Shared.Return(temp); - } - } - } -} diff --git a/samples/PolylineAlgorithm.SensorData.Sample/SensorReading.cs b/samples/PolylineAlgorithm.SensorData.Sample/SensorReading.cs deleted file mode 100644 index 6903c92f..00000000 --- a/samples/PolylineAlgorithm.SensorData.Sample/SensorReading.cs +++ /dev/null @@ -1,16 +0,0 @@ -// -// Copyright © Pete Sramek. All rights reserved. -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace PolylineAlgorithm.SensorData.Sample; - -using System.Runtime.InteropServices; - -/// -/// Represents a single temperature reading captured by a sensor. -/// -/// The UTC time at which the reading was captured. -/// The temperature value of the reading, in degrees Celsius. -[StructLayout(LayoutKind.Auto)] -internal readonly record struct SensorReading(DateTimeOffset Timestamp, double Temperature); diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs index ea087776..1059abb9 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs @@ -6,27 +6,19 @@ using Microsoft.Extensions.Logging; using PolylineAlgorithm.Internal; using PolylineAlgorithm.Internal.Diagnostics; -using System.Buffers; using System.Runtime.CompilerServices; namespace PolylineAlgorithm.Abstraction; /// -/// Provides a base implementation for decoding encoded polyline strings into sequences of items. +/// Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates. /// /// -/// Derive from this class to implement a decoder for a specific polyline type. Override -/// , , and to provide -/// type-specific behavior. -/// -/// The polyline format encodes each item as a fixed-length run of delta-compressed -/// values. All items in a single polyline must have the same number of values. For example, a 2D GPS decoder -/// sets to 2 (latitude, longitude), while a 3D GPS decoder sets it to 3 -/// (latitude, longitude, altitude). -/// +/// Derive from this class to implement a decoder for a specific polyline type. Override +/// and to provide type-specific behavior. /// /// The type that represents the encoded polyline input. -/// The type that represents a decoded item. +/// The type that represents a decoded geographic coordinate. public abstract class AbstractPolylineDecoder : IPolylineDecoder { private readonly ILogger> _logger; @@ -61,16 +53,6 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) { /// public PolylineEncodingOptions Options { get; } - /// - /// Gets the number of encoded values that make up a single decoded item. - /// - /// - /// Override this property to specify the arity of each item. For example, return 2 for - /// latitude/longitude pairs, 3 for latitude/longitude/altitude triples, or any other count - /// that matches the encoding scheme used to produce the polyline. - /// - protected abstract int ValuesPerItem { get; } - /// /// Decodes an encoded into a sequence of instances, /// with support for cancellation. @@ -82,7 +64,7 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) { /// A that can be used to cancel the decoding operation. /// /// - /// An of representing the decoded items. + /// An of representing the decoded latitude and longitude pairs. /// /// /// Thrown when is . @@ -108,45 +90,30 @@ public IEnumerable Decode(TPolyline polyline, CancellationToken can ValidateSequence(sequence, _logger); ValidateFormat(sequence, _logger); - int valuesPerItem = ValuesPerItem; int position = 0; - - int[]? runningRent = ArrayPool.Shared.Rent(valuesPerItem); - // Zero-initialize so delta decoding starts from 0 for all dimensions. - for (int j = 0; j < valuesPerItem; j++) { - runningRent[j] = 0; - } + int encodedLatitude = 0; + int encodedLongitude = 0; try { while (position < sequence.Length) { cancellationToken.ThrowIfCancellationRequested(); - bool allRead = true; - for (int j = 0; j < valuesPerItem; j++) { - if (!PolylineEncoding.TryReadValue(ref runningRent[j], sequence, ref position)) { - allRead = false; - break; - } - } - - if (!allRead) { + if (!PolylineEncoding.TryReadValue(ref encodedLatitude, sequence, ref position) + || !PolylineEncoding.TryReadValue(ref encodedLongitude, sequence, ref position)) { _logger?.LogOperationFailedDebug(OperationName); _logger?.LogInvalidPolylineWarning(position); ExceptionGuard.ThrowInvalidPolylineFormat(position); } - double[] decoded = new double[valuesPerItem]; - for (int j = 0; j < valuesPerItem; j++) { - decoded[j] = PolylineEncoding.Denormalize(runningRent[j], Options.Precision); - } + double decodedLatitude = PolylineEncoding.Denormalize(encodedLatitude, Options.Precision); + double decodedLongitude = PolylineEncoding.Denormalize(encodedLongitude, Options.Precision); - _logger?.LogDecodedValuesDebug(valuesPerItem, position); + _logger?.LogDecodedCoordinateDebug(decodedLatitude, decodedLongitude, position); - yield return CreateItem(decoded.AsMemory()); + yield return CreateCoordinate(decodedLatitude, decodedLongitude); } } finally { - ArrayPool.Shared.Return(runningRent!); _logger?.LogOperationFinishedDebug(OperationName); } } @@ -221,19 +188,17 @@ protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? lo protected abstract ReadOnlyMemory GetReadOnlyMemory(in TPolyline polyline); /// - /// Creates a instance from the specified decoded values. + /// Creates a instance from the specified latitude and longitude values. /// - /// - /// A of containing exactly - /// decoded values for this item, in the same order they were encoded. + /// + /// The latitude component of the coordinate, in degrees. + /// + /// + /// The longitude component of the coordinate, in degrees. /// /// - /// A instance representing the decoded item. + /// A instance representing the specified geographic coordinate. /// - /// - /// Implementations should read all required values from and construct the - /// immediately. The memory is valid only for the duration of this call. - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract TCoordinate CreateItem(ReadOnlyMemory values); + protected abstract TCoordinate CreateCoordinate(double latitude, double longitude); } diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs index dff4eac3..1bcdb0ee 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs @@ -16,19 +16,13 @@ namespace PolylineAlgorithm.Abstraction; using System.Threading; /// -/// Provides a base implementation for encoding sequences of items into encoded polyline strings. +/// Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings. /// /// -/// Derive from this class to implement an encoder for a specific item and polyline type. Override -/// , , and to provide type-specific behavior. -/// -/// The polyline format encodes each item as a fixed-length run of delta-compressed -/// values. All items in a single polyline must have the same number of values. For example, a 2D GPS encoder -/// sets to 2 (latitude, longitude), while a 3D GPS encoder sets it to 3 -/// (latitude, longitude, altitude). -/// +/// Derive from this class to implement an encoder for a specific coordinate and polyline type. Override +/// , , and to provide type-specific behavior. /// -/// The type that represents an item to encode. +/// The type that represents a geographic coordinate to encode. /// The type that represents the encoded polyline output. public abstract class AbstractPolylineEncoder : IPolylineEncoder { private readonly ILogger> _logger; @@ -62,16 +56,6 @@ protected AbstractPolylineEncoder(PolylineEncodingOptions options) { /// public PolylineEncodingOptions Options { get; } - /// - /// Gets the number of values that make up a single encoded item. - /// - /// - /// Override this property to specify the arity of each item. For example, return 2 for - /// latitude/longitude pairs, 3 for latitude/longitude/altitude triples, or any other count - /// that matches your encoding scheme. - /// - protected abstract int ValuesPerItem { get; } - /// /// Encodes a collection of instances into an encoded string. /// @@ -104,12 +88,11 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken ValidateEmptyCoordinates(ref coordinates, _logger); - int valuesPerItem = ValuesPerItem; - CoordinateDelta delta = new(valuesPerItem); + CoordinateDelta delta = new(); int position = 0; int consumed = 0; - int length = GetMaxBufferLength(coordinates.Length, valuesPerItem); + int length = GetMaxBufferLength(coordinates.Length); char[]? temp = length <= Options.StackAllocLimit ? null @@ -117,37 +100,29 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken Span buffer = temp is null ? stackalloc char[length] : temp.AsSpan(0, length); - int[]? normalizedRent = ArrayPool.Shared.Rent(valuesPerItem); - Span normalized = normalizedRent.AsSpan(0, valuesPerItem); - - double[]? valuesRent = ArrayPool.Shared.Rent(valuesPerItem); - Span values = valuesRent.AsSpan(0, valuesPerItem); - string encodedResult; try { for (var i = 0; i < coordinates.Length; i++) { cancellationToken.ThrowIfCancellationRequested(); - GetValues(coordinates[i], values); - - for (int j = 0; j < valuesPerItem; j++) { - normalized[j] = PolylineEncoding.Normalize(values[j], Options.Precision); - } + delta + .Next( + PolylineEncoding.Normalize(GetLatitude(coordinates[i]), Options.Precision), + PolylineEncoding.Normalize(GetLongitude(coordinates[i]), Options.Precision) + ); - delta.Next(normalized); + if (!PolylineEncoding.TryWriteValue(delta.Latitude, buffer, ref position) + || !PolylineEncoding.TryWriteValue(delta.Longitude, buffer, ref position) + ) { + // This shouldn't happen, but if it does, log the error and throw an exception. + _logger + .LogOperationFailedDebug(OperationName); + _logger + .LogCannotWriteValueToBufferWarning(position, consumed); - ReadOnlySpan deltas = delta.Deltas; - for (int j = 0; j < deltas.Length; j++) { - if (!PolylineEncoding.TryWriteValue(deltas[j], buffer, ref position)) { - // This shouldn't happen, but if it does, log the error and throw an exception. - _logger - .LogOperationFailedDebug(OperationName); - _logger - .LogCannotWriteValueToBufferWarning(position, consumed); + ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer(); - ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer(); - } } consumed++; @@ -155,8 +130,6 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken encodedResult = buffer[..position].ToString(); } finally { - ArrayPool.Shared.Return(valuesRent!); - ArrayPool.Shared.Return(normalizedRent!); if (temp is not null) { ArrayPool.Shared.Return(temp); } @@ -168,10 +141,10 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken return CreatePolyline(encodedResult.AsMemory()); [MethodImpl(MethodImplOptions.AggressiveInlining)] - static int GetMaxBufferLength(int count, int perItem) { + static int GetMaxBufferLength(int count) { Debug.Assert(count > 0, "Count must be greater than zero."); - int requestedBufferLength = count * perItem * Defaults.Polyline.Block.Length.Max; + int requestedBufferLength = count * 2 * Defaults.Polyline.Block.Length.Max; Debug.Assert(requestedBufferLength > 0, "Requested buffer length must be greater than zero."); @@ -202,18 +175,23 @@ static void ValidateEmptyCoordinates(ref ReadOnlySpan coordinates, protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline); /// - /// Fills with the values to encode for the specified item. + /// Extracts the longitude value from the specified coordinate. /// - /// The item from which to extract values. - /// - /// A of length to fill with the item's values, - /// in the order they should be encoded. - /// - /// - /// Implementations should write exactly values into . - /// For example, a 2D GPS encoder writes destination[0] = latitude; destination[1] = longitude;. - /// + /// The coordinate from which to extract the longitude. + /// + /// The longitude value as a . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected abstract double GetLongitude(TCoordinate current); + + /// + /// Extracts the latitude value from the specified coordinate. + /// + /// The coordinate from which to extract the latitude. + /// + /// The latitude value as a . + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract void GetValues(TCoordinate item, Span destination); + protected abstract double GetLatitude(TCoordinate current); } diff --git a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs index 70826216..ae217c57 100644 --- a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs +++ b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs @@ -5,82 +5,68 @@ namespace PolylineAlgorithm.Internal; -using System; using System.Diagnostics; using System.Runtime.InteropServices; -using System.Text; /// -/// Represents the running delta state for an arbitrary number of encoded values between consecutive items. +/// Represents the difference (delta) in latitude and longitude between consecutive geographic coordinates. /// /// -/// This struct computes and stores the change in each value dimension as integer deltas between successive items. -/// The number of dimensions is specified at construction time, enabling support for any number of encoded fields -/// (e.g. latitude/longitude, latitude/longitude/altitude, or arbitrary sensor fields). +/// This struct computes and stores the change in coordinate values as integer deltas between successive coordinates. /// [DebuggerDisplay("{ToString(),nq}")] [StructLayout(LayoutKind.Auto)] internal struct CoordinateDelta { - private readonly int[] _current; - private readonly int[] _deltas; + private (int Latitude, int Longitude) _current; /// - /// Initializes a new instance of the struct for the specified number of value dimensions. + /// Initializes a new instance of the struct with the default latitude and longitude deltas. /// - /// The number of value dimensions to track. Must be greater than zero. - public CoordinateDelta(int count) { - Debug.Assert(count > 0, "Count must be greater than zero."); - - _current = new int[count]; - _deltas = new int[count]; + public CoordinateDelta() { + _current = (default, default); } /// - /// Gets the current deltas computed by the most recent call to . + /// Gets the current delta in latitude between the most recent and previous coordinate. + /// + public int Latitude { get; private set; } + + /// + /// Gets the current delta in longitude between the most recent and previous coordinate. /// - public ReadOnlySpan Deltas => _deltas; + public int Longitude { get; private set; } /// - /// Updates the delta values based on the next set of values, and sets them as the baseline for the next call. + /// Updates the delta values based on the next latitude and longitude, and sets the current coordinate as next delta baseline. /// - /// - /// The next normalized integer values. Must have the same length as the count passed to the constructor. - /// - public void Next(ReadOnlySpan values) { - Debug.Assert(values.Length == _current.Length, "Values length must match the delta dimension count."); + /// The next latitude value. + /// The next longitude value. + public void Next(int latitude, int longitude) { + Latitude = Delta(_current.Latitude, latitude); + Longitude = Delta(_current.Longitude, longitude); - for (int i = 0; i < values.Length; i++) { - _deltas[i] = values[i] - _current[i]; - _current[i] = values[i]; - } + _current.Latitude = latitude; + _current.Longitude = longitude; } /// - /// Returns a string representation of the current values and deltas. + /// Calculates the delta between two coordinate values. + /// + /// + /// This method computes the difference between two integer coordinate values, handling cases where the values may be positive or negative. + /// + /// The previous coordinate value. + /// The next coordinate value. + /// The computed delta between and . + private static int Delta(int initial, int next) => next - initial; + + /// + /// Returns a string representation of the current coordinate delta. /// /// - /// A string in the format { Values: [v0, v1, ...], Deltas: [d0, d1, ...] }. + /// A string in the format { Coordinate: { Latitude: [int], Longitude: [int] }, Delta: { Latitude: [int], Longitude: [int] } } representing the current coordinate and deltas to previous coordinate. /// - public override readonly string ToString() { - var sb = new StringBuilder("{ Values: ["); - for (int i = 0; i < _current.Length; i++) { - if (i > 0) { - sb.Append(", "); - } - - sb.Append(_current[i]); - } - - sb.Append("], Deltas: ["); - for (int i = 0; i < _deltas.Length; i++) { - if (i > 0) { - sb.Append(", "); - } - - sb.Append(_deltas[i]); - } - - sb.Append("] }"); - return sb.ToString(); - } + public override readonly string ToString() => + $"{{ Coordinate: {{ Latitude: {_current.Latitude}, Longitude: {_current.Longitude} }}, " + + $"Delta: {{ Latitude: {Latitude}, Longitude: {Longitude} }} }}"; } \ No newline at end of file diff --git a/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs b/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs index 9a422a73..cc58c702 100644 --- a/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs +++ b/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs @@ -46,11 +46,12 @@ internal static partial class LogDebugExtensions { internal static partial void LogOperationFinishedDebug(this ILogger logger, string operationName); /// - /// Logs a debug message containing the number of decoded values and position. + /// Logs a debug message containing the decoded coordinate values and position. /// /// The used to write the log entry. - /// The number of values that were decoded for this item. - /// The position in the polyline buffer at which the item was decoded. - [LoggerMessage(EVENT_ID_BASE + 4, LOG_LEVEL, "Decoded {count} values at position {position}.")] - internal static partial void LogDecodedValuesDebug(this ILogger logger, int count, int position); + /// The decoded latitude value. + /// The decoded longitude value. + /// The position in the polyline buffer at which the coordinate was decoded. + [LoggerMessage(EVENT_ID_BASE + 4, LOG_LEVEL, "Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}.")] + internal static partial void LogDecodedCoordinateDebug(this ILogger logger, double latitude, double longitude, int position); } diff --git a/src/PolylineAlgorithm/PolylineAlgorithm.csproj b/src/PolylineAlgorithm/PolylineAlgorithm.csproj index 907a2a15..24504239 100644 --- a/src/PolylineAlgorithm/PolylineAlgorithm.csproj +++ b/src/PolylineAlgorithm/PolylineAlgorithm.csproj @@ -8,13 +8,6 @@ True
- - - $(WarningsAsErrors);RS0017 - - true diff --git a/src/PolylineAlgorithm/PolylineEncoding.cs b/src/PolylineAlgorithm/PolylineEncoding.cs index 3d6de5e7..4b8d5312 100644 --- a/src/PolylineAlgorithm/PolylineEncoding.cs +++ b/src/PolylineAlgorithm/PolylineEncoding.cs @@ -1,4 +1,4 @@ -// +// // Copyright © Pete Sramek. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for full license information. // @@ -76,11 +76,10 @@ public static int Normalize(double value, uint precision = 5) { uint factor = Pow10.GetFactor(precision); - const double Epsilon = 1e-9; - checked { - return (int)Math.Truncate((value * factor) + (Epsilon * Math.Sign(value))); + return (int)(Math.Truncate(value * 10 * factor) / 10); } + } /// diff --git a/src/PolylineAlgorithm/PublicAPI.Shipped.txt b/src/PolylineAlgorithm/PublicAPI.Shipped.txt index 7dc5c581..91b0e1a4 100644 --- a/src/PolylineAlgorithm/PublicAPI.Shipped.txt +++ b/src/PolylineAlgorithm/PublicAPI.Shipped.txt @@ -1 +1 @@ -#nullable enable +#nullable enable \ No newline at end of file diff --git a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt index 4033ef24..7dc5c581 100644 --- a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt +++ b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt @@ -1,9 +1 @@ #nullable enable -abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.CreateItem(System.ReadOnlyMemory values) -> TCoordinate -abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.GetReadOnlyMemory(in TPolyline polyline) -> System.ReadOnlyMemory -abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValuesPerItem.get -> int -abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.GetValues(TCoordinate item, System.Span destination) -> void -abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.ValuesPerItem.get -> int -virtual PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValidateFormat(System.ReadOnlyMemory sequence, Microsoft.Extensions.Logging.ILogger? logger) -> void -PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException() -> void -PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException(string! message, System.Exception! innerException) -> void diff --git a/src/PolylineAlgorithm/README.md b/src/PolylineAlgorithm/README.md index 97c4bb98..d1bf97e0 100644 --- a/src/PolylineAlgorithm/README.md +++ b/src/PolylineAlgorithm/README.md @@ -1,8 +1,6 @@ # PolylineAlgorithm for .NET -[![NuGet](https://img.shields.io/nuget/v/PolylineAlgorithm)](https://www.nuget.org/packages/PolylineAlgorithm) - -Google's Encoded Polyline Algorithm compresses sequences of geographic coordinates into a compact ASCII string, widely used in mapping APIs. This library provides a fully compliant .NET implementation with extensible, type-safe encoding and decoding APIs. +A modern, fully compliant Google Encoded Polyline Algorithm library for .NET Standard 2.1+, supporting strong input validation, extensibility for custom coordinate types, and robust performance. ## Features @@ -61,7 +59,6 @@ var encoder = new MyPolylineEncoder(); string encoded = encoder.Encode(coordinates); // extension method for List Console.WriteLine(encoded); -// Output: "yseiHoc_MwacOjnwM" ``` ### Implement a custom decoder @@ -87,22 +84,8 @@ IEnumerable<(double Latitude, double Longitude)> decoded = decoder.Decode(encode ## Advanced Usage -Use `PolylineEncodingOptionsBuilder` to customize precision, buffer size, and logging, then pass the built options to the encoder or decoder constructor: - -```csharp -using Microsoft.Extensions.Logging; - -PolylineEncodingOptions options = PolylineEncodingOptionsBuilder.Create() - .WithPrecision(6) // 6 decimal places instead of the default 5 - .WithStackAllocLimit(1024) // increase stack-alloc buffer - .WithLoggerFactory(loggerFactory) // plug in your ILoggerFactory - .Build(); - -var encoder = new MyPolylineEncoder(options); -var decoder = new MyPolylineDecoder(options); -``` - -Use static methods on `PolylineEncoding` for low-level normalization, validation, and bit-level read/write operations. +- Pass a `PolylineEncodingOptions` (built via `PolylineEncodingOptionsBuilder`) to the encoder/decoder constructor for custom precision, stack-alloc limit, and logging. +- Use static methods on `PolylineEncoding` for low-level normalization, validation, and bit-level read/write operations. > See [API Reference](https://petesramek.github.io/polyline-algorithm-csharp/) for full documentation. @@ -110,8 +93,6 @@ Use static methods on `PolylineEncoding` for low-level normalization, validation - **What coordinate ranges are valid?** Latitude: -90..90, Longitude: -180..180 (throws `ArgumentOutOfRangeException` for invalid input) -- **What happens if I pass malformed input to the decoder?** - The decoder throws `InvalidPolylineException` with a descriptive message. Wrap calls in a try/catch in your application. - **What .NET versions are supported?** Any environment supporting `netstandard2.1` - **How do I customize encoder options?** @@ -119,11 +100,6 @@ Use static methods on `PolylineEncoding` for low-level normalization, validation - **Where can I get help?** [GitHub issues](https://github.com/petesramek/polyline-algorithm-csharp/issues) -## Resources - -- [GitHub Repository](https://github.com/petesramek/polyline-algorithm-csharp) — source code, issues, changelog, and samples -- [API Reference](https://petesramek.github.io/polyline-algorithm-csharp/) — full auto-generated documentation - ## License MIT License © Pete Sramek diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs index b5a64627..c6734c6c 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs @@ -16,24 +16,16 @@ namespace PolylineAlgorithm.Tests.Abstraction; [TestClass] public sealed class AbstractPolylineDecoderTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { - protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); - } + protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); } private sealed class TestStringDecoderWithOptions : AbstractPolylineDecoder { public TestStringDecoderWithOptions(PolylineEncodingOptions options) : base(options) { } - protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); - } + protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); } /// diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs index 1500b0de..f537dda2 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs @@ -21,12 +21,9 @@ public TestStringEncoder() public TestStringEncoder(PolylineEncodingOptions options) : base(options) { } - protected override int ValuesPerItem => 2; protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override void GetValues((double Latitude, double Longitude) item, Span destination) { - destination[0] = item.Latitude; - destination[1] = item.Longitude; - } + protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude; + protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude; } /// diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs index 069c639f..c44c914d 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs @@ -17,21 +17,13 @@ namespace PolylineAlgorithm.Tests.Extensions; [TestClass] public sealed class PolylineDecoderExtensionsTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { - protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); - } + protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); } private sealed class TestMemoryDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { - protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) => polyline; - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); - } + protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); } // ----- Decode(char[]) for IPolylineDecoder ----- diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs index 874f168c..da8a622e 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs @@ -17,12 +17,9 @@ namespace PolylineAlgorithm.Tests.Extensions; [TestClass] public sealed class PolylineEncoderExtensionsTests { private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - protected override int ValuesPerItem => 2; protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override void GetValues((double Latitude, double Longitude) item, Span destination) { - destination[0] = item.Latitude; - destination[1] = item.Longitude; - } + protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude; + protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude; } // ----- Encode(List) ----- diff --git a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs index 03ef5e66..1e915fe2 100644 --- a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs +++ b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs @@ -6,6 +6,7 @@ namespace PolylineAlgorithm.Tests.Internal; using PolylineAlgorithm.Internal; +using System.Globalization; /// /// Tests for . @@ -13,22 +14,20 @@ namespace PolylineAlgorithm.Tests.Internal; [TestClass] public sealed class CoordinateDeltaTests { /// - /// Tests that a newly constructed instance reports all-zero deltas. + /// Tests that the default constructor initializes delta values to zero. /// [TestMethod] - public void Constructor_Default_Initializes_Deltas_To_Zero() { + public void Constructor_Default_Initializes_Latitude_And_Longitude_To_Zero() { // Act - CoordinateDelta delta = new(2); + CoordinateDelta delta = new(); // Assert - ReadOnlySpan deltas = delta.Deltas; - Assert.AreEqual(2, deltas.Length); - Assert.AreEqual(0, deltas[0]); - Assert.AreEqual(0, deltas[1]); + Assert.AreEqual(0, delta.Latitude); + Assert.AreEqual(0, delta.Longitude); } /// - /// Tests that a single call to Next computes the correct delta from the initial zero state for 2 values. + /// Tests that a single call to Next computes the correct delta from the initial zero state. /// [TestMethod] [DataRow(10, 20, 10, 20)] @@ -36,94 +35,59 @@ public void Constructor_Default_Initializes_Deltas_To_Zero() { [DataRow(0, 0, 0, 0)] [DataRow(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue)] [DataRow(int.MinValue, int.MinValue, int.MinValue, int.MinValue)] - public void Next_Single_Call_From_Zero_Computes_Expected_Delta_For_Two_Values(int v0, int v1, int expectedD0, int expectedD1) { + public void Next_Single_Call_From_Zero_Computes_Expected_Delta(int latitude, int longitude, int expectedLatitude, int expectedLongitude) { // Arrange - CoordinateDelta delta = new(2); + CoordinateDelta delta = new(); // Act - delta.Next([v0, v1]); + delta.Next(latitude, longitude); // Assert - ReadOnlySpan deltas = delta.Deltas; - Assert.AreEqual(expectedD0, deltas[0]); - Assert.AreEqual(expectedD1, deltas[1]); + Assert.AreEqual(expectedLatitude, delta.Latitude); + Assert.AreEqual(expectedLongitude, delta.Longitude); } /// - /// Tests that two consecutive calls to Next compute the delta relative to the previous value for 2 values. + /// Tests that two consecutive calls to Next compute the delta relative to the previous value. /// [TestMethod] [DataRow(10, 20, 15, 30, 5, 10)] [DataRow(100, 200, 50, 150, -50, -50)] [DataRow(42, 84, 42, 84, 0, 0)] [DataRow(-50, 100, 25, -75, 75, -175)] - public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value_For_Two_Values( - int first0, int first1, - int second0, int second1, - int expectedD0, int expectedD1) { + public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value( + int firstLatitude, int firstLongitude, + int secondLatitude, int secondLongitude, + int expectedLatitude, int expectedLongitude) { // Arrange - CoordinateDelta delta = new(2); - delta.Next([first0, first1]); + CoordinateDelta delta = new(); + delta.Next(firstLatitude, firstLongitude); // Act - delta.Next([second0, second1]); + delta.Next(secondLatitude, secondLongitude); // Assert - ReadOnlySpan deltas = delta.Deltas; - Assert.AreEqual(expectedD0, deltas[0]); - Assert.AreEqual(expectedD1, deltas[1]); + Assert.AreEqual(expectedLatitude, delta.Latitude); + Assert.AreEqual(expectedLongitude, delta.Longitude); } /// - /// Tests that Next works correctly for a single value dimension. - /// - [TestMethod] - public void Next_Single_Dimension_Computes_Correct_Delta() { - // Arrange - CoordinateDelta delta = new(1); - delta.Next([100]); - - // Act - delta.Next([150]); - - // Assert - Assert.AreEqual(50, delta.Deltas[0]); - } - - /// - /// Tests that Next works correctly for three value dimensions. - /// - [TestMethod] - public void Next_Three_Dimensions_Computes_Correct_Deltas() { - // Arrange - CoordinateDelta delta = new(3); - delta.Next([10, 20, 30]); - - // Act - delta.Next([15, 25, 25]); - - // Assert - ReadOnlySpan deltas = delta.Deltas; - Assert.AreEqual(5, deltas[0]); - Assert.AreEqual(5, deltas[1]); - Assert.AreEqual(-5, deltas[2]); - } - - /// - /// Tests that ToString on a default instance returns a non-null string containing structural keywords. + /// Tests that ToString on a default instance returns a string containing expected structural keywords and a zero value. /// [TestMethod] public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zeros() { // Arrange - CoordinateDelta delta = new(2); + CoordinateDelta delta = new(); // Act string result = delta.ToString(); // Assert Assert.IsNotNull(result); - Assert.IsTrue(result.Contains("Values", StringComparison.Ordinal)); - Assert.IsTrue(result.Contains("Deltas", StringComparison.Ordinal)); + Assert.IsTrue(result.Contains("Coordinate", StringComparison.Ordinal)); + Assert.IsTrue(result.Contains("Delta", StringComparison.Ordinal)); + Assert.IsTrue(result.Contains("Latitude", StringComparison.Ordinal)); + Assert.IsTrue(result.Contains("Longitude", StringComparison.Ordinal)); Assert.Contains('0', result); } @@ -133,18 +97,20 @@ public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zero [TestMethod] [DataRow(42, 84)] [DataRow(-100, -200)] - public void ToString_After_Next_Contains_Expected_Values(int v0, int v1) { + [DataRow(int.MaxValue, int.MaxValue)] + [DataRow(int.MinValue, int.MinValue)] + public void ToString_After_Next_Contains_Expected_Values(int latitude, int longitude) { // Arrange - CoordinateDelta delta = new(2); - delta.Next([v0, v1]); + CoordinateDelta delta = new(); + delta.Next(latitude, longitude); // Act string result = delta.ToString(); // Assert Assert.IsNotNull(result); - Assert.IsTrue(result.Contains(v0.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.Ordinal)); - Assert.IsTrue(result.Contains(v1.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.Ordinal)); + Assert.IsTrue(result.Contains(latitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal)); + Assert.IsTrue(result.Contains(longitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal)); } /// @@ -153,9 +119,9 @@ public void ToString_After_Next_Contains_Expected_Values(int v0, int v1) { [TestMethod] public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Latest_Values() { // Arrange - CoordinateDelta delta = new(2); - delta.Next([10, 20]); - delta.Next([30, 50]); + CoordinateDelta delta = new(); + delta.Next(10, 20); + delta.Next(30, 50); // Act string result = delta.ToString(); @@ -166,5 +132,5 @@ public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Lat Assert.IsTrue(result.Contains("50", StringComparison.Ordinal)); Assert.IsTrue(result.Contains("20", StringComparison.Ordinal)); } -} +} diff --git a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs index c9daaa1f..0dff7193 100644 --- a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs @@ -80,21 +80,20 @@ public void LogOperationFinishedDebug_With_Operation_Name_Logs_Finished_Message( } /// - /// Tests that LogDecodedValuesDebug WithCountAndPosition LogsDecodedValuesMessage. + /// Tests that LogDecodedCoordinateDebug WithCoordinatesAndPosition LogsDecodedCoordinateMessage. /// [TestMethod] - public void LogDecodedValuesDebug_With_Count_And_Position_Logs_Decoded_Values_Message() { + public void LogDecodedCoordinateDebug_With_Coordinates_And_Position_Logs_Decoded_Coordinate_Message() { var logger = new TestLogger(); - const int count = 2; + const double latitude = 38.5; + const double longitude = -120.2; const int position = 42; - logger.LogDecodedValuesDebug(count, position); + logger.LogDecodedCoordinateDebug(latitude, longitude, position); Assert.HasCount(1, logger.Logs); Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level); - Assert.Contains("Decoded", logger.Logs[0].Message, StringComparison.Ordinal); - Assert.Contains(count.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal); - Assert.Contains(position.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}."), logger.Logs[0].Message, StringComparison.Ordinal); } /// @@ -143,35 +142,37 @@ public void LogOperationFinishedDebug_With_Null_Operation_Name_Logs_Message() { } /// - /// Tests that LogDecodedValuesDebug WithZeroCountAndPosition LogsMessage. + /// Tests that LogDecodedCoordinateDebug WithZeroCoordinates LogsMessage. /// [TestMethod] - public void LogDecodedValuesDebug_With_Zero_Count_Logs_Message() { + public void LogDecodedCoordinateDebug_With_Zero_Coordinates_Logs_Message() { var logger = new TestLogger(); - const int count = 0; + const double latitude = 0.0; + const double longitude = 0.0; const int position = 0; - logger.LogDecodedValuesDebug(count, position); + logger.LogDecodedCoordinateDebug(latitude, longitude, position); Assert.HasCount(1, logger.Logs); Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level); - Assert.Contains("Decoded", logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains("Decoded coordinate", logger.Logs[0].Message, StringComparison.Ordinal); } /// - /// Tests that LogDecodedValuesDebug WithLargeCount LogsMessage. + /// Tests that LogDecodedCoordinateDebug WithNegativeCoordinates LogsMessage. /// [TestMethod] - public void LogDecodedValuesDebug_With_Large_Count_Logs_Message() { + public void LogDecodedCoordinateDebug_With_Negative_Coordinates_Logs_Message() { var logger = new TestLogger(); - const int count = 5; + const double latitude = -90.0; + const double longitude = -180.0; const int position = 100; - logger.LogDecodedValuesDebug(count, position); + logger.LogDecodedCoordinateDebug(latitude, longitude, position); Assert.HasCount(1, logger.Logs); Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level); - Assert.Contains(count.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Latitude: {latitude}, Longitude: {longitude}"), logger.Logs[0].Message, StringComparison.Ordinal); } /// diff --git a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs index 0ca40426..d3d83b9e 100644 --- a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs +++ b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs @@ -105,15 +105,16 @@ private readonly struct PolylineCoordinateCollectionPair(IEnumerable<(double Lat private sealed class PolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - protected override int ValuesPerItem => 2; - protected override string CreatePolyline(ReadOnlyMemory polyline) { return polyline.ToString(); } - protected override void GetValues((double Latitude, double Longitude) item, Span destination) { - destination[0] = item.Latitude; - destination[1] = item.Longitude; + protected override double GetLatitude((double Latitude, double Longitude) current) { + return current.Latitude; + } + + protected override double GetLongitude((double Latitude, double Longitude) current) { + return current.Longitude; } } } \ No newline at end of file From a5ee061abc6910470a81a474dd8f9c2734284fd2 Mon Sep 17 00:00:00 2001 From: Pete Sramek <2333452+petesramek@users.noreply.github.com> Date: Mon, 6 Apr 2026 00:06:31 +0200 Subject: [PATCH 03/24] Revert "reset: revert all previous changes, clean slate identical to main" This reverts commit 89a6a24401b883dcfdec0d69a8237b3e41a42c02. --- .editorconfig | 3 + .github/CODEOWNERS | 5 + .github/ISSUE_TEMPLATE/bug_report.md | 32 +- .github/ISSUE_TEMPLATE/config.yml | 5 + .github/ISSUE_TEMPLATE/feature_request.md | 4 +- .github/PULL_REQUEST_TEMPLATE.md | 19 + .github/actions/source/compile/action.yml | 2 +- .github/dependabot.yml | 12 + .github/release.yml | 23 + .github/workflows/build.yml | 2 +- .github/workflows/publish-documentation.yml | 21 +- .github/workflows/pull-request.yml | 47 +- .github/workflows/release.yml | 202 ++++++- CHANGELOG.md | 10 + CODE_OF_CONDUCT.md | 47 ++ Directory.Build.props | 3 + PolylineAlgorithm.slnx | 1 + README.md | 81 ++- SECURITY.md | 23 + ....Abstraction.AbstractPolylineDecoder-2.yml | 233 ++++++++ ....Abstraction.AbstractPolylineEncoder-2.yml | 219 ++++++++ ...gorithm.Abstraction.IPolylineDecoder-2.yml | 90 +++ ...gorithm.Abstraction.IPolylineEncoder-2.yml | 142 +++++ .../0.0/PolylineAlgorithm.Abstraction.yml | 34 ++ ...m.Extensions.PolylineDecoderExtensions.yml | 195 +++++++ ...m.Extensions.PolylineEncoderExtensions.yml | 139 +++++ .../0.0/PolylineAlgorithm.Extensions.yml | 19 + ...lineAlgorithm.InvalidPolylineException.yml | 102 ++++ .../PolylineAlgorithm.PolylineEncoding.yml | 529 ++++++++++++++++++ ...ylineAlgorithm.PolylineEncodingOptions.yml | 127 +++++ ...gorithm.PolylineEncodingOptionsBuilder.yml | 141 +++++ api-reference/0.0/PolylineAlgorithm.yml | 38 ++ api-reference/0.0/toc.yml | 34 ++ api-reference/guide/benchmarks.md | 11 + api-reference/guide/toc.yml | 2 + .../PolylineDecoderBenchmark.cs | 18 +- .../PolylineEncoderBenchmark.cs | 7 +- docs/local-development.md | 21 + docs/workflows.md | 1 + .../NetTopologyPolylineDecoder.cs | 19 +- .../NetTopologyPolylineEncoder.cs | 41 +- ...neAlgorithm.NetTopologySuite.Sample.csproj | 3 +- .../Program.cs | 46 ++ ...PolylineAlgorithm.SensorData.Sample.csproj | 16 + .../Program.cs | 49 ++ .../Properties/CodeCoverage.cs | 8 + .../SensorDataDecoder.cs | 107 ++++ .../SensorDataEncoder.cs | 135 +++++ .../SensorReading.cs | 16 + .../Abstraction/AbstractPolylineDecoder.cs | 77 ++- .../Abstraction/AbstractPolylineEncoder.cs | 98 ++-- .../Internal/CoordinateDelta.cs | 88 +-- .../Diagnostics/LogDebugExtensions.cs | 11 +- .../PolylineAlgorithm.csproj | 7 + src/PolylineAlgorithm/PolylineEncoding.cs | 7 +- src/PolylineAlgorithm/PublicAPI.Shipped.txt | 2 +- src/PolylineAlgorithm/PublicAPI.Unshipped.txt | 8 + src/PolylineAlgorithm/README.md | 30 +- .../AbstractPolylineDecoderTests.cs | 12 +- .../AbstractPolylineEncoderTests.cs | 7 +- .../PolylineDecoderExtensionsTests.cs | 12 +- .../PolylineEncoderExtensionsTests.cs | 7 +- .../Internal/CoordinateDeltaTests.cs | 112 ++-- .../Diagnostics/LogDebugExtensionsTests.cs | 35 +- .../RandomValueProvider.cs | 11 +- 65 files changed, 3274 insertions(+), 334 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/release.yml create mode 100644 CHANGELOG.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 SECURITY.md create mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.yml create mode 100644 api-reference/0.0/toc.yml create mode 100644 api-reference/guide/benchmarks.md create mode 100644 samples/PolylineAlgorithm.NetTopologySuite.Sample/Program.cs create mode 100644 samples/PolylineAlgorithm.SensorData.Sample/PolylineAlgorithm.SensorData.Sample.csproj create mode 100644 samples/PolylineAlgorithm.SensorData.Sample/Program.cs create mode 100644 samples/PolylineAlgorithm.SensorData.Sample/Properties/CodeCoverage.cs create mode 100644 samples/PolylineAlgorithm.SensorData.Sample/SensorDataDecoder.cs create mode 100644 samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs create mode 100644 samples/PolylineAlgorithm.SensorData.Sample/SensorReading.cs diff --git a/.editorconfig b/.editorconfig index 75d9084f..7282c0f7 100644 --- a/.editorconfig +++ b/.editorconfig @@ -274,3 +274,6 @@ dotnet_naming_style.underscore_camel_case.capitalization = camel_case # Public API analyzer dotnet_public_api_analyzer.require_api_files = true + +# RS0017: Symbol removed from public API - error severity (IDE guidance; build enforcement via WarningsAsErrors in .csproj) +dotnet_diagnostic.RS0017.severity = error diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..880b45f7 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,5 @@ +* @petesramek + +.github/ @petesramek +src/ @petesramek +tests/ @petesramek diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd84ea78..6236e3a0 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,8 +1,8 @@ --- name: Bug report about: Create a report to help us improve -title: '' -labels: '' +title: '[Bug]: ' +labels: 'bug' assignees: '' --- @@ -11,28 +11,22 @@ assignees: '' A clear and concise description of what the bug is. **To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error +Minimal code snippet that reproduces the issue: + +```csharp +// paste reproduction code here +``` **Expected behavior** A clear and concise description of what you expected to happen. -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] +**Actual behavior** +A clear and concise description of what actually happens (include exception messages/stack traces if applicable). -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] +**Environment** + - Package version: [e.g. 2.1.0] + - .NET version: [e.g. net8.0] + - OS: [e.g. Windows 11, Ubuntu 24.04] **Additional context** Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..2afb950d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Ask a question + url: https://github.com/petesramek/polyline-algorithm-csharp/discussions + about: Use GitHub Discussions for questions, ideas, or general feedback. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7d..5c8a425a 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,8 +1,8 @@ --- name: Feature request about: Suggest an idea for this project -title: '' -labels: '' +title: '[Feature]: ' +labels: 'enhancement' assignees: '' --- diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..70eda657 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,19 @@ +## Summary + + + +## Type of change + +- [ ] Bug fix +- [ ] New feature +- [ ] Breaking change +- [ ] Documentation / samples only + +## Checklist + +- [ ] Unit tests added or updated (`/tests`) +- [ ] Benchmarks added or updated (`/benchmarks`) — if performance-impacting +- [ ] XML doc comments updated for all public API changes +- [ ] `dotnet format` run with no issues +- [ ] README and `/samples` updated — if public API changed +- [ ] PR label added (`breaking` / `feat` / `fix` / `docs`) — for changelog categorization diff --git a/.github/actions/source/compile/action.yml b/.github/actions/source/compile/action.yml index 0af331ee..dbe88dd5 100644 --- a/.github/actions/source/compile/action.yml +++ b/.github/actions/source/compile/action.yml @@ -12,7 +12,7 @@ inputs: file-version: description: 'Assembly file version.' required: true - treat-warnins-as-error: + treat-warnings-as-error: description: 'Treat warnings as errors.' required: true project-path: diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 02a54502..b00ae422 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,11 +4,23 @@ updates: directory: "/" schedule: interval: "weekly" + labels: + - "dependencies" + assignees: + - "petesramek" - package-ecosystem: "nuget" directory: "/" schedule: interval: "weekly" + labels: + - "dependencies" + assignees: + - "petesramek" - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" + labels: + - "dependencies" + assignees: + - "petesramek" diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 00000000..e7b05735 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,23 @@ +changelog: + exclude: + labels: + - ignore-for-release + categories: + - title: Breaking Changes + labels: + - breaking + - title: New Features + labels: + - feat + - enhancement + - title: Bug Fixes + labels: + - fix + - bug + - title: Documentation + labels: + - docs + - documentation + - title: Other Changes + labels: + - '*' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 047d4afd..5abb7df8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -130,7 +130,7 @@ jobs: assembly-version: ${{ env.assembly-version }} assembly-informational-version: ${{ env.assembly-informational-version }} file-version: ${{ env.file-version }} - treat-warnins-as-error: ${{ needs.workflow-variables.outputs.is-release }} + treat-warnings-as-error: ${{ needs.workflow-variables.outputs.is-release }} test: name: 'Run tests' diff --git a/.github/workflows/publish-documentation.yml b/.github/workflows/publish-documentation.yml index 85d8f21a..7f01504d 100644 --- a/.github/workflows/publish-documentation.yml +++ b/.github/workflows/publish-documentation.yml @@ -96,6 +96,21 @@ jobs: run: | cp -r api-reference/guide api-reference/${{ env.friendly-version }}/guide + - name: 'Download benchmark results' + uses: actions/download-artifact@v8 + with: + pattern: benchmark-* + path: /tmp/benchmarks + merge-multiple: true + + - name: 'Inject benchmark results into guide for v${{ env.friendly-version }}' + shell: bash + run: | + find /tmp/benchmarks -name "*-report-github.md" | sort | xargs -r cat > /tmp/benchmark_results.md + awk '/{benchmarks_section}/{while((getline line < "/tmp/benchmark_results.md") > 0) print line; close("/tmp/benchmark_results.md"); next} {print}' \ + "api-reference/${{ env.friendly-version }}/guide/benchmarks.md" > /tmp/benchmarks.md + mv /tmp/benchmarks.md "api-reference/${{ env.friendly-version }}/guide/benchmarks.md" + - name: 'Discover all versions' id: discover-versions shell: bash @@ -151,15 +166,15 @@ jobs: { echo "## Released Versions" echo "" - echo "| Version | Guide | API Reference |" - echo "|---------|-------|---------------|" + echo "| Version | Guide | API Reference | Release Notes |" + echo "|---------|-------|---------------|---------------|" for ver in $(echo "${{ steps.discover-versions.outputs.versions }}" | tr ',' '\n' | sort -Vr); do if [ "$ver" = "$latest" ]; then label="v${ver} (latest)" else label="v${ver}" fi - echo "| ${label} | [Guide](${ver}/guide/getting-started.html) | [API Reference](${ver}/PolylineAlgorithm.html) |" + echo "| ${label} | [Guide](${ver}/guide/getting-started.html) | [API Reference](${ver}/PolylineAlgorithm.html) | [Release Notes](https://github.com/petesramek/polyline-algorithm-csharp/releases/tag/v${ver}) |" done } > /tmp/versions_section.md awk '/{versions_section}/{while((getline line < "/tmp/versions_section.md") > 0) print line; close("/tmp/versions_section.md"); next} {print}' \ diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 4f8917b0..c99f254d 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -18,8 +18,8 @@ permissions: id-token: write contents: write -concurrency: - group: pull-request-${{ github.head_ref || github.ref }} +concurrency: + group: pull-request-${{ github.head_ref || github.ref }} cancel-in-progress: true env: @@ -120,7 +120,7 @@ jobs: assembly-version: ${{ env.assembly-version }} assembly-informational-version: ${{ env.assembly-informational-version }} file-version: ${{ env.file-version }} - treat-warnins-as-error: ${{ needs.workflow-variables.outputs.is-release }} + treat-warnings-as-error: ${{ needs.workflow-variables.outputs.is-release }} test: name: 'Run tests' @@ -189,7 +189,7 @@ jobs: - name: Pack with .NET run: | dotnet pack ${{ vars.SRC_DEFAULT_GLOB_PATTERN }} --configuration ${{ env.build-configuration }} /p:Platform="${{ env.build-platform }}" /p:PackageVersion=${{ env.release-version }} /p:Version=${{ env.assembly-version }} /p:AssemblyInformationalVersion=${{ env.assembly-informational-version }} /p:FileVersion=${{ env.file-version }} --output ${{ runner.temp }}/${{ env.nuget-packages-directory }} - + - name: Upload Package uses: actions/upload-artifact@v7 with: @@ -222,39 +222,20 @@ jobs: nuget-feed-api-key: ${{ secrets.NUGET_PACKAGE_FEED_API_KEY }} nuget-feed-server: 'AzureArtifacts' working-directory: ${{ runner.temp }}/${{ env.nuget-packages-directory }} - dotnet-sdk-version: ${{ env.dotnet-sdk-version }}' + dotnet-sdk-version: ${{ env.dotnet-sdk-version }} - benchmark: - if: ${{ github.env.is_release || vars.BENCHMARKDOTNET_RUN_OVERRIDE == 'true' }} - name: Benchmark with .NET CLI on ${{ matrix.os }} + security: + name: 'Check for vulnerable packages' needs: [build] - strategy: - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest steps: - name: 'Checkout ${{ github.head_ref || github.ref }}' uses: actions/checkout@v6 - - name: Install .NET SDK + + - name: 'Setup .NET' uses: actions/setup-dotnet@v5 with: - dotnet-version: | - 8.x - 10.x - - name: Download Build - uses: actions/download-artifact@v8 - with: - name: build - - name: Benchmark - working-directory: ${{ vars.BENCHMARKDOTNET_WORKING_DIRECTORY }} - run: dotnet run --configuration ${{ env.build-configuration }} /p:Platform=${{ env.build-platform }} --framework ${{ vars.DEFAULT_BUILD_FRAMEWORK }} --runtimes ${{ vars.BENCHMARKDOTNET_RUNTIMES }} --filter ${{ vars.BENCHMARKDOTNET_FILTER }} --artifacts ${{ runner.temp }}/benchmarks/ --exporters GitHub --memory --iterationTime 100 --join - - name: Upload Benchmark Results - uses: actions/upload-artifact@v7 - with: - name: benchmark-${{ matrix.os }} - path: | - ${{ runner.temp }}/benchmarks/**/*-report-github.md - - name: Write Benchmark Summary - shell: bash - run: cat **/*-report-github.md > $GITHUB_STEP_SUMMARY - working-directory: ${{ runner.temp }}/benchmarks/ + dotnet-version: ${{ env.dotnet-sdk-version }} + + - name: 'Check for vulnerable packages' + run: dotnet list src/PolylineAlgorithm/PolylineAlgorithm.csproj package --vulnerable --include-transitive diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0d2808a8..b0bd5699 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -129,7 +129,7 @@ jobs: assembly-version: ${{ env.assembly-version }} assembly-informational-version: ${{ env.assembly-informational-version }} file-version: ${{ env.file-version }} - treat-warnins-as-error: ${{ needs.workflow-variables.outputs.is-release }} + treat-warnings-as-error: ${{ needs.workflow-variables.outputs.is-release }} test: name: 'Run tests' @@ -169,6 +169,89 @@ jobs: - name: Write code coverage report summary run: cat ${{ steps.code-coverage-report.outputs.code-coverage-report-file }} >> $GITHUB_STEP_SUMMARY + update-api-unshipped: + name: 'Update PublicAPI.Unshipped.txt' + needs: [workflow-variables, validate-release] + # Run even when build fails — the build may fail solely because a dropped preview API is still + # listed in Unshipped.txt (RS0017). This job fixes exactly that, so it must not be gated on build. + if: ${{ needs.workflow-variables.outputs.is-preview == 'true' && needs.validate-release.result == 'success' }} + runs-on: ubuntu-latest + steps: + - name: 'Checkout ${{ github.ref }}' + uses: actions/checkout@v6 + + - name: 'Setup .NET' + uses: actions/setup-dotnet@v5 + with: + dotnet-version: ${{ env.dotnet-sdk-version }} + + - name: 'Snapshot PublicAPI.Shipped.txt' + shell: bash + run: cp src/PolylineAlgorithm/PublicAPI.Shipped.txt src/PolylineAlgorithm/PublicAPI.Shipped.txt.bak + + - name: 'Sync PublicAPI.Unshipped.txt (add new + remove dropped preview APIs)' + shell: bash + run: dotnet format analyzers src/PolylineAlgorithm/PolylineAlgorithm.csproj --diagnostics RS0016 RS0017 + + - name: 'Guard against accidental shipped API removal' + shell: bash + run: | + SHIPPED="src/PolylineAlgorithm/PublicAPI.Shipped.txt" + if ! diff -q "$SHIPPED" "$SHIPPED.bak" > /dev/null 2>&1; then + echo "::error::Breaking change detected — a shipped API was removed from PublicAPI.Shipped.txt." + echo "::error::This requires a major version bump. Reverting the unintended change." + cp "$SHIPPED.bak" "$SHIPPED" + exit 1 + fi + rm -f "$SHIPPED.bak" + + - name: 'Configure git identity' + uses: './.github/actions/git/configure-identity' + + - name: 'Commit and push updated API files' + shell: bash + run: | + git add src/PolylineAlgorithm/PublicAPI.Unshipped.txt + git diff --staged --quiet || ( + git commit -m "Sync PublicAPI.Unshipped.txt (add new, remove dropped preview APIs)" && + git pull --rebase origin ${{ github.ref_name }} && + git push + ) + + promote-api-files: + name: 'Promote PublicAPI files (Unshipped -> Shipped)' + needs: [workflow-variables, test, validate-release] + if: ${{ needs.workflow-variables.outputs.is-release == 'true' }} + runs-on: ubuntu-latest + steps: + - name: 'Checkout ${{ github.ref }}' + uses: actions/checkout@v6 + + - name: 'Promote Unshipped.txt into Shipped.txt' + shell: bash + run: | + UNSHIPPED="src/PolylineAlgorithm/PublicAPI.Unshipped.txt" + SHIPPED="src/PolylineAlgorithm/PublicAPI.Shipped.txt" + + # Append every non-blank, non-header line from Unshipped into Shipped + tail -n +2 "$UNSHIPPED" | grep -v '^[[:space:]]*$' >> "$SHIPPED" || true + + # Reset Unshipped to just the nullable-enable header (with BOM to match convention) + printf '\xef\xbb\xbf#nullable enable\n' > "$UNSHIPPED" + + - name: 'Configure git identity' + uses: './.github/actions/git/configure-identity' + + - name: 'Commit and push promoted API files' + shell: bash + run: | + git add src/PolylineAlgorithm/PublicAPI.Shipped.txt src/PolylineAlgorithm/PublicAPI.Unshipped.txt + git diff --staged --quiet || ( + git commit -m "Promote PublicAPI.Unshipped.txt into PublicAPI.Shipped.txt for release" && + git pull --rebase origin ${{ github.ref_name }} && + git push + ) + pack: name: 'Package binaries' needs: [versioning, build, test, validate-release] @@ -207,9 +290,44 @@ jobs: ${{ runner.temp }}/${{ env.nuget-packages-directory }}/**/*.nupkg ${{ runner.temp }}/${{ env.nuget-packages-directory }}/**/*.snupkg + benchmark: + name: Benchmark with .NET CLI on ${{ matrix.os }} + needs: [workflow-variables, build, validate-release] + if: ${{ needs.workflow-variables.outputs.is-release == 'true' || vars.BENCHMARKDOTNET_RUN_OVERRIDE == 'true' }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - name: 'Checkout ${{ github.head_ref || github.ref }}' + uses: actions/checkout@v6 + - name: Install .NET SDK + uses: actions/setup-dotnet@v5 + with: + dotnet-version: | + 8.x + 10.x + - name: Download Build + uses: actions/download-artifact@v8 + with: + name: build + - name: Benchmark + working-directory: ${{ vars.BENCHMARKDOTNET_WORKING_DIRECTORY }} + run: dotnet run --configuration ${{ env.build-configuration }} /p:Platform=${{ env.build-platform }} --framework ${{ vars.DEFAULT_BUILD_FRAMEWORK }} --runtimes ${{ vars.BENCHMARKDOTNET_RUNTIMES }} --filter ${{ vars.BENCHMARKDOTNET_FILTER }} --artifacts ${{ runner.temp }}/benchmarks/ --exporters GitHub --memory --iterationTime 100 --join + - name: Upload Benchmark Results + uses: actions/upload-artifact@v7 + with: + name: benchmark-${{ matrix.os }} + path: | + ${{ runner.temp }}/benchmarks/**/*-report-github.md + - name: Write Benchmark Summary + shell: bash + run: cat **/*-report-github.md > $GITHUB_STEP_SUMMARY + working-directory: ${{ runner.temp }}/benchmarks/ + publish-documentation: name: 'Publish documentation' - needs: [pack, validate-release, workflow-variables] + needs: [pack, benchmark, validate-release, workflow-variables] if: ${{ needs.workflow-variables.outputs.is-release == 'true' }} uses: ./.github/workflows/publish-documentation.yml permissions: @@ -219,8 +337,14 @@ jobs: publish-package: name: 'Publish package' - needs: [pack, validate-release, publish-documentation] - if: ${{ always() && needs.pack.result == 'success' && needs.validate-release.result == 'success' && (needs.publish-documentation.result == 'success' || needs.publish-documentation.result == 'skipped') }} + needs: [pack, validate-release, publish-documentation, update-api-unshipped, promote-api-files] + if: | + always() && + needs.pack.result == 'success' && + needs.validate-release.result == 'success' && + (needs.publish-documentation.result == 'success' || needs.publish-documentation.result == 'skipped') && + (needs.promote-api-files.result == 'success' || needs.promote-api-files.result == 'skipped') && + (needs.update-api-unshipped.result == 'success' || needs.update-api-unshipped.result == 'skipped') env: package-artifact-name: ${{ needs.pack.outputs.package-artifact-name }} runs-on: ubuntu-latest @@ -272,9 +396,68 @@ jobs: is-preview: ${{ env.is-preview }} notes-start-tag: ${{ steps.determine-notes-start-tag.outputs.notes-start-tag }} + update-changelog: + name: 'Update CHANGELOG.md' + needs: [workflow-variables, release, versioning] + if: ${{ needs.workflow-variables.outputs.is-release == 'true' }} + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ github.token }} + release-version: ${{ needs.versioning.outputs.release-version }} + steps: + - name: 'Checkout ${{ github.ref }}' + uses: actions/checkout@v6 + with: + ref: ${{ github.ref }} + + - name: 'Fetch release notes' + shell: bash + run: | + gh release view ${{ env.release-version }} --json body --jq '.body' > /tmp/release-notes.txt + + - name: 'Prepend entry to CHANGELOG.md' + shell: bash + run: | + release_date=$(date -u +%Y-%m-%d) + { + echo "## ${{ env.release-version }} — ${release_date}" + echo "" + cat /tmp/release-notes.txt + echo "" + } > /tmp/new-entry.txt + awk ' + // { + print + print "" + while ((getline line < "/tmp/new-entry.txt") > 0) print line + close("/tmp/new-entry.txt") + next + } + { print } + ' CHANGELOG.md > /tmp/changelog-new.md + mv /tmp/changelog-new.md CHANGELOG.md + + - name: 'Configure git identity' + uses: './.github/actions/git/configure-identity' + + - name: 'Commit and push CHANGELOG.md' + shell: bash + run: | + git add CHANGELOG.md + git diff --staged --quiet || ( + git commit -m "Update CHANGELOG.md for ${{ env.release-version }}" && + git pull --rebase origin ${{ github.ref_name }} && + git push + ) + + - name: 'Write changelog summary' + shell: bash + run: | + echo "✅ CHANGELOG.md updated for **${{ env.release-version }}**." >> $GITHUB_STEP_SUMMARY + merge-to-main: name: 'Merge ${{ github.ref_name }} into main' - needs: [workflow-variables, release, versioning] + needs: [workflow-variables, release, versioning, update-changelog] if: ${{ needs.workflow-variables.outputs.is-release == 'true' }} runs-on: ubuntu-latest permissions: @@ -371,17 +554,10 @@ jobs: git checkout -b "${{ steps.resolve-support-branch.outputs.support-branch }}" git push --set-upstream origin "${{ steps.resolve-support-branch.outputs.support-branch }}" - - name: 'Lock support branch' - if: ${{ steps.check-support-branch.outputs.support-branch-exists == 'false' }} - uses: './.github/actions/github/branch-protection/lock' - with: - branch: ${{ steps.resolve-support-branch.outputs.support-branch }} - token: ${{ secrets.GH_ADMIN_TOKEN }} - - name: 'Write support branch summary' run: | if [[ "${{ steps.check-support-branch.outputs.support-branch-exists }}" == "false" ]]; then - echo "✅ Created and locked support branch **${{ steps.resolve-support-branch.outputs.support-branch }}**." >> $GITHUB_STEP_SUMMARY + echo "✅ Created support branch **${{ steps.resolve-support-branch.outputs.support-branch }}**." >> $GITHUB_STEP_SUMMARY else echo "⏭️ Support branch **${{ steps.resolve-support-branch.outputs.support-branch }}** already exists." >> $GITHUB_STEP_SUMMARY fi diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..9264cdaa --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and release notes are generated automatically from merged pull requests. + +See all releases at: + + diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..d0b9d1d8 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,47 @@ +# Contributor Covenant Code of Conduct + +## Our Commitment + +We are committed to providing a welcoming and inspiring community for all. We pledge to create an environment in which every individual feels valued, respected, and free from harassment and discrimination. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +- Using welcoming and inclusive language +- Being respectful of differing opinions, viewpoints, and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery and unwelcome sexual attention or advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting + +## Enforcement + +Community leaders are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Reporting + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the project maintainer responsible for enforcement. All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the reporter of any incident. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/Directory.Build.props b/Directory.Build.props index 96ebb124..80c3886e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -6,6 +6,8 @@ enable true en + true + embedded @@ -20,6 +22,7 @@ + diff --git a/PolylineAlgorithm.slnx b/PolylineAlgorithm.slnx index 29fa9445..3c54b2a7 100644 --- a/PolylineAlgorithm.slnx +++ b/PolylineAlgorithm.slnx @@ -7,6 +7,7 @@ + diff --git a/README.md b/README.md index 9dfb8a18..0555c16f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # PolylineAlgorithm for .NET -Lightweight .NET Standard 2.1 library implementing Google-compliant Encoded Polyline Algorithm with strong input validation, modern API patterns, and extensibility for custom coordinate types. +[![NuGet](https://img.shields.io/nuget/v/PolylineAlgorithm)](https://www.nuget.org/packages/PolylineAlgorithm) +[![Build](https://github.com/petesramek/polyline-algorithm-csharp/actions/workflows/build.yml/badge.svg)](https://github.com/petesramek/polyline-algorithm-csharp/actions/workflows/build.yml) +[![License: MIT](https://img.shields.io/github/license/petesramek/polyline-algorithm-csharp)](./LICENSE) + +Google's Encoded Polyline Algorithm compresses sequences of geographic coordinates into a compact ASCII string, widely used in mapping APIs. This library provides a fully compliant .NET implementation with extensible, type-safe encoding and decoding APIs. ## Table of Contents @@ -17,15 +21,16 @@ Lightweight .NET Standard 2.1 library implementing Google-compliant Encoded Poly ## Features - Fully compliant Google Encoded Polyline Algorithm for .NET Standard 2.1+ -- Extensible encoding and decoding APIs for custom coordinate and polyline types (`IPolylineEncoder`, `IPolylineDecoder`, `AbstractPolylineEncoder`, `AbstractPolylineDecoder`) -- Extension methods for encoding from `List` and arrays (`PolylineEncoderExtensions`) -- Robust input validation with descriptive exceptions for malformed/invalid data +- Extensible APIs — implement your own encoder/decoder for any coordinate or polyline type +- Robust input validation with descriptive exceptions for malformed or out-of-range data - Advanced configuration via `PolylineEncodingOptions` (precision, buffer size, logging) -- Logging and diagnostic support for CI/CD and developer diagnostics via `Microsoft.Extensions.Logging` -- Low-level utilities for normalization, validation, encoding and decoding via static `PolylineEncoding` class +- Extension methods for encoding directly from `List` and arrays +- Logging and diagnostic support via `Microsoft.Extensions.Logging` +- Low-level utilities for normalization, validation, and bit-level operations via static `PolylineEncoding` class +- Thread-safe, stateless APIs - Thorough unit tests and benchmarks for correctness and performance - Auto-generated API documentation ([API Reference](https://petesramek.github.io/polyline-algorithm-csharp/)) -- Support for .NET Core, .NET 5+, Xamarin, Unity, Blazor, and other platforms supporting `netstandard2.1` +- Supports .NET Core, .NET 5+, Xamarin, Unity, Blazor, and any platform targeting `netstandard2.1` ## Installation @@ -43,7 +48,19 @@ Install-Package PolylineAlgorithm ## Usage -The library provides abstract base classes to implement your own encoder and decoder for any coordinate and polyline type. +The library provides abstract base classes to implement your own encoder and decoder for any coordinate and polyline type. Inherit from `AbstractPolylineEncoder` or `AbstractPolylineDecoder`, override the coordinate accessors, then call `Encode` or `Decode`. + +### Quick Start + +```csharp +// 1. Implement a minimal encoder (see full example below) +var encoder = new MyPolylineEncoder(); +string encoded = encoder.Encode(coordinates); // e.g. "yseiHoc_MwacOjnwM" + +// 2. Implement a minimal decoder (see full example below) +var decoder = new MyPolylineDecoder(); +IEnumerable<(double Latitude, double Longitude)> decoded = decoder.Decode(encoded); +``` ### Custom encoder and decoder @@ -56,23 +73,9 @@ using PolylineAlgorithm; using PolylineAlgorithm.Abstraction; public sealed class MyPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - public MyPolylineEncoder() - : base() { } - - public MyPolylineEncoder(PolylineEncodingOptions options) - : base(options) { } - - protected override double GetLatitude((double Latitude, double Longitude) coordinate) { - return coordinate.Latitude; - } - - protected override double GetLongitude((double Latitude, double Longitude) coordinate) { - return coordinate.Longitude; - } - - protected override string CreatePolyline(ReadOnlyMemory polyline) { - return polyline.ToString(); - } + protected override double GetLatitude((double Latitude, double Longitude) coordinate) => coordinate.Latitude; + protected override double GetLongitude((double Latitude, double Longitude) coordinate) => coordinate.Longitude; + protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); } ``` @@ -102,19 +105,8 @@ using PolylineAlgorithm; using PolylineAlgorithm.Abstraction; public sealed class MyPolylineDecoder : AbstractPolylineDecoder { - public MyPolylineDecoder() - : base() { } - - public MyPolylineDecoder(PolylineEncodingOptions options) - : base(options) { } - - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) { - return (latitude, longitude); - } - - protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { - return polyline.AsMemory(); - } + protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); + protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); } ``` @@ -136,8 +128,13 @@ Full API docs and guides (auto-generated from source) are available at [API Refe ## Benchmarks -- See `/benchmarks` in the repo for performance evaluation. -- Contributors: Update benchmarks and document results for performance-impacting PRs. +- See [`/benchmarks`](./benchmarks) in the repo for benchmark projects. +- Run benchmarks with: + ```shell + dotnet run --project benchmarks/PolylineAlgorithm.Benchmarks --configuration Release + ``` +- For guidance on writing and interpreting benchmarks, see [docs/benchmarks.md](./docs/benchmarks.md). +- Contributors: update benchmarks and document results for performance-impacting PRs. ## FAQ @@ -173,13 +170,13 @@ A: Currently, only batch encode/decode is supported. For streaming scenarios, im ## Contributing -- Follow code style and PR instructions in [AGENTS.md](./AGENTS.md). +- Follow code style and PR instructions in [CONTRIBUTING.md](./CONTRIBUTING.md). - Ensure all features are covered by tests and XML doc comments. - For questions or suggestions, open an issue and use the provided templates. ## Support -Have a question, bug, or feature request? [Open an issue!](https://github.com/petesramek/polyline-algorithm-csharp/issues) +Have a question, bug, or feature request? [Open an issue](https://github.com/petesramek/polyline-algorithm-csharp/issues/new/choose) — bug report and feature request templates are available to guide you. --- diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..8ca1471a --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,23 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | --------- | +| Latest | ✅ | +| Older | ❌ | + +Only the latest published version receives security fixes. If you are on an older version, please upgrade. + +## Reporting a Vulnerability + +**Please do not open a public GitHub issue for security vulnerabilities.** + +Report security issues privately via [GitHub Security Advisories](https://github.com/petesramek/polyline-algorithm-csharp/security/advisories/new). + +Include: +- A description of the vulnerability +- Steps to reproduce or a proof-of-concept +- Potential impact assessment + +You can expect an initial response within 5 business days. Once confirmed, a fix will be prioritized and a patch release issued. You will be credited in the release notes unless you prefer to remain anonymous. diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml new file mode 100644 index 00000000..b5693066 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml @@ -0,0 +1,233 @@ +### YamlMime:ApiPage +title: Class AbstractPolylineDecoder +body: +- api1: Class AbstractPolylineDecoder + id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L22 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2 + commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2 +- facts: + - name: Namespace + value: + text: PolylineAlgorithm.Abstraction + url: PolylineAlgorithm.Abstraction.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates. +- code: 'public abstract class AbstractPolylineDecoder : IPolylineDecoder' +- h4: Type Parameters +- parameters: + - name: TPolyline + description: The type that represents the encoded polyline input. + - name: TCoordinate + description: The type that represents a decoded geographic coordinate. +- h4: Inheritance +- inheritance: + - text: object + url: https://learn.microsoft.com/dotnet/api/system.object + - text: AbstractPolylineDecoder + url: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.html +- h4: Implements +- list: + - text: IPolylineDecoder + url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html +- h4: Inherited Members +- list: + - text: object.Equals(object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - text: object.Equals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - text: object.GetHashCode() + url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - text: object.GetType() + url: https://learn.microsoft.com/dotnet/api/system.object.gettype + - text: object.MemberwiseClone() + url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone + - text: object.ReferenceEquals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - text: object.ToString() + url: https://learn.microsoft.com/dotnet/api/system.object.tostring +- h2: Remarks +- markdown: >- + Derive from this class to implement a decoder for a specific polyline type. Override + + and to provide type-specific behavior. +- h2: Constructors +- api3: AbstractPolylineDecoder() + id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L28 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor +- markdown: Initializes a new instance of the class with default encoding options. +- code: protected AbstractPolylineDecoder() +- api3: AbstractPolylineDecoder(PolylineEncodingOptions) + id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L40 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) +- markdown: Initializes a new instance of the class with the specified encoding options. +- code: protected AbstractPolylineDecoder(PolylineEncodingOptions options) +- h4: Parameters +- parameters: + - name: options + type: + - text: PolylineEncodingOptions + url: PolylineAlgorithm.PolylineEncodingOptions.html + description: The to use for encoding operations. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentNullException + url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception + description: Thrown when options is null. +- h2: Properties +- api3: Options + id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Options + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L54 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options + commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options +- markdown: Gets the encoding options used by this polyline decoder. +- code: public PolylineEncodingOptions Options { get; } +- h4: Property Value +- parameters: + - type: + - text: PolylineEncodingOptions + url: PolylineAlgorithm.PolylineEncodingOptions.html +- h2: Methods +- api3: CreateCoordinate(double, double) + id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_CreateCoordinate_System_Double_System_Double_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L202 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateCoordinate(System.Double,System.Double) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateCoordinate(System.Double,System.Double) +- markdown: Creates a TCoordinate instance from the specified latitude and longitude values. +- code: protected abstract TCoordinate CreateCoordinate(double latitude, double longitude) +- h4: Parameters +- parameters: + - name: latitude + type: + - text: double + url: https://learn.microsoft.com/dotnet/api/system.double + description: The latitude component of the coordinate, in degrees. + - name: longitude + type: + - text: double + url: https://learn.microsoft.com/dotnet/api/system.double + description: The longitude component of the coordinate, in degrees. +- h4: Returns +- parameters: + - type: + - TCoordinate + description: A TCoordinate instance representing the specified geographic coordinate. +- api3: Decode(TPolyline, CancellationToken) + id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L81 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) +- markdown: >- + Decodes an encoded TPolyline into a sequence of TCoordinate instances, + + with support for cancellation. +- code: public IEnumerable Decode(TPolyline polyline, CancellationToken cancellationToken = default) +- h4: Parameters +- parameters: + - name: polyline + type: + - TPolyline + description: The TPolyline instance containing the encoded polyline string to decode. + - name: cancellationToken + type: + - text: CancellationToken + url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken + description: A that can be used to cancel the decoding operation. + optional: true +- h4: Returns +- parameters: + - type: + - text: IEnumerable + url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 + - < + - TCoordinate + - '>' + description: An of TCoordinate representing the decoded latitude and longitude pairs. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentNullException + url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception + description: Thrown when polyline is null. + - type: + - text: ArgumentException + url: https://learn.microsoft.com/dotnet/api/system.argumentexception + description: Thrown when polyline is empty. + - type: + - text: InvalidPolylineException + url: PolylineAlgorithm.InvalidPolylineException.html + description: Thrown when the polyline format is invalid or malformed at a specific position. + - type: + - text: OperationCanceledException + url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception + description: Thrown when cancellationToken is canceled during decoding. +- api3: GetReadOnlyMemory(in TPolyline) + id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_GetReadOnlyMemory__0__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L187 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@) +- markdown: Extracts the underlying read-only memory region of characters from the specified polyline instance. +- code: protected abstract ReadOnlyMemory GetReadOnlyMemory(in TPolyline polyline) +- h4: Parameters +- parameters: + - name: polyline + type: + - TPolyline + description: The TPolyline instance from which to extract the character sequence. +- h4: Returns +- parameters: + - type: + - text: ReadOnlyMemory + url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + description: A of representing the encoded polyline characters. +- api3: ValidateFormat(ReadOnlyMemory, ILogger?) + id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_ValidateFormat_System_ReadOnlyMemory_System_Char__Microsoft_Extensions_Logging_ILogger_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L167 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger) +- markdown: Validates the format of the polyline character sequence, ensuring all characters are within the allowed range. +- code: protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? logger) +- h4: Parameters +- parameters: + - name: sequence + type: + - text: ReadOnlyMemory + url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + description: The read-only memory region of characters representing the polyline to validate. + - name: logger + type: + - text: ILogger + url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger + - '?' + description: An optional used to log a warning when format validation fails. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentException + url: https://learn.microsoft.com/dotnet/api/system.argumentexception + description: Thrown when the polyline contains characters outside the valid encoding range or has an invalid block structure. +languageId: csharp +metadata: + description: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates. diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml new file mode 100644 index 00000000..64e97b11 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml @@ -0,0 +1,219 @@ +### YamlMime:ApiPage +title: Class AbstractPolylineEncoder +body: +- api1: Class AbstractPolylineEncoder + id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L27 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2 + commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2 +- facts: + - name: Namespace + value: + text: PolylineAlgorithm.Abstraction + url: PolylineAlgorithm.Abstraction.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings. +- code: 'public abstract class AbstractPolylineEncoder : IPolylineEncoder' +- h4: Type Parameters +- parameters: + - name: TCoordinate + description: The type that represents a geographic coordinate to encode. + - name: TPolyline + description: The type that represents the encoded polyline output. +- h4: Inheritance +- inheritance: + - text: object + url: https://learn.microsoft.com/dotnet/api/system.object + - text: AbstractPolylineEncoder + url: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.html +- h4: Implements +- list: + - text: IPolylineEncoder + url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html +- h4: Inherited Members +- list: + - text: object.Equals(object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - text: object.Equals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - text: object.GetHashCode() + url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - text: object.GetType() + url: https://learn.microsoft.com/dotnet/api/system.object.gettype + - text: object.MemberwiseClone() + url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone + - text: object.ReferenceEquals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - text: object.ToString() + url: https://learn.microsoft.com/dotnet/api/system.object.tostring +- h4: Extension Methods +- list: + - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, List) + url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__ + - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, TCoordinate[]) + url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___ +- h2: Remarks +- markdown: >- + Derive from this class to implement an encoder for a specific coordinate and polyline type. Override + + , , and to provide type-specific behavior. +- h2: Constructors +- api3: AbstractPolylineEncoder() + id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L33 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor +- markdown: Initializes a new instance of the class with default encoding options. +- code: protected AbstractPolylineEncoder() +- api3: AbstractPolylineEncoder(PolylineEncodingOptions) + id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L43 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) +- markdown: Initializes a new instance of the class with the specified encoding options. +- code: protected AbstractPolylineEncoder(PolylineEncodingOptions options) +- h4: Parameters +- parameters: + - name: options + type: + - text: PolylineEncodingOptions + url: PolylineAlgorithm.PolylineEncodingOptions.html + description: The to use for encoding operations. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentNullException + url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception + description: Thrown when options is null +- h2: Properties +- api3: Options + id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Options + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L57 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options + commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options +- markdown: Gets the encoding options used by this polyline encoder. +- code: public PolylineEncodingOptions Options { get; } +- h4: Property Value +- parameters: + - type: + - text: PolylineEncodingOptions + url: PolylineAlgorithm.PolylineEncodingOptions.html +- h2: Methods +- api3: CreatePolyline(ReadOnlyMemory) + id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_CreatePolyline_System_ReadOnlyMemory_System_Char__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L174 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char}) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char}) +- markdown: Creates a polyline instance from the provided read-only sequence of characters. +- code: protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline) +- h4: Parameters +- parameters: + - name: polyline + type: + - text: ReadOnlyMemory + url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + description: A containing the encoded polyline characters. +- h4: Returns +- parameters: + - type: + - TPolyline + description: An instance of TPolyline representing the encoded polyline. +- api3: Encode(ReadOnlySpan, CancellationToken) + id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L80 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) +- markdown: Encodes a collection of TCoordinate instances into an encoded TPolyline string. +- code: >- + [SuppressMessage("Design", "MA0051:Method is too long", Justification = "Method contains local methods. Actual method only 55 lines.")] + + public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default) +- h4: Parameters +- parameters: + - name: coordinates + type: + - text: ReadOnlySpan + url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 + - < + - TCoordinate + - '>' + description: The collection of TCoordinate objects to encode. + - name: cancellationToken + type: + - text: CancellationToken + url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken + description: A that can be used to cancel the encoding operation. + optional: true +- h4: Returns +- parameters: + - type: + - TPolyline + description: An instance of TPolyline representing the encoded coordinates. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentNullException + url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception + description: Thrown when coordinates is null. + - type: + - text: ArgumentException + url: https://learn.microsoft.com/dotnet/api/system.argumentexception + description: Thrown when coordinates is an empty enumeration. + - type: + - text: InvalidOperationException + url: https://learn.microsoft.com/dotnet/api/system.invalidoperationexception + description: Thrown when the internal encoding buffer cannot accommodate the encoded value. +- api3: GetLatitude(TCoordinate) + id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetLatitude__0_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L194 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLatitude(`0) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLatitude(`0) +- markdown: Extracts the latitude value from the specified coordinate. +- code: protected abstract double GetLatitude(TCoordinate current) +- h4: Parameters +- parameters: + - name: current + type: + - TCoordinate + description: The coordinate from which to extract the latitude. +- h4: Returns +- parameters: + - type: + - text: double + url: https://learn.microsoft.com/dotnet/api/system.double + description: The latitude value as a . +- api3: GetLongitude(TCoordinate) + id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetLongitude__0_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L184 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLongitude(`0) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLongitude(`0) +- markdown: Extracts the longitude value from the specified coordinate. +- code: protected abstract double GetLongitude(TCoordinate current) +- h4: Parameters +- parameters: + - name: current + type: + - TCoordinate + description: The coordinate from which to extract the longitude. +- h4: Returns +- parameters: + - type: + - text: double + url: https://learn.microsoft.com/dotnet/api/system.double + description: The longitude value as a . +languageId: csharp +metadata: + description: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings. diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml new file mode 100644 index 00000000..733987cb --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml @@ -0,0 +1,90 @@ +### YamlMime:ApiPage +title: Interface IPolylineDecoder +body: +- api1: Interface IPolylineDecoder + id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L22 + metadata: + uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2 + commentId: T:PolylineAlgorithm.Abstraction.IPolylineDecoder`2 +- facts: + - name: Namespace + value: + text: PolylineAlgorithm.Abstraction + url: PolylineAlgorithm.Abstraction.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates. +- code: public interface IPolylineDecoder +- h4: Type Parameters +- parameters: + - name: TPolyline + description: >- + The type that represents the encoded polyline input. Common implementations use , + + but custom wrapper types are allowed to carry additional metadata. + - name: TValue + description: >- + The coordinate type returned by the decoder. Typical implementations return a struct or class that + + contains latitude and longitude (for example a LatLng type or a ValueTuple<double,double>). +- h2: Methods +- api3: Decode(TPolyline, CancellationToken) + id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L48 + metadata: + uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) + commentId: M:PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) +- markdown: >- + Decodes the specified encoded polyline into an ordered sequence of geographic coordinates. + + The sequence preserves the original vertex order encoded by the polyline. +- code: IEnumerable Decode(TPolyline polyline, CancellationToken cancellationToken = default) +- h4: Parameters +- parameters: + - name: polyline + type: + - TPolyline + description: >- + The TPolyline instance containing the encoded polyline to decode. + + Implementations SHOULD validate the input and may throw + + or for invalid formats. + - name: cancellationToken + type: + - text: CancellationToken + url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken + description: >- + A to observe while decoding. If cancellation is requested, + + implementations SHOULD stop work and throw an . + optional: true +- h4: Returns +- parameters: + - type: + - text: IEnumerable + url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 + - < + - TValue + - '>' + description: >- + An of TValue representing the decoded + + latitude/longitude pairs (or equivalent coordinates) in the same order they were encoded. +- h4: Remarks +- markdown: >- + Implementations commonly follow the Google Encoded Polyline Algorithm Format, but this interface + + does not mandate a specific encoding. Consumers should rely on a concrete decoder's documentation + + to understand the exact encoding supported. +- h4: Exceptions +- parameters: + - type: + - text: OperationCanceledException + url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception + description: Thrown when the provided cancellationToken requests cancellation. +languageId: csharp +metadata: + description: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates. diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml new file mode 100644 index 00000000..341a9de7 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml @@ -0,0 +1,142 @@ +### YamlMime:ApiPage +title: Interface IPolylineEncoder +body: +- api1: Interface IPolylineEncoder + id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L36 + metadata: + uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2 + commentId: T:PolylineAlgorithm.Abstraction.IPolylineEncoder`2 +- facts: + - name: Namespace + value: + text: PolylineAlgorithm.Abstraction + url: PolylineAlgorithm.Abstraction.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: >- + Contract for encoding a sequence of geographic coordinates into an encoded polyline representation. + + Implementations interpret the generic TValue type and produce an encoded + + representation of those coordinates as TPolyline. +- code: public interface IPolylineEncoder +- h4: Type Parameters +- parameters: + - name: TValue + description: >- + The concrete coordinate representation used by the encoder (for example a struct or class containing + + Latitude and Longitude values). Implementations must document the expected shape, + + units (typically decimal degrees), and any required fields for TValue. + + Common shapes: + + - A struct or class with two double properties named Latitude and Longitude. + + - A tuple-like type (for example ValueTuple<double,double>) where the encoder documents + which element represents latitude and longitude. + - name: TPolyline + description: >- + The encoded polyline representation returned by the encoder (for example string, + + ReadOnlyMemory<char>, or a custom wrapper type). Concrete implementations should document + + the chosen representation and any memory / ownership expectations. +- h4: Extension Methods +- list: + - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, List) + url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__ + - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, TValue[]) + url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___ +- h2: Remarks +- markdown: >- + - This interface is intentionally minimal to allow different encoding strategies (Google encoded polyline, + precision/scale variants, or custom compressed formats) to be expressed behind a common contract. + - Implementations should document: + - Coordinate precision and rounding rules (for example 1e-5 for 5-decimal precision). + - Coordinate ordering and whether altitude or additional dimensions are supported. + - Thread-safety guarantees: whether instances are safe to reuse concurrently or must be instantiated per-call. + - Implementations are encouraged to be memory-efficient; the API accepts a + to avoid forced allocations when callers already have contiguous memory. +- h2: Methods +- api3: Encode(ReadOnlySpan, CancellationToken) + id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L76 + metadata: + uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) + commentId: M:PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) +- markdown: >- + Encodes a sequence of geographic coordinates into an encoded polyline representation. + + The order of coordinates in coordinates is preserved in the encoded result. +- code: TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default) +- h4: Parameters +- parameters: + - name: coordinates + type: + - text: ReadOnlySpan + url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 + - < + - TValue + - '>' + description: >- + The collection of TValue instances to encode into a polyline. + + The span may be empty; implementations should return an appropriate empty encoded representation + + (for example an empty string or an empty memory slice) rather than null. + - name: cancellationToken + type: + - text: CancellationToken + url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken + description: >- + A that can be used to cancel the encoding operation. + + Implementations should observe this token and throw + + when cancellation is requested. For fast, in-memory encoders cancellation may be best-effort. + optional: true +- h4: Returns +- parameters: + - type: + - TPolyline + description: >- + A TPolyline containing the encoded polyline that represents the input coordinates. + + The exact format and any delimiting/terminating characters are implementation-specific and must be + + documented by concrete encoder types. +- h4: Examples +- markdown: >- +
// Example pseudocode for typical usage with a string-based encoder:
+
+    var coords = new[] {
+        new Coordinate { Latitude = 47.6219, Longitude = -122.3503 },
+        new Coordinate { Latitude = 47.6220, Longitude = -122.3504 }
+    };
+
+    IPolylineEncoder<Coordinate,string> encoder = new GoogleEncodedPolylineEncoder();
+
+    string encoded = encoder.Encode(coords, CancellationToken.None);
+- h4: Remarks +- markdown: >- + - Implementations should validate input as appropriate and document any preconditions (for example + if coordinates must be within [-90,90] latitude and [-180,180] longitude). + - For large input sequences, implementations may provide streaming or incremental encoders; those + variants can still implement this interface by materializing the final encoded result. +- h4: Exceptions +- parameters: + - type: + - text: OperationCanceledException + url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception + description: Thrown if the operation is canceled via cancellationToken. +languageId: csharp +metadata: + description: >- + Contract for encoding a sequence of geographic coordinates into an encoded polyline representation. + + Implementations interpret the generic TValue type and produce an encoded + + representation of those coordinates as TPolyline. diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.yml new file mode 100644 index 00000000..e9de48f7 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.yml @@ -0,0 +1,34 @@ +### YamlMime:ApiPage +title: Namespace PolylineAlgorithm.Abstraction +body: +- api1: Namespace PolylineAlgorithm.Abstraction + id: PolylineAlgorithm_Abstraction + metadata: + uid: PolylineAlgorithm.Abstraction + commentId: N:PolylineAlgorithm.Abstraction +- h3: Classes +- parameters: + - type: + text: AbstractPolylineDecoder + url: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.html + description: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates. + - type: + text: AbstractPolylineEncoder + url: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.html + description: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings. +- h3: Interfaces +- parameters: + - type: + text: IPolylineDecoder + url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html + description: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates. + - type: + text: IPolylineEncoder + url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html + description: >- + Contract for encoding a sequence of geographic coordinates into an encoded polyline representation. + + Implementations interpret the generic TValue type and produce an encoded + + representation of those coordinates as TPolyline. +languageId: csharp diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml new file mode 100644 index 00000000..8356b63c --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml @@ -0,0 +1,195 @@ +### YamlMime:ApiPage +title: Class PolylineDecoderExtensions +body: +- api1: Class PolylineDecoderExtensions + id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L16 + metadata: + uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions + commentId: T:PolylineAlgorithm.Extensions.PolylineDecoderExtensions +- facts: + - name: Namespace + value: + text: PolylineAlgorithm.Extensions + url: PolylineAlgorithm.Extensions.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: Provides extension methods for the interface to facilitate decoding encoded polylines. +- code: public static class PolylineDecoderExtensions +- h4: Inheritance +- inheritance: + - text: object + url: https://learn.microsoft.com/dotnet/api/system.object + - text: PolylineDecoderExtensions + url: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.html +- h4: Inherited Members +- list: + - text: object.Equals(object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - text: object.Equals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - text: object.GetHashCode() + url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - text: object.GetType() + url: https://learn.microsoft.com/dotnet/api/system.object.gettype + - text: object.MemberwiseClone() + url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone + - text: object.ReferenceEquals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - text: object.ToString() + url: https://learn.microsoft.com/dotnet/api/system.object.tostring +- h2: Methods +- api3: Decode(IPolylineDecoder, char[]) + id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_String___0__System_Char___ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L33 + metadata: + uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.Char[]) + commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.Char[]) +- markdown: Decodes an encoded polyline represented as a character array into a sequence of geographic coordinates. +- code: public static IEnumerable Decode(this IPolylineDecoder decoder, char[] polyline) +- h4: Parameters +- parameters: + - name: decoder + type: + - text: IPolylineDecoder + url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html + - < + - text: string + url: https://learn.microsoft.com/dotnet/api/system.string + - ',' + - " " + - TValue + - '>' + description: The instance used to perform the decoding operation. + - name: polyline + type: + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '[' + - ']' + description: The encoded polyline as a character array to decode. The array is converted to a string internally. +- h4: Returns +- parameters: + - type: + - text: IEnumerable + url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 + - < + - TValue + - '>' + description: An of TValue containing the decoded coordinate pairs. +- h4: Type Parameters +- parameters: + - name: TValue + description: The coordinate type returned by the decoder. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentNullException + url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception + description: Thrown when decoder or polyline is null. +- api3: Decode(IPolylineDecoder, ReadOnlyMemory) + id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_String___0__System_ReadOnlyMemory_System_Char__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L61 + metadata: + uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.ReadOnlyMemory{System.Char}) + commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.ReadOnlyMemory{System.Char}) +- markdown: Decodes an encoded polyline represented as a read-only memory of characters into a sequence of geographic coordinates. +- code: public static IEnumerable Decode(this IPolylineDecoder decoder, ReadOnlyMemory polyline) +- h4: Parameters +- parameters: + - name: decoder + type: + - text: IPolylineDecoder + url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html + - < + - text: string + url: https://learn.microsoft.com/dotnet/api/system.string + - ',' + - " " + - TValue + - '>' + description: The instance used to perform the decoding operation. + - name: polyline + type: + - text: ReadOnlyMemory + url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + description: The encoded polyline as a read-only memory of characters to decode. The memory is converted to a string internally. +- h4: Returns +- parameters: + - type: + - text: IEnumerable + url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 + - < + - TValue + - '>' + description: An of TValue containing the decoded coordinate pairs. +- h4: Type Parameters +- parameters: + - name: TValue + description: The coordinate type returned by the decoder. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentNullException + url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception + description: Thrown when decoder is null. +- api3: Decode(IPolylineDecoder, TValue>, string) + id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_ReadOnlyMemory_System_Char____0__System_String_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L86 + metadata: + uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.ReadOnlyMemory{System.Char},``0},System.String) + commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.ReadOnlyMemory{System.Char},``0},System.String) +- markdown: >- + Decodes an encoded polyline string into a sequence of geographic coordinates, + + using a decoder that accepts of . +- code: public static IEnumerable Decode(this IPolylineDecoder, TValue> decoder, string polyline) +- h4: Parameters +- parameters: + - name: decoder + type: + - text: IPolylineDecoder + url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html + - < + - text: ReadOnlyMemory + url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + - ',' + - " " + - TValue + - '>' + description: The instance used to perform the decoding operation. + - name: polyline + type: + - text: string + url: https://learn.microsoft.com/dotnet/api/system.string + description: The encoded polyline string to decode. The string is converted to internally. +- h4: Returns +- parameters: + - type: + - text: IEnumerable + url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 + - < + - TValue + - '>' + description: An of TValue containing the decoded coordinate pairs. +- h4: Type Parameters +- parameters: + - name: TValue + description: The coordinate type returned by the decoder. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentNullException + url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception + description: Thrown when decoder or polyline is null. +languageId: csharp +metadata: + description: Provides extension methods for the interface to facilitate decoding encoded polylines. diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml new file mode 100644 index 00000000..e5296518 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml @@ -0,0 +1,139 @@ +### YamlMime:ApiPage +title: Class PolylineEncoderExtensions +body: +- api1: Class PolylineEncoderExtensions + id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L19 + metadata: + uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions + commentId: T:PolylineAlgorithm.Extensions.PolylineEncoderExtensions +- facts: + - name: Namespace + value: + text: PolylineAlgorithm.Extensions + url: PolylineAlgorithm.Extensions.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines. +- code: public static class PolylineEncoderExtensions +- h4: Inheritance +- inheritance: + - text: object + url: https://learn.microsoft.com/dotnet/api/system.object + - text: PolylineEncoderExtensions + url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html +- h4: Inherited Members +- list: + - text: object.Equals(object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - text: object.Equals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - text: object.GetHashCode() + url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - text: object.GetType() + url: https://learn.microsoft.com/dotnet/api/system.object.gettype + - text: object.MemberwiseClone() + url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone + - text: object.ReferenceEquals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - text: object.ToString() + url: https://learn.microsoft.com/dotnet/api/system.object.tostring +- h2: Methods +- api3: Encode(IPolylineEncoder, List) + id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L37 + metadata: + uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},System.Collections.Generic.List{``0}) + commentId: M:PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},System.Collections.Generic.List{``0}) +- markdown: Encodes a of TCoordinate instances into an encoded polyline. +- code: >- + [SuppressMessage("Design", "CA1002:Do not expose generic lists", Justification = "We need a list as we do need to marshal it as span.")] + + [SuppressMessage("Design", "MA0016:Prefer using collection abstraction instead of implementation", Justification = "We need a list as we do need to marshal it as span.")] + + public static TPolyline Encode(this IPolylineEncoder encoder, List coordinates) +- h4: Parameters +- parameters: + - name: encoder + type: + - text: IPolylineEncoder + url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html + - < + - TCoordinate + - ',' + - " " + - TPolyline + - '>' + description: The instance used to perform the encoding operation. + - name: coordinates + type: + - text: List + url: https://learn.microsoft.com/dotnet/api/system.collections.generic.list-1 + - < + - TCoordinate + - '>' + description: The list of TCoordinate objects to encode. +- h4: Returns +- parameters: + - type: + - TPolyline + description: A TPolyline instance representing the encoded polyline for the provided coordinates. +- h4: Type Parameters +- parameters: + - name: TCoordinate + description: The type that represents a geographic coordinate to encode. + - name: TPolyline + description: The type that represents the encoded polyline output. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentNullException + url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception + description: Thrown when encoder or coordinates is null. +- api3: Encode(IPolylineEncoder, TCoordinate[]) + id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L73 + metadata: + uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},``0[]) + commentId: M:PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},``0[]) +- markdown: Encodes an array of TCoordinate instances into an encoded polyline. +- code: public static TPolyline Encode(this IPolylineEncoder encoder, TCoordinate[] coordinates) +- h4: Parameters +- parameters: + - name: encoder + type: + - text: IPolylineEncoder + url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html + - < + - TCoordinate + - ',' + - " " + - TPolyline + - '>' + description: The instance used to perform the encoding operation. + - name: coordinates + type: + - TCoordinate + - '[' + - ']' + description: The array of TCoordinate objects to encode. +- h4: Returns +- parameters: + - type: + - TPolyline + description: A TPolyline instance representing the encoded polyline for the provided coordinates. +- h4: Type Parameters +- parameters: + - name: TCoordinate + description: The type that represents a geographic coordinate to encode. + - name: TPolyline + description: The type that represents the encoded polyline output. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentNullException + url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception + description: Thrown when encoder or coordinates is null. +languageId: csharp +metadata: + description: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines. diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.yml new file mode 100644 index 00000000..c39da0ca --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Extensions.yml @@ -0,0 +1,19 @@ +### YamlMime:ApiPage +title: Namespace PolylineAlgorithm.Extensions +body: +- api1: Namespace PolylineAlgorithm.Extensions + id: PolylineAlgorithm_Extensions + metadata: + uid: PolylineAlgorithm.Extensions + commentId: N:PolylineAlgorithm.Extensions +- h3: Classes +- parameters: + - type: + text: PolylineDecoderExtensions + url: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.html + description: Provides extension methods for the interface to facilitate decoding encoded polylines. + - type: + text: PolylineEncoderExtensions + url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html + description: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines. +languageId: csharp diff --git a/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml b/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml new file mode 100644 index 00000000..2c4e3cc1 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml @@ -0,0 +1,102 @@ +### YamlMime:ApiPage +title: Class InvalidPolylineException +body: +- api1: Class InvalidPolylineException + id: PolylineAlgorithm_InvalidPolylineException + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/InvalidPolylineException.cs#L17 + metadata: + uid: PolylineAlgorithm.InvalidPolylineException + commentId: T:PolylineAlgorithm.InvalidPolylineException +- facts: + - name: Namespace + value: + text: PolylineAlgorithm + url: PolylineAlgorithm.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: Exception thrown when a polyline is determined to be malformed or invalid during processing. +- code: 'public sealed class InvalidPolylineException : Exception, ISerializable' +- h4: Inheritance +- inheritance: + - text: object + url: https://learn.microsoft.com/dotnet/api/system.object + - text: Exception + url: https://learn.microsoft.com/dotnet/api/system.exception + - text: InvalidPolylineException + url: PolylineAlgorithm.InvalidPolylineException.html +- h4: Implements +- list: + - text: ISerializable + url: https://learn.microsoft.com/dotnet/api/system.runtime.serialization.iserializable +- h4: Inherited Members +- list: + - text: Exception.GetBaseException() + url: https://learn.microsoft.com/dotnet/api/system.exception.getbaseexception + - text: Exception.GetObjectData(SerializationInfo, StreamingContext) + url: https://learn.microsoft.com/dotnet/api/system.exception.getobjectdata + - text: Exception.GetType() + url: https://learn.microsoft.com/dotnet/api/system.exception.gettype + - text: Exception.ToString() + url: https://learn.microsoft.com/dotnet/api/system.exception.tostring + - text: Exception.Data + url: https://learn.microsoft.com/dotnet/api/system.exception.data + - text: Exception.HelpLink + url: https://learn.microsoft.com/dotnet/api/system.exception.helplink + - text: Exception.HResult + url: https://learn.microsoft.com/dotnet/api/system.exception.hresult + - text: Exception.InnerException + url: https://learn.microsoft.com/dotnet/api/system.exception.innerexception + - text: Exception.Message + url: https://learn.microsoft.com/dotnet/api/system.exception.message + - text: Exception.Source + url: https://learn.microsoft.com/dotnet/api/system.exception.source + - text: Exception.StackTrace + url: https://learn.microsoft.com/dotnet/api/system.exception.stacktrace + - text: Exception.TargetSite + url: https://learn.microsoft.com/dotnet/api/system.exception.targetsite + - text: object.Equals(object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - text: object.Equals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - text: object.GetHashCode() + url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - text: object.GetType() + url: https://learn.microsoft.com/dotnet/api/system.object.gettype + - text: object.ReferenceEquals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - text: object.ToString() + url: https://learn.microsoft.com/dotnet/api/system.object.tostring +- h2: Remarks +- markdown: This exception is used internally to indicate that a polyline string does not conform to the expected format or contains errors. +- h2: Constructors +- api3: InvalidPolylineException() + id: PolylineAlgorithm_InvalidPolylineException__ctor + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/InvalidPolylineException.cs#L22 + metadata: + uid: PolylineAlgorithm.InvalidPolylineException.#ctor + commentId: M:PolylineAlgorithm.InvalidPolylineException.#ctor +- markdown: Initializes a new instance of the class. +- code: public InvalidPolylineException() +- api3: InvalidPolylineException(string, Exception) + id: PolylineAlgorithm_InvalidPolylineException__ctor_System_String_System_Exception_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/InvalidPolylineException.cs#L43 + metadata: + uid: PolylineAlgorithm.InvalidPolylineException.#ctor(System.String,System.Exception) + commentId: M:PolylineAlgorithm.InvalidPolylineException.#ctor(System.String,System.Exception) +- markdown: Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. +- code: public InvalidPolylineException(string message, Exception innerException) +- h4: Parameters +- parameters: + - name: message + type: + - text: string + url: https://learn.microsoft.com/dotnet/api/system.string + description: The error message that explains the reason for the exception. + - name: innerException + type: + - text: Exception + url: https://learn.microsoft.com/dotnet/api/system.exception + description: The exception that is the cause of the current exception, or a null reference if no inner exception is specified. +languageId: csharp +metadata: + description: Exception thrown when a polyline is determined to be malformed or invalid during processing. diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml new file mode 100644 index 00000000..1add8147 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml @@ -0,0 +1,529 @@ +### YamlMime:ApiPage +title: Class PolylineEncoding +body: +- api1: Class PolylineEncoding + id: PolylineAlgorithm_PolylineEncoding + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L23 + metadata: + uid: PolylineAlgorithm.PolylineEncoding + commentId: T:PolylineAlgorithm.PolylineEncoding +- facts: + - name: Namespace + value: + text: PolylineAlgorithm + url: PolylineAlgorithm.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: >- + Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing + + geographic coordinate values. +- code: public static class PolylineEncoding +- h4: Inheritance +- inheritance: + - text: object + url: https://learn.microsoft.com/dotnet/api/system.object + - text: PolylineEncoding + url: PolylineAlgorithm.PolylineEncoding.html +- h4: Inherited Members +- list: + - text: object.Equals(object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - text: object.Equals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - text: object.GetHashCode() + url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - text: object.GetType() + url: https://learn.microsoft.com/dotnet/api/system.object.gettype + - text: object.MemberwiseClone() + url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone + - text: object.ReferenceEquals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - text: object.ToString() + url: https://learn.microsoft.com/dotnet/api/system.object.tostring +- h2: Remarks +- markdown: >- + The class includes functionality for working with encoded polyline + data, such as reading and writing encoded values, as well as methods for normalizing and de-normalizing geographic + coordinates. It also provides validation utilities to ensure values conform to expected ranges for latitude and + longitude. +- h2: Methods +- api3: Denormalize(int, uint) + id: PolylineAlgorithm_PolylineEncoding_Denormalize_System_Int32_System_UInt32_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L122 + metadata: + uid: PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32) + commentId: M:PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32) +- markdown: Converts a normalized integer coordinate value back to its floating-point representation based on the specified precision. +- code: public static double Denormalize(int value, uint precision = 5) +- h4: Parameters +- parameters: + - name: value + type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + description: The integer value to denormalize. Typically produced by the method. + - name: precision + type: + - text: uint + url: https://learn.microsoft.com/dotnet/api/system.uint32 + description: The number of decimal places used during normalization. Default is 5, matching standard polyline encoding precision. + optional: true +- h4: Returns +- parameters: + - type: + - text: double + url: https://learn.microsoft.com/dotnet/api/system.double + description: The denormalized floating-point coordinate value. +- h4: Remarks +- markdown: >- +

+ + This method reverses the normalization performed by . It takes an integer value and converts it + + to a double by dividing it by 10 raised to the power of the specified precision. If precision is 0, + + the value is returned as a double without division. + +

+ +

+ + The calculation is performed inside a checked block to ensure that any arithmetic overflow is detected + + and an is thrown. + +

+ +

+ + For example, with a precision of 5: + + +

  • A value of 3778903 becomes 37.78903
  • A value of -12241230 becomes -122.4123
+ +

+ +

+ + If the input value is 0, the method returns 0.0 immediately. + +

+- h4: Exceptions +- parameters: + - type: + - text: OverflowException + url: https://learn.microsoft.com/dotnet/api/system.overflowexception + description: Thrown if the arithmetic operation overflows during conversion. +- api3: GetRequiredBufferSize(int) + id: PolylineAlgorithm_PolylineEncoding_GetRequiredBufferSize_System_Int32_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L298 + metadata: + uid: PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32) + commentId: M:PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32) +- markdown: Calculates the number of characters required to encode a delta value in polyline format. +- code: public static int GetRequiredBufferSize(int delta) +- h4: Parameters +- parameters: + - name: delta + type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + description: >- + The integer delta value to calculate the encoded size for. This value typically represents the difference between + + consecutive coordinate values in polyline encoding. +- h4: Returns +- parameters: + - type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + description: The number of characters required to encode the specified delta value. The minimum return value is 1. +- h4: Remarks +- markdown: >- +

+ + This method determines how many characters will be needed to represent an integer delta value when encoded + + using the polyline encoding algorithm. It performs the same zigzag encoding transformation as + + but only calculates the required buffer size without actually writing any data. + +

+ +

+ + The calculation process: + + +

  1. Applies zigzag encoding: left-shifts the value by 1 bit, then inverts all bits if the original value was negative
  2. Counts how many 5-bit chunks are needed to represent the encoded value
  3. Each chunk requires one character, with a minimum of 1 character for any value
+ +

+ +

+ + This method is useful for pre-allocating buffers of the correct size before encoding polyline data, helping to avoid + + buffer overflow checks during the actual encoding process. + +

+ +

+ + The method uses a long internally to prevent overflow during the left-shift operation on large negative values. + +

+- h4: See Also +- list: + - - text: PolylineEncoding + url: PolylineAlgorithm.PolylineEncoding.html + - . + - text: TryWriteValue + url: PolylineAlgorithm.PolylineEncoding.html#PolylineAlgorithm_PolylineEncoding_TryWriteValue_System_Int32_System_Span_System_Char__System_Int32__ + - ( + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + - ',' + - " " + - text: Span + url: https://learn.microsoft.com/dotnet/api/system.span-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + - ',' + - " " + - ref + - " " + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + - ) +- api3: Normalize(double, uint) + id: PolylineAlgorithm_PolylineEncoding_Normalize_System_Double_System_UInt32_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L61 + metadata: + uid: PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32) + commentId: M:PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32) +- markdown: Normalizes a geographic coordinate value to an integer representation based on the specified precision. +- code: public static int Normalize(double value, uint precision = 5) +- h4: Parameters +- parameters: + - name: value + type: + - text: double + url: https://learn.microsoft.com/dotnet/api/system.double + description: The numeric value to normalize. Must be a finite number (not NaN or infinity). + - name: precision + type: + - text: uint + url: https://learn.microsoft.com/dotnet/api/system.uint32 + description: >- + The number of decimal places of precision to preserve in the normalized value. + + The value is multiplied by 10^precision before rounding. + + Default is 5, which is standard for polyline encoding. + optional: true +- h4: Returns +- parameters: + - type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + description: An integer representing the normalized value. Returns 0 if the input value is 0.0. +- h4: Remarks +- markdown: >- +

+ + This method converts a floating-point coordinate value into a normalized integer by multiplying it by 10 raised + + to the power of the specified precision, then truncating the result to an integer. + +

+ +

+ + For example, with the default precision of 5: + + +

  • A value of 37.78903 becomes 3778903
  • A value of -122.4123 becomes -12241230
+ +

+ +

+ + The method validates that the input value is finite (not NaN or infinity) before performing normalization. + + If the precision is 0, the value is rounded without multiplication. + +

+- h4: Exceptions +- parameters: + - type: + - text: ArgumentOutOfRangeException + url: https://learn.microsoft.com/dotnet/api/system.argumentoutofrangeexception + description: Thrown when value is not a finite number (NaN or infinity). + - type: + - text: OverflowException + url: https://learn.microsoft.com/dotnet/api/system.overflowexception + description: Thrown when the normalized result exceeds the range of a 32-bit signed integer during the conversion from double to int. +- api3: TryReadValue(ref int, ReadOnlyMemory, ref int) + id: PolylineAlgorithm_PolylineEncoding_TryReadValue_System_Int32__System_ReadOnlyMemory_System_Char__System_Int32__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L169 + metadata: + uid: PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@) + commentId: M:PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@) +- markdown: Attempts to read an encoded integer value from a polyline buffer, updating the specified delta and position. +- code: public static bool TryReadValue(ref int delta, ReadOnlyMemory buffer, ref int position) +- h4: Parameters +- parameters: + - name: delta + type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + description: Reference to the integer accumulator that will be updated with the decoded value. + - name: buffer + type: + - text: ReadOnlyMemory + url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + description: The buffer containing polyline-encoded characters. + - name: position + type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + description: Reference to the current position in the buffer. This value is updated as characters are read. +- h4: Returns +- parameters: + - type: + - text: bool + url: https://learn.microsoft.com/dotnet/api/system.boolean + description: true if a value was successfully read and decoded; false if the buffer ended before a complete value was read. +- h4: Remarks +- markdown: >- +

+ + This method decodes a value from a polyline-encoded character buffer, starting at the given position. It reads + + characters sequentially, applying the polyline decoding algorithm, and updates the delta with + + the decoded value. The position is advanced as characters are processed. + +

+ +

+ + The decoding process continues until a character with a value less than the algorithm's space constant is encountered, + + which signals the end of the encoded value. If the buffer is exhausted before a complete value is read, the method returns false. + +

+ +

+ + The decoded value is added to delta using zigzag decoding, which handles both positive and negative values. + +

+- api3: TryWriteValue(int, Span, ref int) + id: PolylineAlgorithm_PolylineEncoding_TryWriteValue_System_Int32_System_Span_System_Char__System_Int32__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L237 + metadata: + uid: PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@) + commentId: M:PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@) +- markdown: Attempts to write an encoded integer value to a polyline buffer, updating the specified position. +- code: public static bool TryWriteValue(int delta, Span buffer, ref int position) +- h4: Parameters +- parameters: + - name: delta + type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + description: >- + The integer value to encode and write to the buffer. This value typically represents the difference between consecutive + + coordinate values in polyline encoding. + - name: buffer + type: + - text: Span + url: https://learn.microsoft.com/dotnet/api/system.span-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + description: The destination buffer where the encoded characters will be written. Must have sufficient capacity to hold the encoded value. + - name: position + type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + description: >- + Reference to the current position in the buffer. This value is updated as characters are written to reflect the new position + + after encoding is complete. +- h4: Returns +- parameters: + - type: + - text: bool + url: https://learn.microsoft.com/dotnet/api/system.boolean + description: >- + true if the value was successfully encoded and written to the buffer; false if the buffer + + does not have sufficient remaining capacity to hold the encoded value. +- h4: Remarks +- markdown: >- +

+ + This method encodes an integer delta value into a polyline-encoded format and writes it to the provided character buffer, + + starting at the given position. It applies zigzag encoding followed by the polyline encoding algorithm to represent + + both positive and negative values efficiently. + +

+ +

+ + The encoding process first converts the value using zigzag encoding (left shift by 1, with bitwise inversion for negative values), + + then writes it as a sequence of characters. Each character encodes 5 bits of data, with continuation bits indicating whether + + more characters follow. The position is advanced as characters are written. + +

+ +

+ + Before writing, the method validates that sufficient space is available in the buffer by calling . + + If the buffer does not have enough remaining capacity, the method returns false without modifying the buffer or position. + +

+ +

+ + This method is the inverse of and can be used to encode coordinate deltas for polyline serialization. + +

+- api3: ValidateBlockLength(ReadOnlySpan) + id: PolylineAlgorithm_PolylineEncoding_ValidateBlockLength_System_ReadOnlySpan_System_Char__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L438 + metadata: + uid: PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char}) + commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char}) +- markdown: Validates the block structure of a polyline segment, ensuring each encoded value does not exceed 7 characters and the polyline ends correctly. +- code: public static void ValidateBlockLength(ReadOnlySpan polyline) +- h4: Parameters +- parameters: + - name: polyline + type: + - text: ReadOnlySpan + url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + description: A span representing the polyline segment to validate. +- h4: Remarks +- markdown: >- +

+ + Iterates through the polyline, counting the length of each block (a sequence of characters representing an encoded value). + + Throws an if any block exceeds 7 characters or if the polyline does not end with a valid block terminator. + +

+- h4: Exceptions +- parameters: + - type: + - text: ArgumentException + url: https://learn.microsoft.com/dotnet/api/system.argumentexception + description: Thrown when a block exceeds 7 characters or the polyline does not end with a valid block terminator. +- api3: ValidateCharRange(ReadOnlySpan) + id: PolylineAlgorithm_PolylineEncoding_ValidateCharRange_System_ReadOnlySpan_System_Char__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L392 + metadata: + uid: PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char}) + commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char}) +- markdown: Validates that all characters in the polyline segment are within the allowed ASCII range for polyline encoding. +- code: public static void ValidateCharRange(ReadOnlySpan polyline) +- h4: Parameters +- parameters: + - name: polyline + type: + - text: ReadOnlySpan + url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + description: A span representing the polyline segment to validate. +- h4: Remarks +- markdown: >- +

+ + Uses SIMD vectorization for efficient validation of large spans. Falls back to scalar checks for any block where an invalid character is detected. + +

+ +

+ + The valid range is from '?' (63) to '_' (95), inclusive. If an invalid character is found, an is thrown. + +

+- h4: Exceptions +- parameters: + - type: + - text: ArgumentException + url: https://learn.microsoft.com/dotnet/api/system.argumentexception + description: Thrown when an invalid character is found in the polyline segment. +- api3: ValidateFormat(ReadOnlySpan) + id: PolylineAlgorithm_PolylineEncoding_ValidateFormat_System_ReadOnlySpan_System_Char__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L370 + metadata: + uid: PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char}) + commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char}) +- markdown: Validates the format of a polyline segment, ensuring all characters are valid and block structure is correct. +- code: public static void ValidateFormat(ReadOnlySpan polyline) +- h4: Parameters +- parameters: + - name: polyline + type: + - text: ReadOnlySpan + url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + description: A span representing the polyline segment to validate. +- h4: Remarks +- markdown: >- +

+ + This method performs two levels of validation on the provided polyline segment: + +

+ +
  1. + Character Range Validation: Checks that every character in the polyline is within the valid ASCII range for polyline encoding ('?' [63] to '_' [95], inclusive). + Uses SIMD acceleration for efficient validation of large segments. +
  2. + Block Structure Validation: Ensures that each encoded value (block) does not exceed 7 characters and that the polyline ends with a valid block terminator. +
+

+ + If an invalid character or block structure is detected, an is thrown with details about the error. + +

+- h4: Exceptions +- parameters: + - type: + - text: ArgumentException + url: https://learn.microsoft.com/dotnet/api/system.argumentexception + description: Thrown when an invalid character is found or the block structure is invalid. +languageId: csharp +metadata: + description: >- + Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing + + geographic coordinate values. diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml new file mode 100644 index 00000000..1947eac1 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml @@ -0,0 +1,127 @@ +### YamlMime:ApiPage +title: Class PolylineEncodingOptions +body: +- api1: Class PolylineEncodingOptions + id: PolylineAlgorithm_PolylineEncodingOptions + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L29 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptions + commentId: T:PolylineAlgorithm.PolylineEncodingOptions +- facts: + - name: Namespace + value: + text: PolylineAlgorithm + url: PolylineAlgorithm.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: Provides configuration options for polyline encoding operations. +- code: public sealed class PolylineEncodingOptions +- h4: Inheritance +- inheritance: + - text: object + url: https://learn.microsoft.com/dotnet/api/system.object + - text: PolylineEncodingOptions + url: PolylineAlgorithm.PolylineEncodingOptions.html +- h4: Inherited Members +- list: + - text: object.Equals(object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - text: object.Equals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - text: object.GetHashCode() + url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - text: object.GetType() + url: https://learn.microsoft.com/dotnet/api/system.object.gettype + - text: object.ReferenceEquals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - text: object.ToString() + url: https://learn.microsoft.com/dotnet/api/system.object.tostring +- h2: Remarks +- markdown: >- +

+ + This class allows you to configure various aspects of polyline encoding, including: + +

+ +
  • The level for coordinate encoding
  • The for memory allocation strategy
  • The for diagnostic logging
+ +

+ + All properties have internal setters and should be configured through a builder or factory pattern. + +

+- h2: Properties +- api3: LoggerFactory + id: PolylineAlgorithm_PolylineEncodingOptions_LoggerFactory + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L41 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory + commentId: P:PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory +- markdown: Gets the logger factory used for diagnostic logging during encoding operations. +- code: public ILoggerFactory LoggerFactory { get; } +- h4: Property Value +- parameters: + - type: + - text: ILoggerFactory + url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggerfactory +- h4: Remarks +- markdown: >- + The default logger factory is , which does not log any messages. + + To enable logging, provide a custom implementation. +- api3: Precision + id: PolylineAlgorithm_PolylineEncodingOptions_Precision + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L60 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptions.Precision + commentId: P:PolylineAlgorithm.PolylineEncodingOptions.Precision +- markdown: Gets the precision level used for encoding coordinate values. +- code: public uint Precision { get; } +- h4: Property Value +- parameters: + - type: + - text: uint + url: https://learn.microsoft.com/dotnet/api/system.uint32 +- h4: Remarks +- markdown: >- +

+ + The precision determines the number of decimal places to which each coordinate value (latitude or longitude) + + is multiplied and truncated (not rounded) before encoding. For example, a precision of 5 means each coordinate is multiplied by 10^5 + + and truncated to an integer before encoding. + +

+ +

+ + This setting does not directly correspond to a physical distance or accuracy in meters, but rather controls + + the granularity of the encoded values. + +

+- api3: StackAllocLimit + id: PolylineAlgorithm_PolylineEncodingOptions_StackAllocLimit + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L73 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit + commentId: P:PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit +- markdown: Gets the maximum buffer size (in characters) that can be allocated on the stack for encoding operations. +- code: public int StackAllocLimit { get; } +- h4: Property Value +- parameters: + - type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 +- h4: Remarks +- markdown: >- + When the required buffer size for encoding exceeds this limit, memory will be allocated on the heap instead of the stack. + + This setting specifically applies to stack allocation of character arrays (stackalloc char[]) used during polyline encoding, + + balancing performance and stack safety. +languageId: csharp +metadata: + description: Provides configuration options for polyline encoding operations. diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml new file mode 100644 index 00000000..66ae63b8 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml @@ -0,0 +1,141 @@ +### YamlMime:ApiPage +title: Class PolylineEncodingOptionsBuilder +body: +- api1: Class PolylineEncodingOptionsBuilder + id: PolylineAlgorithm_PolylineEncodingOptionsBuilder + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L15 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder + commentId: T:PolylineAlgorithm.PolylineEncodingOptionsBuilder +- facts: + - name: Namespace + value: + text: PolylineAlgorithm + url: PolylineAlgorithm.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: Provides a builder for configuring options for polyline encoding operations. +- code: public sealed class PolylineEncodingOptionsBuilder +- h4: Inheritance +- inheritance: + - text: object + url: https://learn.microsoft.com/dotnet/api/system.object + - text: PolylineEncodingOptionsBuilder + url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html +- h4: Inherited Members +- list: + - text: object.Equals(object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - text: object.Equals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - text: object.GetHashCode() + url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - text: object.GetType() + url: https://learn.microsoft.com/dotnet/api/system.object.gettype + - text: object.ReferenceEquals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - text: object.ToString() + url: https://learn.microsoft.com/dotnet/api/system.object.tostring +- h2: Methods +- api3: Build() + id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Build + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L38 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build + commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build +- markdown: Builds a new instance using the configured options. +- code: public PolylineEncodingOptions Build() +- h4: Returns +- parameters: + - type: + - text: PolylineEncodingOptions + url: PolylineAlgorithm.PolylineEncodingOptions.html + description: A configured instance. +- api3: Create() + id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Create + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L28 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create + commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create +- markdown: Creates a new instance for the specified coordinate type. +- code: public static PolylineEncodingOptionsBuilder Create() +- h4: Returns +- parameters: + - type: + - text: PolylineEncodingOptionsBuilder + url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html + description: An instance for configuring polyline encoding options. +- api3: WithLoggerFactory(ILoggerFactory) + id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithLoggerFactory_Microsoft_Extensions_Logging_ILoggerFactory_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L97 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory) + commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory) +- markdown: Configures the to be used for logging during polyline encoding operations. +- code: public PolylineEncodingOptionsBuilder WithLoggerFactory(ILoggerFactory loggerFactory) +- h4: Parameters +- parameters: + - name: loggerFactory + type: + - text: ILoggerFactory + url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggerfactory + description: The instance to use for logging. If null, a will be used instead. +- h4: Returns +- parameters: + - type: + - text: PolylineEncodingOptionsBuilder + url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html + description: The current instance for method chaining. +- api3: WithPrecision(uint) + id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithPrecision_System_UInt32_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L82 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32) + commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32) +- markdown: Sets the coordinate encoding precision. +- code: public PolylineEncodingOptionsBuilder WithPrecision(uint precision) +- h4: Parameters +- parameters: + - name: precision + type: + - text: uint + url: https://learn.microsoft.com/dotnet/api/system.uint32 + description: The number of decimal places to use for encoding coordinate values. Default is 5. +- h4: Returns +- parameters: + - type: + - text: PolylineEncodingOptionsBuilder + url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html + description: The current instance for method chaining. +- api3: WithStackAllocLimit(int) + id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithStackAllocLimit_System_Int32_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L61 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32) + commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32) +- markdown: Configures the buffer size used for stack allocation during polyline encoding operations. +- code: public PolylineEncodingOptionsBuilder WithStackAllocLimit(int stackAllocLimit) +- h4: Parameters +- parameters: + - name: stackAllocLimit + type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + description: The maximum buffer size to use for stack allocation. Must be greater than or equal to 1. +- h4: Returns +- parameters: + - type: + - text: PolylineEncodingOptionsBuilder + url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html + description: The current instance for method chaining. +- h4: Remarks +- markdown: This method allows customization of the internal buffer size for encoding, which can impact performance and memory usage. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentOutOfRangeException + url: https://learn.microsoft.com/dotnet/api/system.argumentoutofrangeexception + description: Thrown if stackAllocLimit is less than 1. +languageId: csharp +metadata: + description: Provides a builder for configuring options for polyline encoding operations. diff --git a/api-reference/0.0/PolylineAlgorithm.yml b/api-reference/0.0/PolylineAlgorithm.yml new file mode 100644 index 00000000..b60dc3c0 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.yml @@ -0,0 +1,38 @@ +### YamlMime:ApiPage +title: Namespace PolylineAlgorithm +body: +- api1: Namespace PolylineAlgorithm + id: PolylineAlgorithm + metadata: + uid: PolylineAlgorithm + commentId: N:PolylineAlgorithm +- h3: Namespaces +- parameters: + - type: + text: PolylineAlgorithm.Abstraction + url: PolylineAlgorithm.Abstraction.html + - type: + text: PolylineAlgorithm.Extensions + url: PolylineAlgorithm.Extensions.html +- h3: Classes +- parameters: + - type: + text: InvalidPolylineException + url: PolylineAlgorithm.InvalidPolylineException.html + description: Exception thrown when a polyline is determined to be malformed or invalid during processing. + - type: + text: PolylineEncoding + url: PolylineAlgorithm.PolylineEncoding.html + description: >- + Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing + + geographic coordinate values. + - type: + text: PolylineEncodingOptions + url: PolylineAlgorithm.PolylineEncodingOptions.html + description: Provides configuration options for polyline encoding operations. + - type: + text: PolylineEncodingOptionsBuilder + url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html + description: Provides a builder for configuring options for polyline encoding operations. +languageId: csharp diff --git a/api-reference/0.0/toc.yml b/api-reference/0.0/toc.yml new file mode 100644 index 00000000..d1ffc58a --- /dev/null +++ b/api-reference/0.0/toc.yml @@ -0,0 +1,34 @@ +### YamlMime:TableOfContent +- name: PolylineAlgorithm + href: PolylineAlgorithm.yml + items: + - name: Classes + - name: InvalidPolylineException + href: PolylineAlgorithm.InvalidPolylineException.yml + - name: PolylineEncoding + href: PolylineAlgorithm.PolylineEncoding.yml + - name: PolylineEncodingOptions + href: PolylineAlgorithm.PolylineEncodingOptions.yml + - name: PolylineEncodingOptionsBuilder + href: PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml +- name: PolylineAlgorithm.Abstraction + href: PolylineAlgorithm.Abstraction.yml + items: + - name: Classes + - name: AbstractPolylineDecoder + href: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml + - name: AbstractPolylineEncoder + href: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml + - name: Interfaces + - name: IPolylineDecoder + href: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml + - name: IPolylineEncoder + href: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml +- name: PolylineAlgorithm.Extensions + href: PolylineAlgorithm.Extensions.yml + items: + - name: Classes + - name: PolylineDecoderExtensions + href: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml + - name: PolylineEncoderExtensions + href: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml diff --git a/api-reference/guide/benchmarks.md b/api-reference/guide/benchmarks.md new file mode 100644 index 00000000..47b453f9 --- /dev/null +++ b/api-reference/guide/benchmarks.md @@ -0,0 +1,11 @@ +--- +title: Benchmarks +--- +# Benchmarks + +Performance benchmarks for **PolylineAlgorithm for .NET** measured using [BenchmarkDotNet](https://benchmarkdotnet.org/). + +> [!NOTE] +> Benchmarks are generated automatically during the release process. Results may vary depending on hardware and runtime version. + +{benchmarks_section} diff --git a/api-reference/guide/toc.yml b/api-reference/guide/toc.yml index 015a9943..e9d9e716 100644 --- a/api-reference/guide/toc.yml +++ b/api-reference/guide/toc.yml @@ -8,3 +8,5 @@ href: sample.md - name: FAQ href: faq.md +- name: Benchmarks + href: benchmarks.md diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs index f28c8141..b6b54081 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs @@ -93,8 +93,10 @@ public void PolylineDecoder_Decode_Memory() { } private sealed class StringPolylineDecoder : AbstractPolylineDecoder { - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) { - return (latitude, longitude); + protected override int ValuesPerItem => 2; + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); } protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { @@ -103,8 +105,10 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { } private sealed class CharArrayPolylineDecoder : AbstractPolylineDecoder { - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) { - return (latitude, longitude); + protected override int ValuesPerItem => 2; + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); } protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) { @@ -113,8 +117,10 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) { } private sealed class MemoryCharPolylineDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) { - return (latitude, longitude); + protected override int ValuesPerItem => 2; + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); } protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) { diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs index e0b97c5c..c4b9d5a8 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs @@ -85,8 +85,11 @@ public void PolylineEncoder_Encode_List() { } private sealed class StringPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { + protected override int ValuesPerItem => 2; protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude; - protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude; + protected override void GetValues((double Latitude, double Longitude) item, Span destination) { + destination[0] = item.Latitude; + destination[1] = item.Longitude; + } } } diff --git a/docs/local-development.md b/docs/local-development.md index 48fa5f76..ab2da8ab 100644 --- a/docs/local-development.md +++ b/docs/local-development.md @@ -72,3 +72,24 @@ The CI `format` job also runs `dotnet format` automatically on every push to non ## Editor Configuration Code style rules are stored in `.editorconfig` at the repository root. Any compliant IDE (Visual Studio, VS Code with C# Dev Kit, Rider) will pick these up automatically. + +## Required Repository Secrets and Variables + +The CI/CD workflows rely on the following GitHub repository secrets and variables. + +### Secrets + +| Name | Description | +|------|-------------| +| `NUGET_PACKAGE_FEED_API_KEY` | API key for the Azure Artifacts NuGet feed | + +### Variables + +| Name | Description | +|------|-------------| +| `NUGET_PACKAGE_FEED_URL` | NuGet feed URL | +| `BENCHMARKDOTNET_RUN_OVERRIDE` | Set to `true` to force benchmarks to run on non-release PRs | +| `BENCHMARKDOTNET_RUNTIMES` | Runtimes to benchmark (e.g. `net8.0 net10.0`) | +| `BENCHMARKDOTNET_FILTER` | Benchmark filter pattern (e.g. `*`) | +| `DEFAULT_BUILD_FRAMEWORK` | Default target framework for builds (e.g. `net10.0`) | +| `SRC_DEFAULT_GLOB_PATTERN` | Glob pattern for source project files (e.g. `**/PolylineAlgorithm.csproj`) | diff --git a/docs/workflows.md b/docs/workflows.md index 4c864783..8782270f 100644 --- a/docs/workflows.md +++ b/docs/workflows.md @@ -87,6 +87,7 @@ Version bumping runs independently via `bump-version.yml` (manual trigger). | `pack` | `versioning`, `build` | Packages binaries | | `publish-package` | `pack` | Publishes to NuGet.org (Production environment) | | `create-release` | `versioning`, `publish-package` | Creates a git tag + GitHub release with auto-generated notes | +| `update-changelog` | `release` | Fetches release notes and prepends a new entry to `CHANGELOG.md` — stable releases only | | `generate-docs` | `versioning` | Builds DocFX site | | `publish-docs` | `generate-docs` | Deploys to GitHub Pages | diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs index 82899203..dd05ca88 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs @@ -12,16 +12,23 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; /// /// Polyline decoder using NetTopologySuite. /// -public sealed class NetTopologyPolylineDecoder : AbstractPolylineDecoder { +internal sealed class NetTopologyPolylineDecoder : AbstractPolylineDecoder { /// - /// Creates a NetTopologySuite point from latitude and longitude. + /// Gets the number of encoded values per item: latitude (index 0) and longitude (index 1). /// - /// Latitude value. - /// Longitude value. + protected override int ValuesPerItem => 2; + + /// + /// Creates a NetTopologySuite point from the decoded values. + /// + /// + /// A memory region containing two values: index 0 is latitude, index 1 is longitude. + /// /// Point instance. - protected override Point CreateCoordinate(double latitude, double longitude) { + protected override Point CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; // NetTopologySuite Point: x = longitude, y = latitude - return new Point(longitude, latitude); + return new Point(span[1], span[0]); } /// diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs index 649547bd..5a7b5529 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs @@ -7,11 +7,17 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; using global::NetTopologySuite.Geometries; using PolylineAlgorithm.Abstraction; +using System; /// /// Polyline encoder using NetTopologySuite's Point type. /// -public sealed class NetTopologyPolylineEncoder : AbstractPolylineEncoder { +internal sealed class NetTopologyPolylineEncoder : AbstractPolylineEncoder { + /// + /// Gets the number of values per item: latitude (index 0) and longitude (index 1). + /// + protected override int ValuesPerItem => 2; + /// /// Creates encoded polyline string from memory. /// @@ -26,30 +32,15 @@ protected override string CreatePolyline(ReadOnlyMemory polyline) { } /// - /// Gets latitude from point. + /// Fills destination with latitude (index 0) and longitude (index 1) from the point. /// - /// Point instance. - /// Latitude value. - protected override double GetLatitude(Point current) { - if (current is null) { - throw new ArgumentNullException(nameof(current)); - } - - // NetTopologySuite Point: Y = latitude - return current.Y; - } - - /// - /// Gets longitude from point. - /// - /// Point instance. - /// Longitude value. - protected override double GetLongitude(Point current) { - if (current is null) { - throw new ArgumentNullException(nameof(current)); - } - - // NetTopologySuite Point: X = longitude - return current.X; + /// Point instance. + /// Span of length 2 to fill. + protected override void GetValues(Point item, Span destination) { + ArgumentNullException.ThrowIfNull(item); + + // NetTopologySuite Point: Y = latitude, X = longitude + destination[0] = item.Y; + destination[1] = item.X; } } \ No newline at end of file diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/PolylineAlgorithm.NetTopologySuite.Sample.csproj b/samples/PolylineAlgorithm.NetTopologySuite.Sample/PolylineAlgorithm.NetTopologySuite.Sample.csproj index 57d5f7c1..fef82026 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/PolylineAlgorithm.NetTopologySuite.Sample.csproj +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/PolylineAlgorithm.NetTopologySuite.Sample.csproj @@ -1,7 +1,8 @@  - netstandard2.1 + Exe + net10.0 diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/Program.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/Program.cs new file mode 100644 index 00000000..ca9a8a6f --- /dev/null +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/Program.cs @@ -0,0 +1,46 @@ +// +// Copyright © Pete Sramek. All rights reserved. +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +using NetTopologySuite.Geometries; +using PolylineAlgorithm.NetTopologySuite.Sample; + +public class Program { + public static void Main(string[] args) { + // Sample route: Seattle → Bellevue → Redmond + var points = new Point[] + { + new(x: -122.3503, y: 47.6219), // Seattle (x = longitude, y = latitude) + new(x: -122.2015, y: 47.6101), // Bellevue + new(x: -122.1215, y: 47.6740), // Redmond + }; + + var encoder = new NetTopologyPolylineEncoder(); + var decoder = new NetTopologyPolylineDecoder(); + + // Encode + string encoded = encoder.Encode(points); + + Console.WriteLine("=== NetTopologySuite Polyline Sample ==="); + Console.WriteLine(); + Console.WriteLine("Input points (longitude, latitude):"); + + foreach (Point p in points) { + Console.WriteLine($" ({p.X}, {p.Y})"); + } + + Console.WriteLine(); + Console.WriteLine($"Encoded polyline: {encoded}"); + Console.WriteLine(); + + // Decode + IEnumerable decoded = decoder.Decode(encoded); + + Console.WriteLine("Decoded points (longitude, latitude):"); + + foreach (Point p in decoded) { + Console.WriteLine($" ({p.X}, {p.Y})"); + } + } +} \ No newline at end of file diff --git a/samples/PolylineAlgorithm.SensorData.Sample/PolylineAlgorithm.SensorData.Sample.csproj b/samples/PolylineAlgorithm.SensorData.Sample/PolylineAlgorithm.SensorData.Sample.csproj new file mode 100644 index 00000000..3e1bcb63 --- /dev/null +++ b/samples/PolylineAlgorithm.SensorData.Sample/PolylineAlgorithm.SensorData.Sample.csproj @@ -0,0 +1,16 @@ + + + + Exe + net10.0 + + + + false + + + + + + + diff --git a/samples/PolylineAlgorithm.SensorData.Sample/Program.cs b/samples/PolylineAlgorithm.SensorData.Sample/Program.cs new file mode 100644 index 00000000..e14977f9 --- /dev/null +++ b/samples/PolylineAlgorithm.SensorData.Sample/Program.cs @@ -0,0 +1,49 @@ +// +// Copyright © Pete Sramek. All rights reserved. +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +using PolylineAlgorithm.SensorData.Sample; + +public static class Program { + public static void Main(string[] args) { + // Sample temperature readings from a sensor over six seconds + var readings = new SensorReading[] + { + new(DateTimeOffset.UtcNow, 23.5), + new(DateTimeOffset.UtcNow.AddSeconds(1), 23.7), + new(DateTimeOffset.UtcNow.AddSeconds(2), 24.1), + new(DateTimeOffset.UtcNow.AddSeconds(3), 25.0), + new(DateTimeOffset.UtcNow.AddSeconds(4), 24.8), + new(DateTimeOffset.UtcNow.AddSeconds(5), 24.8), + new(DateTimeOffset.UtcNow.AddSeconds(6), 22.3), + }; + + var encoder = new SensorDataEncoder(); + var decoder = new SensorDataDecoder(); + + // Encode + string encoded = encoder.Encode(readings); + + Console.WriteLine("=== Sensor Data Polyline Sample ==="); + Console.WriteLine(); + Console.WriteLine("Input readings:"); + + foreach (SensorReading r in readings) { + Console.WriteLine($" [{r.Timestamp:HH:mm:ss}] {r.Temperature:F1} °C"); + } + + Console.WriteLine(); + Console.WriteLine($"Encoded polyline: {encoded}"); + Console.WriteLine(); + + // Decode (timestamps and temperatures are both recovered) + IEnumerable decoded = decoder.Decode(encoded); + + Console.WriteLine("Decoded readings:"); + + foreach (SensorReading r in decoded) { + Console.WriteLine($" [{r.Timestamp:HH:mm:ss}] {r.Temperature:F1} °C"); + } + } +} \ No newline at end of file diff --git a/samples/PolylineAlgorithm.SensorData.Sample/Properties/CodeCoverage.cs b/samples/PolylineAlgorithm.SensorData.Sample/Properties/CodeCoverage.cs new file mode 100644 index 00000000..e3468ef6 --- /dev/null +++ b/samples/PolylineAlgorithm.SensorData.Sample/Properties/CodeCoverage.cs @@ -0,0 +1,8 @@ +// +// Copyright © Pete Sramek. All rights reserved. +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +using System.Diagnostics.CodeAnalysis; + +[assembly: ExcludeFromCodeCoverage] diff --git a/samples/PolylineAlgorithm.SensorData.Sample/SensorDataDecoder.cs b/samples/PolylineAlgorithm.SensorData.Sample/SensorDataDecoder.cs new file mode 100644 index 00000000..9c63d647 --- /dev/null +++ b/samples/PolylineAlgorithm.SensorData.Sample/SensorDataDecoder.cs @@ -0,0 +1,107 @@ +// +// Copyright © Pete Sramek. All rights reserved. +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace PolylineAlgorithm.SensorData.Sample; + +using PolylineAlgorithm.Abstraction; +using System.Collections.Generic; +using System.Threading; + +/// +/// Decodes a compact polyline string produced by back into a sequence +/// of values. +/// +/// +/// +/// This class demonstrates implementing for a custom +/// scalar type, following the same structural pattern as . +/// +/// +/// Each encoded pair consists of a delta-compressed Unix timestamp (seconds since Unix epoch, precision 0) +/// followed by a delta-compressed temperature value (at ). +/// Both are recovered and used to reconstruct the original . +/// +/// +[System.Diagnostics.CodeAnalysis.SuppressMessage("Sonar", "S4456:Parameter validation in yielding methods should be wrapped", Justification = "Inlined by design to demonstrate a simple iterator without a wrapper method.")] +internal sealed class SensorDataDecoder : IPolylineDecoder { + /// + /// Initializes a new instance of the class with default encoding options. + /// + public SensorDataDecoder() + : this(new PolylineEncodingOptions()) { } + + /// + /// Initializes a new instance of the class with the specified encoding options. + /// + /// + /// The to use for decoding operations. + /// The value must match the precision used during encoding. + /// + /// + /// Thrown when is . + /// + public SensorDataDecoder(PolylineEncodingOptions options) { + ArgumentNullException.ThrowIfNull(options); + + Options = options; + } + + /// + /// Gets the encoding options used by this decoder. + /// + public PolylineEncodingOptions Options { get; } + + /// + /// Decodes a polyline string back into a sequence of values. + /// + /// + /// The polyline-encoded string produced by . + /// + /// + /// A that can be used to cancel the decoding operation. + /// + /// + /// An of whose + /// and values + /// are recovered from the encoded string. + /// + /// + /// Thrown when is . + /// + /// + /// Thrown when is empty. + /// + /// + /// Thrown when requests cancellation. + /// + public IEnumerable Decode(string polyline, CancellationToken cancellationToken = default) { + ArgumentNullException.ThrowIfNull(polyline); + + if (polyline.Length < 1) { + throw new ArgumentException("Encoded polyline must not be empty.", nameof(polyline)); + } + + ReadOnlyMemory memory = polyline.AsMemory(); + int position = 0; + // Mirror the encoder's base epoch so the first delta decodes back to the correct Unix seconds. + int accumulatedTimestamp = SensorDataEncoder.TimestampBaseEpochSeconds; + int accumulatedTemperature = 0; + + while (position < memory.Length) { + cancellationToken.ThrowIfCancellationRequested(); + + // Read Unix timestamp delta (precision 0) then temperature delta. + if (!PolylineEncoding.TryReadValue(ref accumulatedTimestamp, memory, ref position) + || !PolylineEncoding.TryReadValue(ref accumulatedTemperature, memory, ref position)) { + yield break; + } + + long unixSeconds = (long)PolylineEncoding.Denormalize(accumulatedTimestamp, precision: 0); + double temperature = PolylineEncoding.Denormalize(accumulatedTemperature, Options.Precision); + + yield return new SensorReading(DateTimeOffset.FromUnixTimeSeconds(unixSeconds), temperature); + } + } +} diff --git a/samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs b/samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs new file mode 100644 index 00000000..be199e4d --- /dev/null +++ b/samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs @@ -0,0 +1,135 @@ +// +// Copyright © Pete Sramek. All rights reserved. +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace PolylineAlgorithm.SensorData.Sample; + +using PolylineAlgorithm.Abstraction; +using System.Buffers; +using System.Threading; + +/// +/// Encodes a sequence of values into a compact polyline string +/// using the polyline delta-encoding algorithm applied to both the +/// and fields. +/// +/// +/// +/// This class demonstrates implementing for a custom +/// scalar type, following the same structural pattern as . +/// +/// +/// Because sensor readings carry two numeric dimensions (timestamp and temperature), the base class designed +/// for geographic coordinate pairs is not used. Instead, static +/// helpers are called directly to perform normalisation, delta computation, and character-level encoding. +/// +/// +/// Each reading is encoded as a pair of delta-compressed values: +/// the Unix timestamp in seconds (precision 0) followed by the temperature (at ). +/// +/// +internal sealed class SensorDataEncoder : IPolylineEncoder { + // 2020-01-01 00:00:00 UTC in Unix seconds. Used as the delta-encoding base for timestamps + // so that the first absolute delta stays within the int32 safe range of the polyline algorithm. + internal const int TimestampBaseEpochSeconds = 1_577_836_800; + + /// + /// Initializes a new instance of the class with default encoding options. + /// + public SensorDataEncoder() + : this(new PolylineEncodingOptions()) { } + + /// + /// Initializes a new instance of the class with the specified encoding options. + /// + /// + /// The to use for encoding operations. + /// + /// + /// Thrown when is . + /// + public SensorDataEncoder(PolylineEncodingOptions options) { + ArgumentNullException.ThrowIfNull(options); + + Options = options; + } + + /// + /// Gets the encoding options used by this encoder. + /// + public PolylineEncodingOptions Options { get; } + + /// + /// Encodes a sequence of values into a polyline string. + /// + /// + /// The sensor readings to encode. Each reading contributes a delta-compressed Unix timestamp + /// (seconds since Unix epoch, precision 0) and a delta-compressed temperature value. + /// Must contain at least one element. + /// + /// + /// A that can be used to cancel the encoding operation. + /// + /// + /// A polyline-encoded string representing the delta-compressed timestamp and temperature series. + /// + /// + /// Thrown when is empty. + /// + /// + /// Thrown when requests cancellation. + /// + public string Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default) { + if (coordinates.Length < 1) { + throw new ArgumentException("Sequence must contain at least one element.", nameof(coordinates)); + } + + // Maximum number of ASCII characters required to encode a single 32-bit delta value + // using the polyline algorithm (ceil(32 bits / 5 bits per chunk) + sign bit = 7). + const int MaxEncodedCharsPerValue = 7; + + // Each reading encodes two values: Unix timestamp (precision 0) + temperature. + // The polyline algorithm uses signed int32 internally, limiting safe absolute values to ~1.07B. + // Current Unix time in seconds (~1.74B) exceeds this. We therefore delta-encode relative to + // 2020-01-01 00:00:00 UTC (= 1 577 836 800 s), keeping the initial delta well within range. + int previousTimestampNormalized = TimestampBaseEpochSeconds; + int previousTemperatureNormalized = 0; + int position = 0; + int length = coordinates.Length * 2 * MaxEncodedCharsPerValue; + + char[]? temp = length <= Options.StackAllocLimit + ? null + : ArrayPool.Shared.Rent(length); + + Span buffer = temp is null ? stackalloc char[length] : temp.AsSpan(0, length); + + try { + for (int i = 0; i < coordinates.Length; i++) { + cancellationToken.ThrowIfCancellationRequested(); + + // Encode Unix timestamp in whole seconds (precision 0). + int normalizedTimestamp = PolylineEncoding.Normalize((double)coordinates[i].Timestamp.ToUnixTimeSeconds(), precision: 0); + int timestampDelta = normalizedTimestamp - previousTimestampNormalized; + + // Encode temperature at the configured precision. + int normalizedTemperature = PolylineEncoding.Normalize(coordinates[i].Temperature, Options.Precision); + int temperatureDelta = normalizedTemperature - previousTemperatureNormalized; + + if (!PolylineEncoding.TryWriteValue(timestampDelta, buffer, ref position) + || !PolylineEncoding.TryWriteValue(temperatureDelta, buffer, ref position)) { + throw new InvalidOperationException("Encoding buffer is too small to hold the encoded value."); + } + + previousTimestampNormalized = normalizedTimestamp; + previousTemperatureNormalized = normalizedTemperature; + } + + return buffer[..position].ToString(); + } finally { + if (temp is not null) { + ArrayPool.Shared.Return(temp); + } + } + } +} diff --git a/samples/PolylineAlgorithm.SensorData.Sample/SensorReading.cs b/samples/PolylineAlgorithm.SensorData.Sample/SensorReading.cs new file mode 100644 index 00000000..6903c92f --- /dev/null +++ b/samples/PolylineAlgorithm.SensorData.Sample/SensorReading.cs @@ -0,0 +1,16 @@ +// +// Copyright © Pete Sramek. All rights reserved. +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace PolylineAlgorithm.SensorData.Sample; + +using System.Runtime.InteropServices; + +/// +/// Represents a single temperature reading captured by a sensor. +/// +/// The UTC time at which the reading was captured. +/// The temperature value of the reading, in degrees Celsius. +[StructLayout(LayoutKind.Auto)] +internal readonly record struct SensorReading(DateTimeOffset Timestamp, double Temperature); diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs index 1059abb9..ea087776 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs @@ -6,19 +6,27 @@ using Microsoft.Extensions.Logging; using PolylineAlgorithm.Internal; using PolylineAlgorithm.Internal.Diagnostics; +using System.Buffers; using System.Runtime.CompilerServices; namespace PolylineAlgorithm.Abstraction; /// -/// Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates. +/// Provides a base implementation for decoding encoded polyline strings into sequences of items. /// /// -/// Derive from this class to implement a decoder for a specific polyline type. Override -/// and to provide type-specific behavior. +/// Derive from this class to implement a decoder for a specific polyline type. Override +/// , , and to provide +/// type-specific behavior. +/// +/// The polyline format encodes each item as a fixed-length run of delta-compressed +/// values. All items in a single polyline must have the same number of values. For example, a 2D GPS decoder +/// sets to 2 (latitude, longitude), while a 3D GPS decoder sets it to 3 +/// (latitude, longitude, altitude). +/// /// /// The type that represents the encoded polyline input. -/// The type that represents a decoded geographic coordinate. +/// The type that represents a decoded item. public abstract class AbstractPolylineDecoder : IPolylineDecoder { private readonly ILogger> _logger; @@ -53,6 +61,16 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) { /// public PolylineEncodingOptions Options { get; } + /// + /// Gets the number of encoded values that make up a single decoded item. + /// + /// + /// Override this property to specify the arity of each item. For example, return 2 for + /// latitude/longitude pairs, 3 for latitude/longitude/altitude triples, or any other count + /// that matches the encoding scheme used to produce the polyline. + /// + protected abstract int ValuesPerItem { get; } + /// /// Decodes an encoded into a sequence of instances, /// with support for cancellation. @@ -64,7 +82,7 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) { /// A that can be used to cancel the decoding operation. /// /// - /// An of representing the decoded latitude and longitude pairs. + /// An of representing the decoded items. /// /// /// Thrown when is . @@ -90,30 +108,45 @@ public IEnumerable Decode(TPolyline polyline, CancellationToken can ValidateSequence(sequence, _logger); ValidateFormat(sequence, _logger); + int valuesPerItem = ValuesPerItem; int position = 0; - int encodedLatitude = 0; - int encodedLongitude = 0; + + int[]? runningRent = ArrayPool.Shared.Rent(valuesPerItem); + // Zero-initialize so delta decoding starts from 0 for all dimensions. + for (int j = 0; j < valuesPerItem; j++) { + runningRent[j] = 0; + } try { while (position < sequence.Length) { cancellationToken.ThrowIfCancellationRequested(); - if (!PolylineEncoding.TryReadValue(ref encodedLatitude, sequence, ref position) - || !PolylineEncoding.TryReadValue(ref encodedLongitude, sequence, ref position)) { + bool allRead = true; + for (int j = 0; j < valuesPerItem; j++) { + if (!PolylineEncoding.TryReadValue(ref runningRent[j], sequence, ref position)) { + allRead = false; + break; + } + } + + if (!allRead) { _logger?.LogOperationFailedDebug(OperationName); _logger?.LogInvalidPolylineWarning(position); ExceptionGuard.ThrowInvalidPolylineFormat(position); } - double decodedLatitude = PolylineEncoding.Denormalize(encodedLatitude, Options.Precision); - double decodedLongitude = PolylineEncoding.Denormalize(encodedLongitude, Options.Precision); + double[] decoded = new double[valuesPerItem]; + for (int j = 0; j < valuesPerItem; j++) { + decoded[j] = PolylineEncoding.Denormalize(runningRent[j], Options.Precision); + } - _logger?.LogDecodedCoordinateDebug(decodedLatitude, decodedLongitude, position); + _logger?.LogDecodedValuesDebug(valuesPerItem, position); - yield return CreateCoordinate(decodedLatitude, decodedLongitude); + yield return CreateItem(decoded.AsMemory()); } } finally { + ArrayPool.Shared.Return(runningRent!); _logger?.LogOperationFinishedDebug(OperationName); } } @@ -188,17 +221,19 @@ protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? lo protected abstract ReadOnlyMemory GetReadOnlyMemory(in TPolyline polyline); /// - /// Creates a instance from the specified latitude and longitude values. + /// Creates a instance from the specified decoded values. /// - /// - /// The latitude component of the coordinate, in degrees. - /// - /// - /// The longitude component of the coordinate, in degrees. + /// + /// A of containing exactly + /// decoded values for this item, in the same order they were encoded. /// /// - /// A instance representing the specified geographic coordinate. + /// A instance representing the decoded item. /// + /// + /// Implementations should read all required values from and construct the + /// immediately. The memory is valid only for the duration of this call. + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract TCoordinate CreateCoordinate(double latitude, double longitude); + protected abstract TCoordinate CreateItem(ReadOnlyMemory values); } diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs index 1bcdb0ee..dff4eac3 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs @@ -16,13 +16,19 @@ namespace PolylineAlgorithm.Abstraction; using System.Threading; /// -/// Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings. +/// Provides a base implementation for encoding sequences of items into encoded polyline strings. /// /// -/// Derive from this class to implement an encoder for a specific coordinate and polyline type. Override -/// , , and to provide type-specific behavior. +/// Derive from this class to implement an encoder for a specific item and polyline type. Override +/// , , and to provide type-specific behavior. +/// +/// The polyline format encodes each item as a fixed-length run of delta-compressed +/// values. All items in a single polyline must have the same number of values. For example, a 2D GPS encoder +/// sets to 2 (latitude, longitude), while a 3D GPS encoder sets it to 3 +/// (latitude, longitude, altitude). +/// /// -/// The type that represents a geographic coordinate to encode. +/// The type that represents an item to encode. /// The type that represents the encoded polyline output. public abstract class AbstractPolylineEncoder : IPolylineEncoder { private readonly ILogger> _logger; @@ -56,6 +62,16 @@ protected AbstractPolylineEncoder(PolylineEncodingOptions options) { /// public PolylineEncodingOptions Options { get; } + /// + /// Gets the number of values that make up a single encoded item. + /// + /// + /// Override this property to specify the arity of each item. For example, return 2 for + /// latitude/longitude pairs, 3 for latitude/longitude/altitude triples, or any other count + /// that matches your encoding scheme. + /// + protected abstract int ValuesPerItem { get; } + /// /// Encodes a collection of instances into an encoded string. /// @@ -88,11 +104,12 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken ValidateEmptyCoordinates(ref coordinates, _logger); - CoordinateDelta delta = new(); + int valuesPerItem = ValuesPerItem; + CoordinateDelta delta = new(valuesPerItem); int position = 0; int consumed = 0; - int length = GetMaxBufferLength(coordinates.Length); + int length = GetMaxBufferLength(coordinates.Length, valuesPerItem); char[]? temp = length <= Options.StackAllocLimit ? null @@ -100,29 +117,37 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken Span buffer = temp is null ? stackalloc char[length] : temp.AsSpan(0, length); + int[]? normalizedRent = ArrayPool.Shared.Rent(valuesPerItem); + Span normalized = normalizedRent.AsSpan(0, valuesPerItem); + + double[]? valuesRent = ArrayPool.Shared.Rent(valuesPerItem); + Span values = valuesRent.AsSpan(0, valuesPerItem); + string encodedResult; try { for (var i = 0; i < coordinates.Length; i++) { cancellationToken.ThrowIfCancellationRequested(); - delta - .Next( - PolylineEncoding.Normalize(GetLatitude(coordinates[i]), Options.Precision), - PolylineEncoding.Normalize(GetLongitude(coordinates[i]), Options.Precision) - ); + GetValues(coordinates[i], values); + + for (int j = 0; j < valuesPerItem; j++) { + normalized[j] = PolylineEncoding.Normalize(values[j], Options.Precision); + } - if (!PolylineEncoding.TryWriteValue(delta.Latitude, buffer, ref position) - || !PolylineEncoding.TryWriteValue(delta.Longitude, buffer, ref position) - ) { - // This shouldn't happen, but if it does, log the error and throw an exception. - _logger - .LogOperationFailedDebug(OperationName); - _logger - .LogCannotWriteValueToBufferWarning(position, consumed); + delta.Next(normalized); - ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer(); + ReadOnlySpan deltas = delta.Deltas; + for (int j = 0; j < deltas.Length; j++) { + if (!PolylineEncoding.TryWriteValue(deltas[j], buffer, ref position)) { + // This shouldn't happen, but if it does, log the error and throw an exception. + _logger + .LogOperationFailedDebug(OperationName); + _logger + .LogCannotWriteValueToBufferWarning(position, consumed); + ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer(); + } } consumed++; @@ -130,6 +155,8 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken encodedResult = buffer[..position].ToString(); } finally { + ArrayPool.Shared.Return(valuesRent!); + ArrayPool.Shared.Return(normalizedRent!); if (temp is not null) { ArrayPool.Shared.Return(temp); } @@ -141,10 +168,10 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken return CreatePolyline(encodedResult.AsMemory()); [MethodImpl(MethodImplOptions.AggressiveInlining)] - static int GetMaxBufferLength(int count) { + static int GetMaxBufferLength(int count, int perItem) { Debug.Assert(count > 0, "Count must be greater than zero."); - int requestedBufferLength = count * 2 * Defaults.Polyline.Block.Length.Max; + int requestedBufferLength = count * perItem * Defaults.Polyline.Block.Length.Max; Debug.Assert(requestedBufferLength > 0, "Requested buffer length must be greater than zero."); @@ -175,23 +202,18 @@ static void ValidateEmptyCoordinates(ref ReadOnlySpan coordinates, protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline); /// - /// Extracts the longitude value from the specified coordinate. - /// - /// The coordinate from which to extract the longitude. - /// - /// The longitude value as a . - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract double GetLongitude(TCoordinate current); - - /// - /// Extracts the latitude value from the specified coordinate. + /// Fills with the values to encode for the specified item. /// - /// The coordinate from which to extract the latitude. - /// - /// The latitude value as a . - /// + /// The item from which to extract values. + /// + /// A of length to fill with the item's values, + /// in the order they should be encoded. + /// + /// + /// Implementations should write exactly values into . + /// For example, a 2D GPS encoder writes destination[0] = latitude; destination[1] = longitude;. + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract double GetLatitude(TCoordinate current); + protected abstract void GetValues(TCoordinate item, Span destination); } diff --git a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs index ae217c57..70826216 100644 --- a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs +++ b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs @@ -5,68 +5,82 @@ namespace PolylineAlgorithm.Internal; +using System; using System.Diagnostics; using System.Runtime.InteropServices; +using System.Text; /// -/// Represents the difference (delta) in latitude and longitude between consecutive geographic coordinates. +/// Represents the running delta state for an arbitrary number of encoded values between consecutive items. /// /// -/// This struct computes and stores the change in coordinate values as integer deltas between successive coordinates. +/// This struct computes and stores the change in each value dimension as integer deltas between successive items. +/// The number of dimensions is specified at construction time, enabling support for any number of encoded fields +/// (e.g. latitude/longitude, latitude/longitude/altitude, or arbitrary sensor fields). /// [DebuggerDisplay("{ToString(),nq}")] [StructLayout(LayoutKind.Auto)] internal struct CoordinateDelta { - private (int Latitude, int Longitude) _current; + private readonly int[] _current; + private readonly int[] _deltas; /// - /// Initializes a new instance of the struct with the default latitude and longitude deltas. + /// Initializes a new instance of the struct for the specified number of value dimensions. /// - public CoordinateDelta() { - _current = (default, default); - } + /// The number of value dimensions to track. Must be greater than zero. + public CoordinateDelta(int count) { + Debug.Assert(count > 0, "Count must be greater than zero."); - /// - /// Gets the current delta in latitude between the most recent and previous coordinate. - /// - public int Latitude { get; private set; } + _current = new int[count]; + _deltas = new int[count]; + } /// - /// Gets the current delta in longitude between the most recent and previous coordinate. + /// Gets the current deltas computed by the most recent call to . /// - public int Longitude { get; private set; } + public ReadOnlySpan Deltas => _deltas; /// - /// Updates the delta values based on the next latitude and longitude, and sets the current coordinate as next delta baseline. + /// Updates the delta values based on the next set of values, and sets them as the baseline for the next call. /// - /// The next latitude value. - /// The next longitude value. - public void Next(int latitude, int longitude) { - Latitude = Delta(_current.Latitude, latitude); - Longitude = Delta(_current.Longitude, longitude); + /// + /// The next normalized integer values. Must have the same length as the count passed to the constructor. + /// + public void Next(ReadOnlySpan values) { + Debug.Assert(values.Length == _current.Length, "Values length must match the delta dimension count."); - _current.Latitude = latitude; - _current.Longitude = longitude; + for (int i = 0; i < values.Length; i++) { + _deltas[i] = values[i] - _current[i]; + _current[i] = values[i]; + } } /// - /// Calculates the delta between two coordinate values. - /// - /// - /// This method computes the difference between two integer coordinate values, handling cases where the values may be positive or negative. - /// - /// The previous coordinate value. - /// The next coordinate value. - /// The computed delta between and . - private static int Delta(int initial, int next) => next - initial; - - /// - /// Returns a string representation of the current coordinate delta. + /// Returns a string representation of the current values and deltas. /// /// - /// A string in the format { Coordinate: { Latitude: [int], Longitude: [int] }, Delta: { Latitude: [int], Longitude: [int] } } representing the current coordinate and deltas to previous coordinate. + /// A string in the format { Values: [v0, v1, ...], Deltas: [d0, d1, ...] }. /// - public override readonly string ToString() => - $"{{ Coordinate: {{ Latitude: {_current.Latitude}, Longitude: {_current.Longitude} }}, " + - $"Delta: {{ Latitude: {Latitude}, Longitude: {Longitude} }} }}"; + public override readonly string ToString() { + var sb = new StringBuilder("{ Values: ["); + for (int i = 0; i < _current.Length; i++) { + if (i > 0) { + sb.Append(", "); + } + + sb.Append(_current[i]); + } + + sb.Append("], Deltas: ["); + for (int i = 0; i < _deltas.Length; i++) { + if (i > 0) { + sb.Append(", "); + } + + sb.Append(_deltas[i]); + } + + sb.Append("] }"); + return sb.ToString(); + } } \ No newline at end of file diff --git a/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs b/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs index cc58c702..9a422a73 100644 --- a/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs +++ b/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs @@ -46,12 +46,11 @@ internal static partial class LogDebugExtensions { internal static partial void LogOperationFinishedDebug(this ILogger logger, string operationName); /// - /// Logs a debug message containing the decoded coordinate values and position. + /// Logs a debug message containing the number of decoded values and position. /// /// The used to write the log entry. - /// The decoded latitude value. - /// The decoded longitude value. - /// The position in the polyline buffer at which the coordinate was decoded. - [LoggerMessage(EVENT_ID_BASE + 4, LOG_LEVEL, "Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}.")] - internal static partial void LogDecodedCoordinateDebug(this ILogger logger, double latitude, double longitude, int position); + /// The number of values that were decoded for this item. + /// The position in the polyline buffer at which the item was decoded. + [LoggerMessage(EVENT_ID_BASE + 4, LOG_LEVEL, "Decoded {count} values at position {position}.")] + internal static partial void LogDecodedValuesDebug(this ILogger logger, int count, int position); } diff --git a/src/PolylineAlgorithm/PolylineAlgorithm.csproj b/src/PolylineAlgorithm/PolylineAlgorithm.csproj index 24504239..907a2a15 100644 --- a/src/PolylineAlgorithm/PolylineAlgorithm.csproj +++ b/src/PolylineAlgorithm/PolylineAlgorithm.csproj @@ -8,6 +8,13 @@ True
+ + + $(WarningsAsErrors);RS0017 + + true diff --git a/src/PolylineAlgorithm/PolylineEncoding.cs b/src/PolylineAlgorithm/PolylineEncoding.cs index 4b8d5312..3d6de5e7 100644 --- a/src/PolylineAlgorithm/PolylineEncoding.cs +++ b/src/PolylineAlgorithm/PolylineEncoding.cs @@ -1,4 +1,4 @@ -// +// // Copyright © Pete Sramek. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for full license information. // @@ -76,10 +76,11 @@ public static int Normalize(double value, uint precision = 5) { uint factor = Pow10.GetFactor(precision); + const double Epsilon = 1e-9; + checked { - return (int)(Math.Truncate(value * 10 * factor) / 10); + return (int)Math.Truncate((value * factor) + (Epsilon * Math.Sign(value))); } - } /// diff --git a/src/PolylineAlgorithm/PublicAPI.Shipped.txt b/src/PolylineAlgorithm/PublicAPI.Shipped.txt index 91b0e1a4..7dc5c581 100644 --- a/src/PolylineAlgorithm/PublicAPI.Shipped.txt +++ b/src/PolylineAlgorithm/PublicAPI.Shipped.txt @@ -1 +1 @@ -#nullable enable \ No newline at end of file +#nullable enable diff --git a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt index 7dc5c581..4033ef24 100644 --- a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt +++ b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt @@ -1 +1,9 @@ #nullable enable +abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.CreateItem(System.ReadOnlyMemory values) -> TCoordinate +abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.GetReadOnlyMemory(in TPolyline polyline) -> System.ReadOnlyMemory +abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValuesPerItem.get -> int +abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.GetValues(TCoordinate item, System.Span destination) -> void +abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.ValuesPerItem.get -> int +virtual PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValidateFormat(System.ReadOnlyMemory sequence, Microsoft.Extensions.Logging.ILogger? logger) -> void +PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException() -> void +PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException(string! message, System.Exception! innerException) -> void diff --git a/src/PolylineAlgorithm/README.md b/src/PolylineAlgorithm/README.md index d1bf97e0..97c4bb98 100644 --- a/src/PolylineAlgorithm/README.md +++ b/src/PolylineAlgorithm/README.md @@ -1,6 +1,8 @@ # PolylineAlgorithm for .NET -A modern, fully compliant Google Encoded Polyline Algorithm library for .NET Standard 2.1+, supporting strong input validation, extensibility for custom coordinate types, and robust performance. +[![NuGet](https://img.shields.io/nuget/v/PolylineAlgorithm)](https://www.nuget.org/packages/PolylineAlgorithm) + +Google's Encoded Polyline Algorithm compresses sequences of geographic coordinates into a compact ASCII string, widely used in mapping APIs. This library provides a fully compliant .NET implementation with extensible, type-safe encoding and decoding APIs. ## Features @@ -59,6 +61,7 @@ var encoder = new MyPolylineEncoder(); string encoded = encoder.Encode(coordinates); // extension method for List Console.WriteLine(encoded); +// Output: "yseiHoc_MwacOjnwM" ``` ### Implement a custom decoder @@ -84,8 +87,22 @@ IEnumerable<(double Latitude, double Longitude)> decoded = decoder.Decode(encode ## Advanced Usage -- Pass a `PolylineEncodingOptions` (built via `PolylineEncodingOptionsBuilder`) to the encoder/decoder constructor for custom precision, stack-alloc limit, and logging. -- Use static methods on `PolylineEncoding` for low-level normalization, validation, and bit-level read/write operations. +Use `PolylineEncodingOptionsBuilder` to customize precision, buffer size, and logging, then pass the built options to the encoder or decoder constructor: + +```csharp +using Microsoft.Extensions.Logging; + +PolylineEncodingOptions options = PolylineEncodingOptionsBuilder.Create() + .WithPrecision(6) // 6 decimal places instead of the default 5 + .WithStackAllocLimit(1024) // increase stack-alloc buffer + .WithLoggerFactory(loggerFactory) // plug in your ILoggerFactory + .Build(); + +var encoder = new MyPolylineEncoder(options); +var decoder = new MyPolylineDecoder(options); +``` + +Use static methods on `PolylineEncoding` for low-level normalization, validation, and bit-level read/write operations. > See [API Reference](https://petesramek.github.io/polyline-algorithm-csharp/) for full documentation. @@ -93,6 +110,8 @@ IEnumerable<(double Latitude, double Longitude)> decoded = decoder.Decode(encode - **What coordinate ranges are valid?** Latitude: -90..90, Longitude: -180..180 (throws `ArgumentOutOfRangeException` for invalid input) +- **What happens if I pass malformed input to the decoder?** + The decoder throws `InvalidPolylineException` with a descriptive message. Wrap calls in a try/catch in your application. - **What .NET versions are supported?** Any environment supporting `netstandard2.1` - **How do I customize encoder options?** @@ -100,6 +119,11 @@ IEnumerable<(double Latitude, double Longitude)> decoded = decoder.Decode(encode - **Where can I get help?** [GitHub issues](https://github.com/petesramek/polyline-algorithm-csharp/issues) +## Resources + +- [GitHub Repository](https://github.com/petesramek/polyline-algorithm-csharp) — source code, issues, changelog, and samples +- [API Reference](https://petesramek.github.io/polyline-algorithm-csharp/) — full auto-generated documentation + ## License MIT License © Pete Sramek diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs index c6734c6c..b5a64627 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs @@ -16,16 +16,24 @@ namespace PolylineAlgorithm.Tests.Abstraction; [TestClass] public sealed class AbstractPolylineDecoderTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { + protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); + } } private sealed class TestStringDecoderWithOptions : AbstractPolylineDecoder { public TestStringDecoderWithOptions(PolylineEncodingOptions options) : base(options) { } + protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); + } } /// diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs index f537dda2..1500b0de 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs @@ -21,9 +21,12 @@ public TestStringEncoder() public TestStringEncoder(PolylineEncodingOptions options) : base(options) { } + protected override int ValuesPerItem => 2; protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude; - protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude; + protected override void GetValues((double Latitude, double Longitude) item, Span destination) { + destination[0] = item.Latitude; + destination[1] = item.Longitude; + } } /// diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs index c44c914d..069c639f 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs @@ -17,13 +17,21 @@ namespace PolylineAlgorithm.Tests.Extensions; [TestClass] public sealed class PolylineDecoderExtensionsTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { + protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); + } } private sealed class TestMemoryDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { + protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) => polyline; - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); + } } // ----- Decode(char[]) for IPolylineDecoder ----- diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs index da8a622e..874f168c 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs @@ -17,9 +17,12 @@ namespace PolylineAlgorithm.Tests.Extensions; [TestClass] public sealed class PolylineEncoderExtensionsTests { private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { + protected override int ValuesPerItem => 2; protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude; - protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude; + protected override void GetValues((double Latitude, double Longitude) item, Span destination) { + destination[0] = item.Latitude; + destination[1] = item.Longitude; + } } // ----- Encode(List) ----- diff --git a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs index 1e915fe2..03ef5e66 100644 --- a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs +++ b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs @@ -6,7 +6,6 @@ namespace PolylineAlgorithm.Tests.Internal; using PolylineAlgorithm.Internal; -using System.Globalization; /// /// Tests for . @@ -14,20 +13,22 @@ namespace PolylineAlgorithm.Tests.Internal; [TestClass] public sealed class CoordinateDeltaTests { /// - /// Tests that the default constructor initializes delta values to zero. + /// Tests that a newly constructed instance reports all-zero deltas. /// [TestMethod] - public void Constructor_Default_Initializes_Latitude_And_Longitude_To_Zero() { + public void Constructor_Default_Initializes_Deltas_To_Zero() { // Act - CoordinateDelta delta = new(); + CoordinateDelta delta = new(2); // Assert - Assert.AreEqual(0, delta.Latitude); - Assert.AreEqual(0, delta.Longitude); + ReadOnlySpan deltas = delta.Deltas; + Assert.AreEqual(2, deltas.Length); + Assert.AreEqual(0, deltas[0]); + Assert.AreEqual(0, deltas[1]); } /// - /// Tests that a single call to Next computes the correct delta from the initial zero state. + /// Tests that a single call to Next computes the correct delta from the initial zero state for 2 values. /// [TestMethod] [DataRow(10, 20, 10, 20)] @@ -35,59 +36,94 @@ public void Constructor_Default_Initializes_Latitude_And_Longitude_To_Zero() { [DataRow(0, 0, 0, 0)] [DataRow(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue)] [DataRow(int.MinValue, int.MinValue, int.MinValue, int.MinValue)] - public void Next_Single_Call_From_Zero_Computes_Expected_Delta(int latitude, int longitude, int expectedLatitude, int expectedLongitude) { + public void Next_Single_Call_From_Zero_Computes_Expected_Delta_For_Two_Values(int v0, int v1, int expectedD0, int expectedD1) { // Arrange - CoordinateDelta delta = new(); + CoordinateDelta delta = new(2); // Act - delta.Next(latitude, longitude); + delta.Next([v0, v1]); // Assert - Assert.AreEqual(expectedLatitude, delta.Latitude); - Assert.AreEqual(expectedLongitude, delta.Longitude); + ReadOnlySpan deltas = delta.Deltas; + Assert.AreEqual(expectedD0, deltas[0]); + Assert.AreEqual(expectedD1, deltas[1]); } /// - /// Tests that two consecutive calls to Next compute the delta relative to the previous value. + /// Tests that two consecutive calls to Next compute the delta relative to the previous value for 2 values. /// [TestMethod] [DataRow(10, 20, 15, 30, 5, 10)] [DataRow(100, 200, 50, 150, -50, -50)] [DataRow(42, 84, 42, 84, 0, 0)] [DataRow(-50, 100, 25, -75, 75, -175)] - public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value( - int firstLatitude, int firstLongitude, - int secondLatitude, int secondLongitude, - int expectedLatitude, int expectedLongitude) { + public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value_For_Two_Values( + int first0, int first1, + int second0, int second1, + int expectedD0, int expectedD1) { // Arrange - CoordinateDelta delta = new(); - delta.Next(firstLatitude, firstLongitude); + CoordinateDelta delta = new(2); + delta.Next([first0, first1]); // Act - delta.Next(secondLatitude, secondLongitude); + delta.Next([second0, second1]); // Assert - Assert.AreEqual(expectedLatitude, delta.Latitude); - Assert.AreEqual(expectedLongitude, delta.Longitude); + ReadOnlySpan deltas = delta.Deltas; + Assert.AreEqual(expectedD0, deltas[0]); + Assert.AreEqual(expectedD1, deltas[1]); } /// - /// Tests that ToString on a default instance returns a string containing expected structural keywords and a zero value. + /// Tests that Next works correctly for a single value dimension. + /// + [TestMethod] + public void Next_Single_Dimension_Computes_Correct_Delta() { + // Arrange + CoordinateDelta delta = new(1); + delta.Next([100]); + + // Act + delta.Next([150]); + + // Assert + Assert.AreEqual(50, delta.Deltas[0]); + } + + /// + /// Tests that Next works correctly for three value dimensions. + /// + [TestMethod] + public void Next_Three_Dimensions_Computes_Correct_Deltas() { + // Arrange + CoordinateDelta delta = new(3); + delta.Next([10, 20, 30]); + + // Act + delta.Next([15, 25, 25]); + + // Assert + ReadOnlySpan deltas = delta.Deltas; + Assert.AreEqual(5, deltas[0]); + Assert.AreEqual(5, deltas[1]); + Assert.AreEqual(-5, deltas[2]); + } + + /// + /// Tests that ToString on a default instance returns a non-null string containing structural keywords. /// [TestMethod] public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zeros() { // Arrange - CoordinateDelta delta = new(); + CoordinateDelta delta = new(2); // Act string result = delta.ToString(); // Assert Assert.IsNotNull(result); - Assert.IsTrue(result.Contains("Coordinate", StringComparison.Ordinal)); - Assert.IsTrue(result.Contains("Delta", StringComparison.Ordinal)); - Assert.IsTrue(result.Contains("Latitude", StringComparison.Ordinal)); - Assert.IsTrue(result.Contains("Longitude", StringComparison.Ordinal)); + Assert.IsTrue(result.Contains("Values", StringComparison.Ordinal)); + Assert.IsTrue(result.Contains("Deltas", StringComparison.Ordinal)); Assert.Contains('0', result); } @@ -97,20 +133,18 @@ public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zero [TestMethod] [DataRow(42, 84)] [DataRow(-100, -200)] - [DataRow(int.MaxValue, int.MaxValue)] - [DataRow(int.MinValue, int.MinValue)] - public void ToString_After_Next_Contains_Expected_Values(int latitude, int longitude) { + public void ToString_After_Next_Contains_Expected_Values(int v0, int v1) { // Arrange - CoordinateDelta delta = new(); - delta.Next(latitude, longitude); + CoordinateDelta delta = new(2); + delta.Next([v0, v1]); // Act string result = delta.ToString(); // Assert Assert.IsNotNull(result); - Assert.IsTrue(result.Contains(latitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal)); - Assert.IsTrue(result.Contains(longitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal)); + Assert.IsTrue(result.Contains(v0.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.Ordinal)); + Assert.IsTrue(result.Contains(v1.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.Ordinal)); } /// @@ -119,9 +153,9 @@ public void ToString_After_Next_Contains_Expected_Values(int latitude, int longi [TestMethod] public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Latest_Values() { // Arrange - CoordinateDelta delta = new(); - delta.Next(10, 20); - delta.Next(30, 50); + CoordinateDelta delta = new(2); + delta.Next([10, 20]); + delta.Next([30, 50]); // Act string result = delta.ToString(); @@ -132,5 +166,5 @@ public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Lat Assert.IsTrue(result.Contains("50", StringComparison.Ordinal)); Assert.IsTrue(result.Contains("20", StringComparison.Ordinal)); } - } + diff --git a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs index 0dff7193..c9daaa1f 100644 --- a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs @@ -80,20 +80,21 @@ public void LogOperationFinishedDebug_With_Operation_Name_Logs_Finished_Message( } /// - /// Tests that LogDecodedCoordinateDebug WithCoordinatesAndPosition LogsDecodedCoordinateMessage. + /// Tests that LogDecodedValuesDebug WithCountAndPosition LogsDecodedValuesMessage. /// [TestMethod] - public void LogDecodedCoordinateDebug_With_Coordinates_And_Position_Logs_Decoded_Coordinate_Message() { + public void LogDecodedValuesDebug_With_Count_And_Position_Logs_Decoded_Values_Message() { var logger = new TestLogger(); - const double latitude = 38.5; - const double longitude = -120.2; + const int count = 2; const int position = 42; - logger.LogDecodedCoordinateDebug(latitude, longitude, position); + logger.LogDecodedValuesDebug(count, position); Assert.HasCount(1, logger.Logs); Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level); - Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}."), logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains("Decoded", logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains(count.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains(position.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal); } /// @@ -142,37 +143,35 @@ public void LogOperationFinishedDebug_With_Null_Operation_Name_Logs_Message() { } /// - /// Tests that LogDecodedCoordinateDebug WithZeroCoordinates LogsMessage. + /// Tests that LogDecodedValuesDebug WithZeroCountAndPosition LogsMessage. /// [TestMethod] - public void LogDecodedCoordinateDebug_With_Zero_Coordinates_Logs_Message() { + public void LogDecodedValuesDebug_With_Zero_Count_Logs_Message() { var logger = new TestLogger(); - const double latitude = 0.0; - const double longitude = 0.0; + const int count = 0; const int position = 0; - logger.LogDecodedCoordinateDebug(latitude, longitude, position); + logger.LogDecodedValuesDebug(count, position); Assert.HasCount(1, logger.Logs); Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level); - Assert.Contains("Decoded coordinate", logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains("Decoded", logger.Logs[0].Message, StringComparison.Ordinal); } /// - /// Tests that LogDecodedCoordinateDebug WithNegativeCoordinates LogsMessage. + /// Tests that LogDecodedValuesDebug WithLargeCount LogsMessage. /// [TestMethod] - public void LogDecodedCoordinateDebug_With_Negative_Coordinates_Logs_Message() { + public void LogDecodedValuesDebug_With_Large_Count_Logs_Message() { var logger = new TestLogger(); - const double latitude = -90.0; - const double longitude = -180.0; + const int count = 5; const int position = 100; - logger.LogDecodedCoordinateDebug(latitude, longitude, position); + logger.LogDecodedValuesDebug(count, position); Assert.HasCount(1, logger.Logs); Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level); - Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Latitude: {latitude}, Longitude: {longitude}"), logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains(count.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal); } /// diff --git a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs index d3d83b9e..0ca40426 100644 --- a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs +++ b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs @@ -105,16 +105,15 @@ private readonly struct PolylineCoordinateCollectionPair(IEnumerable<(double Lat private sealed class PolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { + protected override int ValuesPerItem => 2; + protected override string CreatePolyline(ReadOnlyMemory polyline) { return polyline.ToString(); } - protected override double GetLatitude((double Latitude, double Longitude) current) { - return current.Latitude; - } - - protected override double GetLongitude((double Latitude, double Longitude) current) { - return current.Longitude; + protected override void GetValues((double Latitude, double Longitude) item, Span destination) { + destination[0] = item.Latitude; + destination[1] = item.Longitude; } } } \ No newline at end of file From 9660b87c4167fa7eab103ca9cd6b613738e4ef44 Mon Sep 17 00:00:00 2001 From: Pete Sramek <2333452+petesramek@users.noreply.github.com> Date: Mon, 6 Apr 2026 00:06:42 +0200 Subject: [PATCH 04/24] Revert "refactor: replace fixed lat/lon pair contract with N-value GetValues/CreateItem/ValuesPerItem" This reverts commit a94f7c7f194754782d429a469a8b75ec3c169d5d. --- .../PolylineDecoderBenchmark.cs | 18 +-- .../PolylineEncoderBenchmark.cs | 7 +- .../NetTopologyPolylineDecoder.cs | 17 +-- .../NetTopologyPolylineEncoder.cs | 35 +++--- .../Abstraction/AbstractPolylineDecoder.cs | 77 ++++-------- .../Abstraction/AbstractPolylineEncoder.cs | 98 ++++++--------- .../Internal/CoordinateDelta.cs | 88 ++++++-------- .../Diagnostics/LogDebugExtensions.cs | 11 +- src/PolylineAlgorithm/PublicAPI.Unshipped.txt | 8 -- .../AbstractPolylineDecoderTests.cs | 12 +- .../AbstractPolylineEncoderTests.cs | 7 +- .../PolylineDecoderExtensionsTests.cs | 12 +- .../PolylineEncoderExtensionsTests.cs | 7 +- .../Internal/CoordinateDeltaTests.cs | 112 ++++++------------ .../Diagnostics/LogDebugExtensionsTests.cs | 35 +++--- .../RandomValueProvider.cs | 11 +- 16 files changed, 206 insertions(+), 349 deletions(-) diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs index b6b54081..f28c8141 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs @@ -93,10 +93,8 @@ public void PolylineDecoder_Decode_Memory() { } private sealed class StringPolylineDecoder : AbstractPolylineDecoder { - protected override int ValuesPerItem => 2; - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); + protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) { + return (latitude, longitude); } protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { @@ -105,10 +103,8 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { } private sealed class CharArrayPolylineDecoder : AbstractPolylineDecoder { - protected override int ValuesPerItem => 2; - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); + protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) { + return (latitude, longitude); } protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) { @@ -117,10 +113,8 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) { } private sealed class MemoryCharPolylineDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { - protected override int ValuesPerItem => 2; - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); + protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) { + return (latitude, longitude); } protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) { diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs index c4b9d5a8..e0b97c5c 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs @@ -85,11 +85,8 @@ public void PolylineEncoder_Encode_List() { } private sealed class StringPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - protected override int ValuesPerItem => 2; protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override void GetValues((double Latitude, double Longitude) item, Span destination) { - destination[0] = item.Latitude; - destination[1] = item.Longitude; - } + protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude; + protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude; } } diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs index dd05ca88..d7dcb13e 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs @@ -14,21 +14,14 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; /// internal sealed class NetTopologyPolylineDecoder : AbstractPolylineDecoder { /// - /// Gets the number of encoded values per item: latitude (index 0) and longitude (index 1). + /// Creates a NetTopologySuite point from latitude and longitude. /// - protected override int ValuesPerItem => 2; - - /// - /// Creates a NetTopologySuite point from the decoded values. - /// - /// - /// A memory region containing two values: index 0 is latitude, index 1 is longitude. - /// + /// Latitude value. + /// Longitude value. /// Point instance. - protected override Point CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; + protected override Point CreateCoordinate(double latitude, double longitude) { // NetTopologySuite Point: x = longitude, y = latitude - return new Point(span[1], span[0]); + return new Point(longitude, latitude); } /// diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs index 5a7b5529..c6719000 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs @@ -7,17 +7,11 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; using global::NetTopologySuite.Geometries; using PolylineAlgorithm.Abstraction; -using System; /// /// Polyline encoder using NetTopologySuite's Point type. /// internal sealed class NetTopologyPolylineEncoder : AbstractPolylineEncoder { - /// - /// Gets the number of values per item: latitude (index 0) and longitude (index 1). - /// - protected override int ValuesPerItem => 2; - /// /// Creates encoded polyline string from memory. /// @@ -32,15 +26,26 @@ protected override string CreatePolyline(ReadOnlyMemory polyline) { } /// - /// Fills destination with latitude (index 0) and longitude (index 1) from the point. + /// Gets latitude from point. /// - /// Point instance. - /// Span of length 2 to fill. - protected override void GetValues(Point item, Span destination) { - ArgumentNullException.ThrowIfNull(item); - - // NetTopologySuite Point: Y = latitude, X = longitude - destination[0] = item.Y; - destination[1] = item.X; + /// Point instance. + /// Latitude value. + protected override double GetLatitude(Point current) { + ArgumentNullException.ThrowIfNull(current); + + // NetTopologySuite Point: Y = latitude + return current.Y; + } + + /// + /// Gets longitude from point. + /// + /// Point instance. + /// Longitude value. + protected override double GetLongitude(Point current) { + ArgumentNullException.ThrowIfNull(current); + + // NetTopologySuite Point: X = longitude + return current.X; } } \ No newline at end of file diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs index ea087776..1059abb9 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs @@ -6,27 +6,19 @@ using Microsoft.Extensions.Logging; using PolylineAlgorithm.Internal; using PolylineAlgorithm.Internal.Diagnostics; -using System.Buffers; using System.Runtime.CompilerServices; namespace PolylineAlgorithm.Abstraction; /// -/// Provides a base implementation for decoding encoded polyline strings into sequences of items. +/// Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates. /// /// -/// Derive from this class to implement a decoder for a specific polyline type. Override -/// , , and to provide -/// type-specific behavior. -/// -/// The polyline format encodes each item as a fixed-length run of delta-compressed -/// values. All items in a single polyline must have the same number of values. For example, a 2D GPS decoder -/// sets to 2 (latitude, longitude), while a 3D GPS decoder sets it to 3 -/// (latitude, longitude, altitude). -/// +/// Derive from this class to implement a decoder for a specific polyline type. Override +/// and to provide type-specific behavior. /// /// The type that represents the encoded polyline input. -/// The type that represents a decoded item. +/// The type that represents a decoded geographic coordinate. public abstract class AbstractPolylineDecoder : IPolylineDecoder { private readonly ILogger> _logger; @@ -61,16 +53,6 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) { /// public PolylineEncodingOptions Options { get; } - /// - /// Gets the number of encoded values that make up a single decoded item. - /// - /// - /// Override this property to specify the arity of each item. For example, return 2 for - /// latitude/longitude pairs, 3 for latitude/longitude/altitude triples, or any other count - /// that matches the encoding scheme used to produce the polyline. - /// - protected abstract int ValuesPerItem { get; } - /// /// Decodes an encoded into a sequence of instances, /// with support for cancellation. @@ -82,7 +64,7 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) { /// A that can be used to cancel the decoding operation. /// /// - /// An of representing the decoded items. + /// An of representing the decoded latitude and longitude pairs. /// /// /// Thrown when is . @@ -108,45 +90,30 @@ public IEnumerable Decode(TPolyline polyline, CancellationToken can ValidateSequence(sequence, _logger); ValidateFormat(sequence, _logger); - int valuesPerItem = ValuesPerItem; int position = 0; - - int[]? runningRent = ArrayPool.Shared.Rent(valuesPerItem); - // Zero-initialize so delta decoding starts from 0 for all dimensions. - for (int j = 0; j < valuesPerItem; j++) { - runningRent[j] = 0; - } + int encodedLatitude = 0; + int encodedLongitude = 0; try { while (position < sequence.Length) { cancellationToken.ThrowIfCancellationRequested(); - bool allRead = true; - for (int j = 0; j < valuesPerItem; j++) { - if (!PolylineEncoding.TryReadValue(ref runningRent[j], sequence, ref position)) { - allRead = false; - break; - } - } - - if (!allRead) { + if (!PolylineEncoding.TryReadValue(ref encodedLatitude, sequence, ref position) + || !PolylineEncoding.TryReadValue(ref encodedLongitude, sequence, ref position)) { _logger?.LogOperationFailedDebug(OperationName); _logger?.LogInvalidPolylineWarning(position); ExceptionGuard.ThrowInvalidPolylineFormat(position); } - double[] decoded = new double[valuesPerItem]; - for (int j = 0; j < valuesPerItem; j++) { - decoded[j] = PolylineEncoding.Denormalize(runningRent[j], Options.Precision); - } + double decodedLatitude = PolylineEncoding.Denormalize(encodedLatitude, Options.Precision); + double decodedLongitude = PolylineEncoding.Denormalize(encodedLongitude, Options.Precision); - _logger?.LogDecodedValuesDebug(valuesPerItem, position); + _logger?.LogDecodedCoordinateDebug(decodedLatitude, decodedLongitude, position); - yield return CreateItem(decoded.AsMemory()); + yield return CreateCoordinate(decodedLatitude, decodedLongitude); } } finally { - ArrayPool.Shared.Return(runningRent!); _logger?.LogOperationFinishedDebug(OperationName); } } @@ -221,19 +188,17 @@ protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? lo protected abstract ReadOnlyMemory GetReadOnlyMemory(in TPolyline polyline); /// - /// Creates a instance from the specified decoded values. + /// Creates a instance from the specified latitude and longitude values. /// - /// - /// A of containing exactly - /// decoded values for this item, in the same order they were encoded. + /// + /// The latitude component of the coordinate, in degrees. + /// + /// + /// The longitude component of the coordinate, in degrees. /// /// - /// A instance representing the decoded item. + /// A instance representing the specified geographic coordinate. /// - /// - /// Implementations should read all required values from and construct the - /// immediately. The memory is valid only for the duration of this call. - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract TCoordinate CreateItem(ReadOnlyMemory values); + protected abstract TCoordinate CreateCoordinate(double latitude, double longitude); } diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs index dff4eac3..1bcdb0ee 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs @@ -16,19 +16,13 @@ namespace PolylineAlgorithm.Abstraction; using System.Threading; /// -/// Provides a base implementation for encoding sequences of items into encoded polyline strings. +/// Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings. /// /// -/// Derive from this class to implement an encoder for a specific item and polyline type. Override -/// , , and to provide type-specific behavior. -/// -/// The polyline format encodes each item as a fixed-length run of delta-compressed -/// values. All items in a single polyline must have the same number of values. For example, a 2D GPS encoder -/// sets to 2 (latitude, longitude), while a 3D GPS encoder sets it to 3 -/// (latitude, longitude, altitude). -/// +/// Derive from this class to implement an encoder for a specific coordinate and polyline type. Override +/// , , and to provide type-specific behavior. /// -/// The type that represents an item to encode. +/// The type that represents a geographic coordinate to encode. /// The type that represents the encoded polyline output. public abstract class AbstractPolylineEncoder : IPolylineEncoder { private readonly ILogger> _logger; @@ -62,16 +56,6 @@ protected AbstractPolylineEncoder(PolylineEncodingOptions options) { /// public PolylineEncodingOptions Options { get; } - /// - /// Gets the number of values that make up a single encoded item. - /// - /// - /// Override this property to specify the arity of each item. For example, return 2 for - /// latitude/longitude pairs, 3 for latitude/longitude/altitude triples, or any other count - /// that matches your encoding scheme. - /// - protected abstract int ValuesPerItem { get; } - /// /// Encodes a collection of instances into an encoded string. /// @@ -104,12 +88,11 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken ValidateEmptyCoordinates(ref coordinates, _logger); - int valuesPerItem = ValuesPerItem; - CoordinateDelta delta = new(valuesPerItem); + CoordinateDelta delta = new(); int position = 0; int consumed = 0; - int length = GetMaxBufferLength(coordinates.Length, valuesPerItem); + int length = GetMaxBufferLength(coordinates.Length); char[]? temp = length <= Options.StackAllocLimit ? null @@ -117,37 +100,29 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken Span buffer = temp is null ? stackalloc char[length] : temp.AsSpan(0, length); - int[]? normalizedRent = ArrayPool.Shared.Rent(valuesPerItem); - Span normalized = normalizedRent.AsSpan(0, valuesPerItem); - - double[]? valuesRent = ArrayPool.Shared.Rent(valuesPerItem); - Span values = valuesRent.AsSpan(0, valuesPerItem); - string encodedResult; try { for (var i = 0; i < coordinates.Length; i++) { cancellationToken.ThrowIfCancellationRequested(); - GetValues(coordinates[i], values); - - for (int j = 0; j < valuesPerItem; j++) { - normalized[j] = PolylineEncoding.Normalize(values[j], Options.Precision); - } + delta + .Next( + PolylineEncoding.Normalize(GetLatitude(coordinates[i]), Options.Precision), + PolylineEncoding.Normalize(GetLongitude(coordinates[i]), Options.Precision) + ); - delta.Next(normalized); + if (!PolylineEncoding.TryWriteValue(delta.Latitude, buffer, ref position) + || !PolylineEncoding.TryWriteValue(delta.Longitude, buffer, ref position) + ) { + // This shouldn't happen, but if it does, log the error and throw an exception. + _logger + .LogOperationFailedDebug(OperationName); + _logger + .LogCannotWriteValueToBufferWarning(position, consumed); - ReadOnlySpan deltas = delta.Deltas; - for (int j = 0; j < deltas.Length; j++) { - if (!PolylineEncoding.TryWriteValue(deltas[j], buffer, ref position)) { - // This shouldn't happen, but if it does, log the error and throw an exception. - _logger - .LogOperationFailedDebug(OperationName); - _logger - .LogCannotWriteValueToBufferWarning(position, consumed); + ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer(); - ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer(); - } } consumed++; @@ -155,8 +130,6 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken encodedResult = buffer[..position].ToString(); } finally { - ArrayPool.Shared.Return(valuesRent!); - ArrayPool.Shared.Return(normalizedRent!); if (temp is not null) { ArrayPool.Shared.Return(temp); } @@ -168,10 +141,10 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken return CreatePolyline(encodedResult.AsMemory()); [MethodImpl(MethodImplOptions.AggressiveInlining)] - static int GetMaxBufferLength(int count, int perItem) { + static int GetMaxBufferLength(int count) { Debug.Assert(count > 0, "Count must be greater than zero."); - int requestedBufferLength = count * perItem * Defaults.Polyline.Block.Length.Max; + int requestedBufferLength = count * 2 * Defaults.Polyline.Block.Length.Max; Debug.Assert(requestedBufferLength > 0, "Requested buffer length must be greater than zero."); @@ -202,18 +175,23 @@ static void ValidateEmptyCoordinates(ref ReadOnlySpan coordinates, protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline); /// - /// Fills with the values to encode for the specified item. + /// Extracts the longitude value from the specified coordinate. /// - /// The item from which to extract values. - /// - /// A of length to fill with the item's values, - /// in the order they should be encoded. - /// - /// - /// Implementations should write exactly values into . - /// For example, a 2D GPS encoder writes destination[0] = latitude; destination[1] = longitude;. - /// + /// The coordinate from which to extract the longitude. + /// + /// The longitude value as a . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected abstract double GetLongitude(TCoordinate current); + + /// + /// Extracts the latitude value from the specified coordinate. + /// + /// The coordinate from which to extract the latitude. + /// + /// The latitude value as a . + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract void GetValues(TCoordinate item, Span destination); + protected abstract double GetLatitude(TCoordinate current); } diff --git a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs index 70826216..ae217c57 100644 --- a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs +++ b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs @@ -5,82 +5,68 @@ namespace PolylineAlgorithm.Internal; -using System; using System.Diagnostics; using System.Runtime.InteropServices; -using System.Text; /// -/// Represents the running delta state for an arbitrary number of encoded values between consecutive items. +/// Represents the difference (delta) in latitude and longitude between consecutive geographic coordinates. /// /// -/// This struct computes and stores the change in each value dimension as integer deltas between successive items. -/// The number of dimensions is specified at construction time, enabling support for any number of encoded fields -/// (e.g. latitude/longitude, latitude/longitude/altitude, or arbitrary sensor fields). +/// This struct computes and stores the change in coordinate values as integer deltas between successive coordinates. /// [DebuggerDisplay("{ToString(),nq}")] [StructLayout(LayoutKind.Auto)] internal struct CoordinateDelta { - private readonly int[] _current; - private readonly int[] _deltas; + private (int Latitude, int Longitude) _current; /// - /// Initializes a new instance of the struct for the specified number of value dimensions. + /// Initializes a new instance of the struct with the default latitude and longitude deltas. /// - /// The number of value dimensions to track. Must be greater than zero. - public CoordinateDelta(int count) { - Debug.Assert(count > 0, "Count must be greater than zero."); - - _current = new int[count]; - _deltas = new int[count]; + public CoordinateDelta() { + _current = (default, default); } /// - /// Gets the current deltas computed by the most recent call to . + /// Gets the current delta in latitude between the most recent and previous coordinate. + /// + public int Latitude { get; private set; } + + /// + /// Gets the current delta in longitude between the most recent and previous coordinate. /// - public ReadOnlySpan Deltas => _deltas; + public int Longitude { get; private set; } /// - /// Updates the delta values based on the next set of values, and sets them as the baseline for the next call. + /// Updates the delta values based on the next latitude and longitude, and sets the current coordinate as next delta baseline. /// - /// - /// The next normalized integer values. Must have the same length as the count passed to the constructor. - /// - public void Next(ReadOnlySpan values) { - Debug.Assert(values.Length == _current.Length, "Values length must match the delta dimension count."); + /// The next latitude value. + /// The next longitude value. + public void Next(int latitude, int longitude) { + Latitude = Delta(_current.Latitude, latitude); + Longitude = Delta(_current.Longitude, longitude); - for (int i = 0; i < values.Length; i++) { - _deltas[i] = values[i] - _current[i]; - _current[i] = values[i]; - } + _current.Latitude = latitude; + _current.Longitude = longitude; } /// - /// Returns a string representation of the current values and deltas. + /// Calculates the delta between two coordinate values. + /// + /// + /// This method computes the difference between two integer coordinate values, handling cases where the values may be positive or negative. + /// + /// The previous coordinate value. + /// The next coordinate value. + /// The computed delta between and . + private static int Delta(int initial, int next) => next - initial; + + /// + /// Returns a string representation of the current coordinate delta. /// /// - /// A string in the format { Values: [v0, v1, ...], Deltas: [d0, d1, ...] }. + /// A string in the format { Coordinate: { Latitude: [int], Longitude: [int] }, Delta: { Latitude: [int], Longitude: [int] } } representing the current coordinate and deltas to previous coordinate. /// - public override readonly string ToString() { - var sb = new StringBuilder("{ Values: ["); - for (int i = 0; i < _current.Length; i++) { - if (i > 0) { - sb.Append(", "); - } - - sb.Append(_current[i]); - } - - sb.Append("], Deltas: ["); - for (int i = 0; i < _deltas.Length; i++) { - if (i > 0) { - sb.Append(", "); - } - - sb.Append(_deltas[i]); - } - - sb.Append("] }"); - return sb.ToString(); - } + public override readonly string ToString() => + $"{{ Coordinate: {{ Latitude: {_current.Latitude}, Longitude: {_current.Longitude} }}, " + + $"Delta: {{ Latitude: {Latitude}, Longitude: {Longitude} }} }}"; } \ No newline at end of file diff --git a/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs b/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs index 9a422a73..cc58c702 100644 --- a/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs +++ b/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs @@ -46,11 +46,12 @@ internal static partial class LogDebugExtensions { internal static partial void LogOperationFinishedDebug(this ILogger logger, string operationName); /// - /// Logs a debug message containing the number of decoded values and position. + /// Logs a debug message containing the decoded coordinate values and position. /// /// The used to write the log entry. - /// The number of values that were decoded for this item. - /// The position in the polyline buffer at which the item was decoded. - [LoggerMessage(EVENT_ID_BASE + 4, LOG_LEVEL, "Decoded {count} values at position {position}.")] - internal static partial void LogDecodedValuesDebug(this ILogger logger, int count, int position); + /// The decoded latitude value. + /// The decoded longitude value. + /// The position in the polyline buffer at which the coordinate was decoded. + [LoggerMessage(EVENT_ID_BASE + 4, LOG_LEVEL, "Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}.")] + internal static partial void LogDecodedCoordinateDebug(this ILogger logger, double latitude, double longitude, int position); } diff --git a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt index 4033ef24..7dc5c581 100644 --- a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt +++ b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt @@ -1,9 +1 @@ #nullable enable -abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.CreateItem(System.ReadOnlyMemory values) -> TCoordinate -abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.GetReadOnlyMemory(in TPolyline polyline) -> System.ReadOnlyMemory -abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValuesPerItem.get -> int -abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.GetValues(TCoordinate item, System.Span destination) -> void -abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.ValuesPerItem.get -> int -virtual PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValidateFormat(System.ReadOnlyMemory sequence, Microsoft.Extensions.Logging.ILogger? logger) -> void -PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException() -> void -PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException(string! message, System.Exception! innerException) -> void diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs index b5a64627..c6734c6c 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs @@ -16,24 +16,16 @@ namespace PolylineAlgorithm.Tests.Abstraction; [TestClass] public sealed class AbstractPolylineDecoderTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { - protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); - } + protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); } private sealed class TestStringDecoderWithOptions : AbstractPolylineDecoder { public TestStringDecoderWithOptions(PolylineEncodingOptions options) : base(options) { } - protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); - } + protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); } /// diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs index 1500b0de..f537dda2 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs @@ -21,12 +21,9 @@ public TestStringEncoder() public TestStringEncoder(PolylineEncodingOptions options) : base(options) { } - protected override int ValuesPerItem => 2; protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override void GetValues((double Latitude, double Longitude) item, Span destination) { - destination[0] = item.Latitude; - destination[1] = item.Longitude; - } + protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude; + protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude; } /// diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs index 069c639f..c44c914d 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs @@ -17,21 +17,13 @@ namespace PolylineAlgorithm.Tests.Extensions; [TestClass] public sealed class PolylineDecoderExtensionsTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { - protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); - } + protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); } private sealed class TestMemoryDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { - protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) => polyline; - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); - } + protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); } // ----- Decode(char[]) for IPolylineDecoder ----- diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs index 874f168c..da8a622e 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs @@ -17,12 +17,9 @@ namespace PolylineAlgorithm.Tests.Extensions; [TestClass] public sealed class PolylineEncoderExtensionsTests { private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - protected override int ValuesPerItem => 2; protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override void GetValues((double Latitude, double Longitude) item, Span destination) { - destination[0] = item.Latitude; - destination[1] = item.Longitude; - } + protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude; + protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude; } // ----- Encode(List) ----- diff --git a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs index 03ef5e66..1e915fe2 100644 --- a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs +++ b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs @@ -6,6 +6,7 @@ namespace PolylineAlgorithm.Tests.Internal; using PolylineAlgorithm.Internal; +using System.Globalization; /// /// Tests for . @@ -13,22 +14,20 @@ namespace PolylineAlgorithm.Tests.Internal; [TestClass] public sealed class CoordinateDeltaTests { /// - /// Tests that a newly constructed instance reports all-zero deltas. + /// Tests that the default constructor initializes delta values to zero. /// [TestMethod] - public void Constructor_Default_Initializes_Deltas_To_Zero() { + public void Constructor_Default_Initializes_Latitude_And_Longitude_To_Zero() { // Act - CoordinateDelta delta = new(2); + CoordinateDelta delta = new(); // Assert - ReadOnlySpan deltas = delta.Deltas; - Assert.AreEqual(2, deltas.Length); - Assert.AreEqual(0, deltas[0]); - Assert.AreEqual(0, deltas[1]); + Assert.AreEqual(0, delta.Latitude); + Assert.AreEqual(0, delta.Longitude); } /// - /// Tests that a single call to Next computes the correct delta from the initial zero state for 2 values. + /// Tests that a single call to Next computes the correct delta from the initial zero state. /// [TestMethod] [DataRow(10, 20, 10, 20)] @@ -36,94 +35,59 @@ public void Constructor_Default_Initializes_Deltas_To_Zero() { [DataRow(0, 0, 0, 0)] [DataRow(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue)] [DataRow(int.MinValue, int.MinValue, int.MinValue, int.MinValue)] - public void Next_Single_Call_From_Zero_Computes_Expected_Delta_For_Two_Values(int v0, int v1, int expectedD0, int expectedD1) { + public void Next_Single_Call_From_Zero_Computes_Expected_Delta(int latitude, int longitude, int expectedLatitude, int expectedLongitude) { // Arrange - CoordinateDelta delta = new(2); + CoordinateDelta delta = new(); // Act - delta.Next([v0, v1]); + delta.Next(latitude, longitude); // Assert - ReadOnlySpan deltas = delta.Deltas; - Assert.AreEqual(expectedD0, deltas[0]); - Assert.AreEqual(expectedD1, deltas[1]); + Assert.AreEqual(expectedLatitude, delta.Latitude); + Assert.AreEqual(expectedLongitude, delta.Longitude); } /// - /// Tests that two consecutive calls to Next compute the delta relative to the previous value for 2 values. + /// Tests that two consecutive calls to Next compute the delta relative to the previous value. /// [TestMethod] [DataRow(10, 20, 15, 30, 5, 10)] [DataRow(100, 200, 50, 150, -50, -50)] [DataRow(42, 84, 42, 84, 0, 0)] [DataRow(-50, 100, 25, -75, 75, -175)] - public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value_For_Two_Values( - int first0, int first1, - int second0, int second1, - int expectedD0, int expectedD1) { + public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value( + int firstLatitude, int firstLongitude, + int secondLatitude, int secondLongitude, + int expectedLatitude, int expectedLongitude) { // Arrange - CoordinateDelta delta = new(2); - delta.Next([first0, first1]); + CoordinateDelta delta = new(); + delta.Next(firstLatitude, firstLongitude); // Act - delta.Next([second0, second1]); + delta.Next(secondLatitude, secondLongitude); // Assert - ReadOnlySpan deltas = delta.Deltas; - Assert.AreEqual(expectedD0, deltas[0]); - Assert.AreEqual(expectedD1, deltas[1]); + Assert.AreEqual(expectedLatitude, delta.Latitude); + Assert.AreEqual(expectedLongitude, delta.Longitude); } /// - /// Tests that Next works correctly for a single value dimension. - /// - [TestMethod] - public void Next_Single_Dimension_Computes_Correct_Delta() { - // Arrange - CoordinateDelta delta = new(1); - delta.Next([100]); - - // Act - delta.Next([150]); - - // Assert - Assert.AreEqual(50, delta.Deltas[0]); - } - - /// - /// Tests that Next works correctly for three value dimensions. - /// - [TestMethod] - public void Next_Three_Dimensions_Computes_Correct_Deltas() { - // Arrange - CoordinateDelta delta = new(3); - delta.Next([10, 20, 30]); - - // Act - delta.Next([15, 25, 25]); - - // Assert - ReadOnlySpan deltas = delta.Deltas; - Assert.AreEqual(5, deltas[0]); - Assert.AreEqual(5, deltas[1]); - Assert.AreEqual(-5, deltas[2]); - } - - /// - /// Tests that ToString on a default instance returns a non-null string containing structural keywords. + /// Tests that ToString on a default instance returns a string containing expected structural keywords and a zero value. /// [TestMethod] public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zeros() { // Arrange - CoordinateDelta delta = new(2); + CoordinateDelta delta = new(); // Act string result = delta.ToString(); // Assert Assert.IsNotNull(result); - Assert.IsTrue(result.Contains("Values", StringComparison.Ordinal)); - Assert.IsTrue(result.Contains("Deltas", StringComparison.Ordinal)); + Assert.IsTrue(result.Contains("Coordinate", StringComparison.Ordinal)); + Assert.IsTrue(result.Contains("Delta", StringComparison.Ordinal)); + Assert.IsTrue(result.Contains("Latitude", StringComparison.Ordinal)); + Assert.IsTrue(result.Contains("Longitude", StringComparison.Ordinal)); Assert.Contains('0', result); } @@ -133,18 +97,20 @@ public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zero [TestMethod] [DataRow(42, 84)] [DataRow(-100, -200)] - public void ToString_After_Next_Contains_Expected_Values(int v0, int v1) { + [DataRow(int.MaxValue, int.MaxValue)] + [DataRow(int.MinValue, int.MinValue)] + public void ToString_After_Next_Contains_Expected_Values(int latitude, int longitude) { // Arrange - CoordinateDelta delta = new(2); - delta.Next([v0, v1]); + CoordinateDelta delta = new(); + delta.Next(latitude, longitude); // Act string result = delta.ToString(); // Assert Assert.IsNotNull(result); - Assert.IsTrue(result.Contains(v0.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.Ordinal)); - Assert.IsTrue(result.Contains(v1.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.Ordinal)); + Assert.IsTrue(result.Contains(latitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal)); + Assert.IsTrue(result.Contains(longitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal)); } /// @@ -153,9 +119,9 @@ public void ToString_After_Next_Contains_Expected_Values(int v0, int v1) { [TestMethod] public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Latest_Values() { // Arrange - CoordinateDelta delta = new(2); - delta.Next([10, 20]); - delta.Next([30, 50]); + CoordinateDelta delta = new(); + delta.Next(10, 20); + delta.Next(30, 50); // Act string result = delta.ToString(); @@ -166,5 +132,5 @@ public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Lat Assert.IsTrue(result.Contains("50", StringComparison.Ordinal)); Assert.IsTrue(result.Contains("20", StringComparison.Ordinal)); } -} +} diff --git a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs index c9daaa1f..0dff7193 100644 --- a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs @@ -80,21 +80,20 @@ public void LogOperationFinishedDebug_With_Operation_Name_Logs_Finished_Message( } /// - /// Tests that LogDecodedValuesDebug WithCountAndPosition LogsDecodedValuesMessage. + /// Tests that LogDecodedCoordinateDebug WithCoordinatesAndPosition LogsDecodedCoordinateMessage. /// [TestMethod] - public void LogDecodedValuesDebug_With_Count_And_Position_Logs_Decoded_Values_Message() { + public void LogDecodedCoordinateDebug_With_Coordinates_And_Position_Logs_Decoded_Coordinate_Message() { var logger = new TestLogger(); - const int count = 2; + const double latitude = 38.5; + const double longitude = -120.2; const int position = 42; - logger.LogDecodedValuesDebug(count, position); + logger.LogDecodedCoordinateDebug(latitude, longitude, position); Assert.HasCount(1, logger.Logs); Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level); - Assert.Contains("Decoded", logger.Logs[0].Message, StringComparison.Ordinal); - Assert.Contains(count.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal); - Assert.Contains(position.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}."), logger.Logs[0].Message, StringComparison.Ordinal); } /// @@ -143,35 +142,37 @@ public void LogOperationFinishedDebug_With_Null_Operation_Name_Logs_Message() { } /// - /// Tests that LogDecodedValuesDebug WithZeroCountAndPosition LogsMessage. + /// Tests that LogDecodedCoordinateDebug WithZeroCoordinates LogsMessage. /// [TestMethod] - public void LogDecodedValuesDebug_With_Zero_Count_Logs_Message() { + public void LogDecodedCoordinateDebug_With_Zero_Coordinates_Logs_Message() { var logger = new TestLogger(); - const int count = 0; + const double latitude = 0.0; + const double longitude = 0.0; const int position = 0; - logger.LogDecodedValuesDebug(count, position); + logger.LogDecodedCoordinateDebug(latitude, longitude, position); Assert.HasCount(1, logger.Logs); Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level); - Assert.Contains("Decoded", logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains("Decoded coordinate", logger.Logs[0].Message, StringComparison.Ordinal); } /// - /// Tests that LogDecodedValuesDebug WithLargeCount LogsMessage. + /// Tests that LogDecodedCoordinateDebug WithNegativeCoordinates LogsMessage. /// [TestMethod] - public void LogDecodedValuesDebug_With_Large_Count_Logs_Message() { + public void LogDecodedCoordinateDebug_With_Negative_Coordinates_Logs_Message() { var logger = new TestLogger(); - const int count = 5; + const double latitude = -90.0; + const double longitude = -180.0; const int position = 100; - logger.LogDecodedValuesDebug(count, position); + logger.LogDecodedCoordinateDebug(latitude, longitude, position); Assert.HasCount(1, logger.Logs); Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level); - Assert.Contains(count.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Latitude: {latitude}, Longitude: {longitude}"), logger.Logs[0].Message, StringComparison.Ordinal); } /// diff --git a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs index 0ca40426..d3d83b9e 100644 --- a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs +++ b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs @@ -105,15 +105,16 @@ private readonly struct PolylineCoordinateCollectionPair(IEnumerable<(double Lat private sealed class PolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - protected override int ValuesPerItem => 2; - protected override string CreatePolyline(ReadOnlyMemory polyline) { return polyline.ToString(); } - protected override void GetValues((double Latitude, double Longitude) item, Span destination) { - destination[0] = item.Latitude; - destination[1] = item.Longitude; + protected override double GetLatitude((double Latitude, double Longitude) current) { + return current.Latitude; + } + + protected override double GetLongitude((double Latitude, double Longitude) current) { + return current.Longitude; } } } \ No newline at end of file From 345637de98c3d689a2fa1aa822704a7f5ac46dcd Mon Sep 17 00:00:00 2001 From: Pete Sramek <2333452+petesramek@users.noreply.github.com> Date: Mon, 6 Apr 2026 00:09:01 +0200 Subject: [PATCH 05/24] updated slnx --- PolylineAlgorithm.slnx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/PolylineAlgorithm.slnx b/PolylineAlgorithm.slnx index 3c54b2a7..9f6748bf 100644 --- a/PolylineAlgorithm.slnx +++ b/PolylineAlgorithm.slnx @@ -7,7 +7,9 @@ - + + + From a86ac30be05525b21db4e945f0293f2545dbe50b Mon Sep 17 00:00:00 2001 From: Pete Sramek <2333452+petesramek@users.noreply.github.com> Date: Sun, 5 Apr 2026 22:11:58 +0000 Subject: [PATCH 06/24] Updated docs for version 0.0 --- ...m.Abstraction.AbstractPolylineDecoder-2.yml | 16 ++++++++-------- ...m.Abstraction.AbstractPolylineEncoder-2.yml | 16 ++++++++-------- ...lgorithm.Abstraction.IPolylineDecoder-2.yml | 4 ++-- ...lgorithm.Abstraction.IPolylineEncoder-2.yml | 4 ++-- ...hm.Extensions.PolylineDecoderExtensions.yml | 8 ++++---- ...hm.Extensions.PolylineEncoderExtensions.yml | 6 +++--- ...ylineAlgorithm.InvalidPolylineException.yml | 6 +++--- .../0.0/PolylineAlgorithm.PolylineEncoding.yml | 18 +++++++++--------- ...lylineAlgorithm.PolylineEncodingOptions.yml | 8 ++++---- ...lgorithm.PolylineEncodingOptionsBuilder.yml | 12 ++++++------ 10 files changed, 49 insertions(+), 49 deletions(-) diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml index b5693066..56ef6af4 100644 --- a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml +++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml @@ -3,7 +3,7 @@ title: Class AbstractPolylineDecoder body: - api1: Class AbstractPolylineDecoder id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2 - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L22 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L22 metadata: uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2 commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2 @@ -56,7 +56,7 @@ body: - h2: Constructors - api3: AbstractPolylineDecoder() id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L28 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L28 metadata: uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor @@ -64,7 +64,7 @@ body: - code: protected AbstractPolylineDecoder() - api3: AbstractPolylineDecoder(PolylineEncodingOptions) id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L40 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L40 metadata: uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) @@ -86,7 +86,7 @@ body: - h2: Properties - api3: Options id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Options - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L54 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L54 metadata: uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options @@ -100,7 +100,7 @@ body: - h2: Methods - api3: CreateCoordinate(double, double) id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_CreateCoordinate_System_Double_System_Double_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L202 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L202 metadata: uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateCoordinate(System.Double,System.Double) commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateCoordinate(System.Double,System.Double) @@ -125,7 +125,7 @@ body: description: A TCoordinate instance representing the specified geographic coordinate. - api3: Decode(TPolyline, CancellationToken) id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L81 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L81 metadata: uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) @@ -175,7 +175,7 @@ body: description: Thrown when cancellationToken is canceled during decoding. - api3: GetReadOnlyMemory(in TPolyline) id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_GetReadOnlyMemory__0__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L187 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L187 metadata: uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@) commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@) @@ -199,7 +199,7 @@ body: description: A of representing the encoded polyline characters. - api3: ValidateFormat(ReadOnlyMemory, ILogger?) id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_ValidateFormat_System_ReadOnlyMemory_System_Char__Microsoft_Extensions_Logging_ILogger_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L167 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L167 metadata: uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger) commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger) diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml index 64e97b11..985138f8 100644 --- a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml +++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml @@ -3,7 +3,7 @@ title: Class AbstractPolylineEncoder body: - api1: Class AbstractPolylineEncoder id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2 - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L27 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L27 metadata: uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2 commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2 @@ -62,7 +62,7 @@ body: - h2: Constructors - api3: AbstractPolylineEncoder() id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L33 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L33 metadata: uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor @@ -70,7 +70,7 @@ body: - code: protected AbstractPolylineEncoder() - api3: AbstractPolylineEncoder(PolylineEncodingOptions) id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L43 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L43 metadata: uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) @@ -92,7 +92,7 @@ body: - h2: Properties - api3: Options id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Options - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L57 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L57 metadata: uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options @@ -106,7 +106,7 @@ body: - h2: Methods - api3: CreatePolyline(ReadOnlyMemory) id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_CreatePolyline_System_ReadOnlyMemory_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L174 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L174 metadata: uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char}) commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char}) @@ -130,7 +130,7 @@ body: description: An instance of TPolyline representing the encoded polyline. - api3: Encode(ReadOnlySpan, CancellationToken) id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L80 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L80 metadata: uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) @@ -176,7 +176,7 @@ body: description: Thrown when the internal encoding buffer cannot accommodate the encoded value. - api3: GetLatitude(TCoordinate) id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetLatitude__0_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L194 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L194 metadata: uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLatitude(`0) commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLatitude(`0) @@ -196,7 +196,7 @@ body: description: The latitude value as a . - api3: GetLongitude(TCoordinate) id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetLongitude__0_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L184 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L184 metadata: uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLongitude(`0) commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLongitude(`0) diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml index 733987cb..c3a0cc71 100644 --- a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml +++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml @@ -3,7 +3,7 @@ title: Interface IPolylineDecoder body: - api1: Interface IPolylineDecoder id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2 - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L22 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L22 metadata: uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2 commentId: T:PolylineAlgorithm.Abstraction.IPolylineDecoder`2 @@ -31,7 +31,7 @@ body: - h2: Methods - api3: Decode(TPolyline, CancellationToken) id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L48 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L48 metadata: uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) commentId: M:PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml index 341a9de7..952d1a27 100644 --- a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml +++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml @@ -3,7 +3,7 @@ title: Interface IPolylineEncoder body: - api1: Interface IPolylineEncoder id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2 - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L36 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L36 metadata: uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2 commentId: T:PolylineAlgorithm.Abstraction.IPolylineEncoder`2 @@ -63,7 +63,7 @@ body: - h2: Methods - api3: Encode(ReadOnlySpan, CancellationToken) id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L76 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L76 metadata: uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) commentId: M:PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml index 8356b63c..5b6e2da1 100644 --- a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml +++ b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml @@ -3,7 +3,7 @@ title: Class PolylineDecoderExtensions body: - api1: Class PolylineDecoderExtensions id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L16 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L16 metadata: uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions commentId: T:PolylineAlgorithm.Extensions.PolylineDecoderExtensions @@ -41,7 +41,7 @@ body: - h2: Methods - api3: Decode(IPolylineDecoder, char[]) id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_String___0__System_Char___ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L33 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L33 metadata: uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.Char[]) commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.Char[]) @@ -89,7 +89,7 @@ body: description: Thrown when decoder or polyline is null. - api3: Decode(IPolylineDecoder, ReadOnlyMemory) id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_String___0__System_ReadOnlyMemory_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L61 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L61 metadata: uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.ReadOnlyMemory{System.Char}) commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.ReadOnlyMemory{System.Char}) @@ -139,7 +139,7 @@ body: description: Thrown when decoder is null. - api3: Decode(IPolylineDecoder, TValue>, string) id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_ReadOnlyMemory_System_Char____0__System_String_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L86 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L86 metadata: uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.ReadOnlyMemory{System.Char},``0},System.String) commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.ReadOnlyMemory{System.Char},``0},System.String) diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml index e5296518..bd62ed13 100644 --- a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml +++ b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml @@ -3,7 +3,7 @@ title: Class PolylineEncoderExtensions body: - api1: Class PolylineEncoderExtensions id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L19 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L19 metadata: uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions commentId: T:PolylineAlgorithm.Extensions.PolylineEncoderExtensions @@ -41,7 +41,7 @@ body: - h2: Methods - api3: Encode(IPolylineEncoder, List) id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L37 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L37 metadata: uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},System.Collections.Generic.List{``0}) commentId: M:PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},System.Collections.Generic.List{``0}) @@ -92,7 +92,7 @@ body: description: Thrown when encoder or coordinates is null. - api3: Encode(IPolylineEncoder, TCoordinate[]) id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L73 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L73 metadata: uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},``0[]) commentId: M:PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},``0[]) diff --git a/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml b/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml index 2c4e3cc1..8f6b6e76 100644 --- a/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml +++ b/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml @@ -3,7 +3,7 @@ title: Class InvalidPolylineException body: - api1: Class InvalidPolylineException id: PolylineAlgorithm_InvalidPolylineException - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/InvalidPolylineException.cs#L17 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/InvalidPolylineException.cs#L17 metadata: uid: PolylineAlgorithm.InvalidPolylineException commentId: T:PolylineAlgorithm.InvalidPolylineException @@ -71,7 +71,7 @@ body: - h2: Constructors - api3: InvalidPolylineException() id: PolylineAlgorithm_InvalidPolylineException__ctor - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/InvalidPolylineException.cs#L22 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/InvalidPolylineException.cs#L22 metadata: uid: PolylineAlgorithm.InvalidPolylineException.#ctor commentId: M:PolylineAlgorithm.InvalidPolylineException.#ctor @@ -79,7 +79,7 @@ body: - code: public InvalidPolylineException() - api3: InvalidPolylineException(string, Exception) id: PolylineAlgorithm_InvalidPolylineException__ctor_System_String_System_Exception_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/InvalidPolylineException.cs#L43 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/InvalidPolylineException.cs#L43 metadata: uid: PolylineAlgorithm.InvalidPolylineException.#ctor(System.String,System.Exception) commentId: M:PolylineAlgorithm.InvalidPolylineException.#ctor(System.String,System.Exception) diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml index 1add8147..56818e4c 100644 --- a/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml +++ b/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml @@ -3,7 +3,7 @@ title: Class PolylineEncoding body: - api1: Class PolylineEncoding id: PolylineAlgorithm_PolylineEncoding - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L23 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L23 metadata: uid: PolylineAlgorithm.PolylineEncoding commentId: T:PolylineAlgorithm.PolylineEncoding @@ -50,7 +50,7 @@ body: - h2: Methods - api3: Denormalize(int, uint) id: PolylineAlgorithm_PolylineEncoding_Denormalize_System_Int32_System_UInt32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L122 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L122 metadata: uid: PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32) commentId: M:PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32) @@ -117,7 +117,7 @@ body: description: Thrown if the arithmetic operation overflows during conversion. - api3: GetRequiredBufferSize(int) id: PolylineAlgorithm_PolylineEncoding_GetRequiredBufferSize_System_Int32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L298 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L298 metadata: uid: PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32) commentId: M:PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32) @@ -200,7 +200,7 @@ body: - ) - api3: Normalize(double, uint) id: PolylineAlgorithm_PolylineEncoding_Normalize_System_Double_System_UInt32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L61 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L61 metadata: uid: PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32) commentId: M:PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32) @@ -268,7 +268,7 @@ body: description: Thrown when the normalized result exceeds the range of a 32-bit signed integer during the conversion from double to int. - api3: TryReadValue(ref int, ReadOnlyMemory, ref int) id: PolylineAlgorithm_PolylineEncoding_TryReadValue_System_Int32__System_ReadOnlyMemory_System_Char__System_Int32__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L169 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L169 metadata: uid: PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@) commentId: M:PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@) @@ -328,7 +328,7 @@ body:

- api3: TryWriteValue(int, Span, ref int) id: PolylineAlgorithm_PolylineEncoding_TryWriteValue_System_Int32_System_Span_System_Char__System_Int32__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L237 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L237 metadata: uid: PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@) commentId: M:PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@) @@ -407,7 +407,7 @@ body:

- api3: ValidateBlockLength(ReadOnlySpan) id: PolylineAlgorithm_PolylineEncoding_ValidateBlockLength_System_ReadOnlySpan_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L438 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L438 metadata: uid: PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char}) commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char}) @@ -441,7 +441,7 @@ body: description: Thrown when a block exceeds 7 characters or the polyline does not end with a valid block terminator. - api3: ValidateCharRange(ReadOnlySpan) id: PolylineAlgorithm_PolylineEncoding_ValidateCharRange_System_ReadOnlySpan_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L392 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L392 metadata: uid: PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char}) commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char}) @@ -479,7 +479,7 @@ body: description: Thrown when an invalid character is found in the polyline segment. - api3: ValidateFormat(ReadOnlySpan) id: PolylineAlgorithm_PolylineEncoding_ValidateFormat_System_ReadOnlySpan_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L370 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L370 metadata: uid: PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char}) commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char}) diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml index 1947eac1..90dc279b 100644 --- a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml +++ b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml @@ -3,7 +3,7 @@ title: Class PolylineEncodingOptions body: - api1: Class PolylineEncodingOptions id: PolylineAlgorithm_PolylineEncodingOptions - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L29 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L29 metadata: uid: PolylineAlgorithm.PolylineEncodingOptions commentId: T:PolylineAlgorithm.PolylineEncodingOptions @@ -54,7 +54,7 @@ body: - h2: Properties - api3: LoggerFactory id: PolylineAlgorithm_PolylineEncodingOptions_LoggerFactory - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L41 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L41 metadata: uid: PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory commentId: P:PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory @@ -72,7 +72,7 @@ body: To enable logging, provide a custom implementation. - api3: Precision id: PolylineAlgorithm_PolylineEncodingOptions_Precision - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L60 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L60 metadata: uid: PolylineAlgorithm.PolylineEncodingOptions.Precision commentId: P:PolylineAlgorithm.PolylineEncodingOptions.Precision @@ -104,7 +104,7 @@ body:

- api3: StackAllocLimit id: PolylineAlgorithm_PolylineEncodingOptions_StackAllocLimit - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L73 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L73 metadata: uid: PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit commentId: P:PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml index 66ae63b8..2c959bdb 100644 --- a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml +++ b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml @@ -3,7 +3,7 @@ title: Class PolylineEncodingOptionsBuilder body: - api1: Class PolylineEncodingOptionsBuilder id: PolylineAlgorithm_PolylineEncodingOptionsBuilder - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L15 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L15 metadata: uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder commentId: T:PolylineAlgorithm.PolylineEncodingOptionsBuilder @@ -39,7 +39,7 @@ body: - h2: Methods - api3: Build() id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Build - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L38 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L38 metadata: uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build @@ -53,7 +53,7 @@ body: description: A configured instance. - api3: Create() id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Create - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L28 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L28 metadata: uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create @@ -67,7 +67,7 @@ body: description: An instance for configuring polyline encoding options. - api3: WithLoggerFactory(ILoggerFactory) id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithLoggerFactory_Microsoft_Extensions_Logging_ILoggerFactory_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L97 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L97 metadata: uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory) commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory) @@ -88,7 +88,7 @@ body: description: The current instance for method chaining. - api3: WithPrecision(uint) id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithPrecision_System_UInt32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L82 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L82 metadata: uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32) commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32) @@ -109,7 +109,7 @@ body: description: The current instance for method chaining. - api3: WithStackAllocLimit(int) id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithStackAllocLimit_System_Int32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L61 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L61 metadata: uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32) commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32) From 5641294ab9a856cb383f24d791de0a25abd7890e Mon Sep 17 00:00:00 2001 From: Pete Sramek <2333452+petesramek@users.noreply.github.com> Date: Mon, 6 Apr 2026 00:12:44 +0200 Subject: [PATCH 07/24] fixed slnx --- PolylineAlgorithm.slnx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/PolylineAlgorithm.slnx b/PolylineAlgorithm.slnx index 9f6748bf..2be9e3c1 100644 --- a/PolylineAlgorithm.slnx +++ b/PolylineAlgorithm.slnx @@ -7,10 +7,7 @@
- - - - + From b48500306b8253efbb40230f9ab0f8636408923b Mon Sep 17 00:00:00 2001 From: Pete Sramek <2333452+petesramek@users.noreply.github.com> Date: Mon, 6 Apr 2026 00:13:47 +0200 Subject: [PATCH 08/24] removed 0.0 api ref --- ....Abstraction.AbstractPolylineDecoder-2.yml | 233 -------- ....Abstraction.AbstractPolylineEncoder-2.yml | 219 -------- ...gorithm.Abstraction.IPolylineDecoder-2.yml | 90 --- ...gorithm.Abstraction.IPolylineEncoder-2.yml | 142 ----- .../0.0/PolylineAlgorithm.Abstraction.yml | 34 -- ...m.Extensions.PolylineDecoderExtensions.yml | 195 ------- ...m.Extensions.PolylineEncoderExtensions.yml | 139 ----- .../0.0/PolylineAlgorithm.Extensions.yml | 19 - ...lineAlgorithm.InvalidPolylineException.yml | 102 ---- .../PolylineAlgorithm.PolylineEncoding.yml | 529 ------------------ ...ylineAlgorithm.PolylineEncodingOptions.yml | 127 ----- ...gorithm.PolylineEncodingOptionsBuilder.yml | 141 ----- api-reference/0.0/PolylineAlgorithm.yml | 38 -- api-reference/0.0/toc.yml | 34 -- 14 files changed, 2042 deletions(-) delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml delete mode 100644 api-reference/0.0/PolylineAlgorithm.yml delete mode 100644 api-reference/0.0/toc.yml diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml deleted file mode 100644 index 56ef6af4..00000000 --- a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml +++ /dev/null @@ -1,233 +0,0 @@ -### YamlMime:ApiPage -title: Class AbstractPolylineDecoder -body: -- api1: Class AbstractPolylineDecoder - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2 - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L22 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2 - commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2 -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Abstraction - url: PolylineAlgorithm.Abstraction.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates. -- code: 'public abstract class AbstractPolylineDecoder : IPolylineDecoder' -- h4: Type Parameters -- parameters: - - name: TPolyline - description: The type that represents the encoded polyline input. - - name: TCoordinate - description: The type that represents a decoded geographic coordinate. -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: AbstractPolylineDecoder - url: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.html -- h4: Implements -- list: - - text: IPolylineDecoder - url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.MemberwiseClone() - url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Remarks -- markdown: >- - Derive from this class to implement a decoder for a specific polyline type. Override - - and to provide type-specific behavior. -- h2: Constructors -- api3: AbstractPolylineDecoder() - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L28 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor -- markdown: Initializes a new instance of the class with default encoding options. -- code: protected AbstractPolylineDecoder() -- api3: AbstractPolylineDecoder(PolylineEncodingOptions) - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L40 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) -- markdown: Initializes a new instance of the class with the specified encoding options. -- code: protected AbstractPolylineDecoder(PolylineEncodingOptions options) -- h4: Parameters -- parameters: - - name: options - type: - - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html - description: The to use for encoding operations. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when options is null. -- h2: Properties -- api3: Options - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Options - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L54 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options - commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options -- markdown: Gets the encoding options used by this polyline decoder. -- code: public PolylineEncodingOptions Options { get; } -- h4: Property Value -- parameters: - - type: - - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html -- h2: Methods -- api3: CreateCoordinate(double, double) - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_CreateCoordinate_System_Double_System_Double_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L202 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateCoordinate(System.Double,System.Double) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateCoordinate(System.Double,System.Double) -- markdown: Creates a TCoordinate instance from the specified latitude and longitude values. -- code: protected abstract TCoordinate CreateCoordinate(double latitude, double longitude) -- h4: Parameters -- parameters: - - name: latitude - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The latitude component of the coordinate, in degrees. - - name: longitude - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The longitude component of the coordinate, in degrees. -- h4: Returns -- parameters: - - type: - - TCoordinate - description: A TCoordinate instance representing the specified geographic coordinate. -- api3: Decode(TPolyline, CancellationToken) - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L81 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) -- markdown: >- - Decodes an encoded TPolyline into a sequence of TCoordinate instances, - - with support for cancellation. -- code: public IEnumerable Decode(TPolyline polyline, CancellationToken cancellationToken = default) -- h4: Parameters -- parameters: - - name: polyline - type: - - TPolyline - description: The TPolyline instance containing the encoded polyline string to decode. - - name: cancellationToken - type: - - text: CancellationToken - url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken - description: A that can be used to cancel the decoding operation. - optional: true -- h4: Returns -- parameters: - - type: - - text: IEnumerable - url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 - - < - - TCoordinate - - '>' - description: An of TCoordinate representing the decoded latitude and longitude pairs. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when polyline is null. - - type: - - text: ArgumentException - url: https://learn.microsoft.com/dotnet/api/system.argumentexception - description: Thrown when polyline is empty. - - type: - - text: InvalidPolylineException - url: PolylineAlgorithm.InvalidPolylineException.html - description: Thrown when the polyline format is invalid or malformed at a specific position. - - type: - - text: OperationCanceledException - url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception - description: Thrown when cancellationToken is canceled during decoding. -- api3: GetReadOnlyMemory(in TPolyline) - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_GetReadOnlyMemory__0__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L187 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@) -- markdown: Extracts the underlying read-only memory region of characters from the specified polyline instance. -- code: protected abstract ReadOnlyMemory GetReadOnlyMemory(in TPolyline polyline) -- h4: Parameters -- parameters: - - name: polyline - type: - - TPolyline - description: The TPolyline instance from which to extract the character sequence. -- h4: Returns -- parameters: - - type: - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: A of representing the encoded polyline characters. -- api3: ValidateFormat(ReadOnlyMemory, ILogger?) - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_ValidateFormat_System_ReadOnlyMemory_System_Char__Microsoft_Extensions_Logging_ILogger_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L167 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger) -- markdown: Validates the format of the polyline character sequence, ensuring all characters are within the allowed range. -- code: protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? logger) -- h4: Parameters -- parameters: - - name: sequence - type: - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: The read-only memory region of characters representing the polyline to validate. - - name: logger - type: - - text: ILogger - url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger - - '?' - description: An optional used to log a warning when format validation fails. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentException - url: https://learn.microsoft.com/dotnet/api/system.argumentexception - description: Thrown when the polyline contains characters outside the valid encoding range or has an invalid block structure. -languageId: csharp -metadata: - description: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates. diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml deleted file mode 100644 index 985138f8..00000000 --- a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml +++ /dev/null @@ -1,219 +0,0 @@ -### YamlMime:ApiPage -title: Class AbstractPolylineEncoder -body: -- api1: Class AbstractPolylineEncoder - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2 - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L27 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2 - commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2 -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Abstraction - url: PolylineAlgorithm.Abstraction.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings. -- code: 'public abstract class AbstractPolylineEncoder : IPolylineEncoder' -- h4: Type Parameters -- parameters: - - name: TCoordinate - description: The type that represents a geographic coordinate to encode. - - name: TPolyline - description: The type that represents the encoded polyline output. -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: AbstractPolylineEncoder - url: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.html -- h4: Implements -- list: - - text: IPolylineEncoder - url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.MemberwiseClone() - url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h4: Extension Methods -- list: - - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, List) - url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__ - - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, TCoordinate[]) - url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___ -- h2: Remarks -- markdown: >- - Derive from this class to implement an encoder for a specific coordinate and polyline type. Override - - , , and to provide type-specific behavior. -- h2: Constructors -- api3: AbstractPolylineEncoder() - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L33 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor -- markdown: Initializes a new instance of the class with default encoding options. -- code: protected AbstractPolylineEncoder() -- api3: AbstractPolylineEncoder(PolylineEncodingOptions) - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L43 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) -- markdown: Initializes a new instance of the class with the specified encoding options. -- code: protected AbstractPolylineEncoder(PolylineEncodingOptions options) -- h4: Parameters -- parameters: - - name: options - type: - - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html - description: The to use for encoding operations. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when options is null -- h2: Properties -- api3: Options - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Options - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L57 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options - commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options -- markdown: Gets the encoding options used by this polyline encoder. -- code: public PolylineEncodingOptions Options { get; } -- h4: Property Value -- parameters: - - type: - - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html -- h2: Methods -- api3: CreatePolyline(ReadOnlyMemory) - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_CreatePolyline_System_ReadOnlyMemory_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L174 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char}) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char}) -- markdown: Creates a polyline instance from the provided read-only sequence of characters. -- code: protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline) -- h4: Parameters -- parameters: - - name: polyline - type: - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: A containing the encoded polyline characters. -- h4: Returns -- parameters: - - type: - - TPolyline - description: An instance of TPolyline representing the encoded polyline. -- api3: Encode(ReadOnlySpan, CancellationToken) - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L80 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) -- markdown: Encodes a collection of TCoordinate instances into an encoded TPolyline string. -- code: >- - [SuppressMessage("Design", "MA0051:Method is too long", Justification = "Method contains local methods. Actual method only 55 lines.")] - - public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default) -- h4: Parameters -- parameters: - - name: coordinates - type: - - text: ReadOnlySpan - url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 - - < - - TCoordinate - - '>' - description: The collection of TCoordinate objects to encode. - - name: cancellationToken - type: - - text: CancellationToken - url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken - description: A that can be used to cancel the encoding operation. - optional: true -- h4: Returns -- parameters: - - type: - - TPolyline - description: An instance of TPolyline representing the encoded coordinates. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when coordinates is null. - - type: - - text: ArgumentException - url: https://learn.microsoft.com/dotnet/api/system.argumentexception - description: Thrown when coordinates is an empty enumeration. - - type: - - text: InvalidOperationException - url: https://learn.microsoft.com/dotnet/api/system.invalidoperationexception - description: Thrown when the internal encoding buffer cannot accommodate the encoded value. -- api3: GetLatitude(TCoordinate) - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetLatitude__0_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L194 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLatitude(`0) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLatitude(`0) -- markdown: Extracts the latitude value from the specified coordinate. -- code: protected abstract double GetLatitude(TCoordinate current) -- h4: Parameters -- parameters: - - name: current - type: - - TCoordinate - description: The coordinate from which to extract the latitude. -- h4: Returns -- parameters: - - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The latitude value as a . -- api3: GetLongitude(TCoordinate) - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetLongitude__0_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L184 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLongitude(`0) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLongitude(`0) -- markdown: Extracts the longitude value from the specified coordinate. -- code: protected abstract double GetLongitude(TCoordinate current) -- h4: Parameters -- parameters: - - name: current - type: - - TCoordinate - description: The coordinate from which to extract the longitude. -- h4: Returns -- parameters: - - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The longitude value as a . -languageId: csharp -metadata: - description: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings. diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml deleted file mode 100644 index c3a0cc71..00000000 --- a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml +++ /dev/null @@ -1,90 +0,0 @@ -### YamlMime:ApiPage -title: Interface IPolylineDecoder -body: -- api1: Interface IPolylineDecoder - id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2 - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L22 - metadata: - uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2 - commentId: T:PolylineAlgorithm.Abstraction.IPolylineDecoder`2 -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Abstraction - url: PolylineAlgorithm.Abstraction.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates. -- code: public interface IPolylineDecoder -- h4: Type Parameters -- parameters: - - name: TPolyline - description: >- - The type that represents the encoded polyline input. Common implementations use , - - but custom wrapper types are allowed to carry additional metadata. - - name: TValue - description: >- - The coordinate type returned by the decoder. Typical implementations return a struct or class that - - contains latitude and longitude (for example a LatLng type or a ValueTuple<double,double>). -- h2: Methods -- api3: Decode(TPolyline, CancellationToken) - id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L48 - metadata: - uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) - commentId: M:PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) -- markdown: >- - Decodes the specified encoded polyline into an ordered sequence of geographic coordinates. - - The sequence preserves the original vertex order encoded by the polyline. -- code: IEnumerable Decode(TPolyline polyline, CancellationToken cancellationToken = default) -- h4: Parameters -- parameters: - - name: polyline - type: - - TPolyline - description: >- - The TPolyline instance containing the encoded polyline to decode. - - Implementations SHOULD validate the input and may throw - - or for invalid formats. - - name: cancellationToken - type: - - text: CancellationToken - url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken - description: >- - A to observe while decoding. If cancellation is requested, - - implementations SHOULD stop work and throw an . - optional: true -- h4: Returns -- parameters: - - type: - - text: IEnumerable - url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 - - < - - TValue - - '>' - description: >- - An of TValue representing the decoded - - latitude/longitude pairs (or equivalent coordinates) in the same order they were encoded. -- h4: Remarks -- markdown: >- - Implementations commonly follow the Google Encoded Polyline Algorithm Format, but this interface - - does not mandate a specific encoding. Consumers should rely on a concrete decoder's documentation - - to understand the exact encoding supported. -- h4: Exceptions -- parameters: - - type: - - text: OperationCanceledException - url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception - description: Thrown when the provided cancellationToken requests cancellation. -languageId: csharp -metadata: - description: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates. diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml deleted file mode 100644 index 952d1a27..00000000 --- a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml +++ /dev/null @@ -1,142 +0,0 @@ -### YamlMime:ApiPage -title: Interface IPolylineEncoder -body: -- api1: Interface IPolylineEncoder - id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2 - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L36 - metadata: - uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2 - commentId: T:PolylineAlgorithm.Abstraction.IPolylineEncoder`2 -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Abstraction - url: PolylineAlgorithm.Abstraction.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: >- - Contract for encoding a sequence of geographic coordinates into an encoded polyline representation. - - Implementations interpret the generic TValue type and produce an encoded - - representation of those coordinates as TPolyline. -- code: public interface IPolylineEncoder -- h4: Type Parameters -- parameters: - - name: TValue - description: >- - The concrete coordinate representation used by the encoder (for example a struct or class containing - - Latitude and Longitude values). Implementations must document the expected shape, - - units (typically decimal degrees), and any required fields for TValue. - - Common shapes: - - - A struct or class with two double properties named Latitude and Longitude. - - - A tuple-like type (for example ValueTuple<double,double>) where the encoder documents - which element represents latitude and longitude. - - name: TPolyline - description: >- - The encoded polyline representation returned by the encoder (for example string, - - ReadOnlyMemory<char>, or a custom wrapper type). Concrete implementations should document - - the chosen representation and any memory / ownership expectations. -- h4: Extension Methods -- list: - - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, List) - url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__ - - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, TValue[]) - url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___ -- h2: Remarks -- markdown: >- - - This interface is intentionally minimal to allow different encoding strategies (Google encoded polyline, - precision/scale variants, or custom compressed formats) to be expressed behind a common contract. - - Implementations should document: - - Coordinate precision and rounding rules (for example 1e-5 for 5-decimal precision). - - Coordinate ordering and whether altitude or additional dimensions are supported. - - Thread-safety guarantees: whether instances are safe to reuse concurrently or must be instantiated per-call. - - Implementations are encouraged to be memory-efficient; the API accepts a - to avoid forced allocations when callers already have contiguous memory. -- h2: Methods -- api3: Encode(ReadOnlySpan, CancellationToken) - id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L76 - metadata: - uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) - commentId: M:PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) -- markdown: >- - Encodes a sequence of geographic coordinates into an encoded polyline representation. - - The order of coordinates in coordinates is preserved in the encoded result. -- code: TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default) -- h4: Parameters -- parameters: - - name: coordinates - type: - - text: ReadOnlySpan - url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 - - < - - TValue - - '>' - description: >- - The collection of TValue instances to encode into a polyline. - - The span may be empty; implementations should return an appropriate empty encoded representation - - (for example an empty string or an empty memory slice) rather than null. - - name: cancellationToken - type: - - text: CancellationToken - url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken - description: >- - A that can be used to cancel the encoding operation. - - Implementations should observe this token and throw - - when cancellation is requested. For fast, in-memory encoders cancellation may be best-effort. - optional: true -- h4: Returns -- parameters: - - type: - - TPolyline - description: >- - A TPolyline containing the encoded polyline that represents the input coordinates. - - The exact format and any delimiting/terminating characters are implementation-specific and must be - - documented by concrete encoder types. -- h4: Examples -- markdown: >- -
// Example pseudocode for typical usage with a string-based encoder:
-
-    var coords = new[] {
-        new Coordinate { Latitude = 47.6219, Longitude = -122.3503 },
-        new Coordinate { Latitude = 47.6220, Longitude = -122.3504 }
-    };
-
-    IPolylineEncoder<Coordinate,string> encoder = new GoogleEncodedPolylineEncoder();
-
-    string encoded = encoder.Encode(coords, CancellationToken.None);
-- h4: Remarks -- markdown: >- - - Implementations should validate input as appropriate and document any preconditions (for example - if coordinates must be within [-90,90] latitude and [-180,180] longitude). - - For large input sequences, implementations may provide streaming or incremental encoders; those - variants can still implement this interface by materializing the final encoded result. -- h4: Exceptions -- parameters: - - type: - - text: OperationCanceledException - url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception - description: Thrown if the operation is canceled via cancellationToken. -languageId: csharp -metadata: - description: >- - Contract for encoding a sequence of geographic coordinates into an encoded polyline representation. - - Implementations interpret the generic TValue type and produce an encoded - - representation of those coordinates as TPolyline. diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.yml deleted file mode 100644 index e9de48f7..00000000 --- a/api-reference/0.0/PolylineAlgorithm.Abstraction.yml +++ /dev/null @@ -1,34 +0,0 @@ -### YamlMime:ApiPage -title: Namespace PolylineAlgorithm.Abstraction -body: -- api1: Namespace PolylineAlgorithm.Abstraction - id: PolylineAlgorithm_Abstraction - metadata: - uid: PolylineAlgorithm.Abstraction - commentId: N:PolylineAlgorithm.Abstraction -- h3: Classes -- parameters: - - type: - text: AbstractPolylineDecoder - url: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.html - description: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates. - - type: - text: AbstractPolylineEncoder - url: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.html - description: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings. -- h3: Interfaces -- parameters: - - type: - text: IPolylineDecoder - url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html - description: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates. - - type: - text: IPolylineEncoder - url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html - description: >- - Contract for encoding a sequence of geographic coordinates into an encoded polyline representation. - - Implementations interpret the generic TValue type and produce an encoded - - representation of those coordinates as TPolyline. -languageId: csharp diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml deleted file mode 100644 index 5b6e2da1..00000000 --- a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml +++ /dev/null @@ -1,195 +0,0 @@ -### YamlMime:ApiPage -title: Class PolylineDecoderExtensions -body: -- api1: Class PolylineDecoderExtensions - id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L16 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions - commentId: T:PolylineAlgorithm.Extensions.PolylineDecoderExtensions -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Extensions - url: PolylineAlgorithm.Extensions.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Provides extension methods for the interface to facilitate decoding encoded polylines. -- code: public static class PolylineDecoderExtensions -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: PolylineDecoderExtensions - url: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.MemberwiseClone() - url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Methods -- api3: Decode(IPolylineDecoder, char[]) - id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_String___0__System_Char___ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L33 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.Char[]) - commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.Char[]) -- markdown: Decodes an encoded polyline represented as a character array into a sequence of geographic coordinates. -- code: public static IEnumerable Decode(this IPolylineDecoder decoder, char[] polyline) -- h4: Parameters -- parameters: - - name: decoder - type: - - text: IPolylineDecoder - url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html - - < - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - - ',' - - " " - - TValue - - '>' - description: The instance used to perform the decoding operation. - - name: polyline - type: - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '[' - - ']' - description: The encoded polyline as a character array to decode. The array is converted to a string internally. -- h4: Returns -- parameters: - - type: - - text: IEnumerable - url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 - - < - - TValue - - '>' - description: An of TValue containing the decoded coordinate pairs. -- h4: Type Parameters -- parameters: - - name: TValue - description: The coordinate type returned by the decoder. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when decoder or polyline is null. -- api3: Decode(IPolylineDecoder, ReadOnlyMemory) - id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_String___0__System_ReadOnlyMemory_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L61 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.ReadOnlyMemory{System.Char}) - commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.ReadOnlyMemory{System.Char}) -- markdown: Decodes an encoded polyline represented as a read-only memory of characters into a sequence of geographic coordinates. -- code: public static IEnumerable Decode(this IPolylineDecoder decoder, ReadOnlyMemory polyline) -- h4: Parameters -- parameters: - - name: decoder - type: - - text: IPolylineDecoder - url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html - - < - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - - ',' - - " " - - TValue - - '>' - description: The instance used to perform the decoding operation. - - name: polyline - type: - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: The encoded polyline as a read-only memory of characters to decode. The memory is converted to a string internally. -- h4: Returns -- parameters: - - type: - - text: IEnumerable - url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 - - < - - TValue - - '>' - description: An of TValue containing the decoded coordinate pairs. -- h4: Type Parameters -- parameters: - - name: TValue - description: The coordinate type returned by the decoder. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when decoder is null. -- api3: Decode(IPolylineDecoder, TValue>, string) - id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_ReadOnlyMemory_System_Char____0__System_String_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L86 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.ReadOnlyMemory{System.Char},``0},System.String) - commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.ReadOnlyMemory{System.Char},``0},System.String) -- markdown: >- - Decodes an encoded polyline string into a sequence of geographic coordinates, - - using a decoder that accepts of . -- code: public static IEnumerable Decode(this IPolylineDecoder, TValue> decoder, string polyline) -- h4: Parameters -- parameters: - - name: decoder - type: - - text: IPolylineDecoder - url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html - - < - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - - ',' - - " " - - TValue - - '>' - description: The instance used to perform the decoding operation. - - name: polyline - type: - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - description: The encoded polyline string to decode. The string is converted to internally. -- h4: Returns -- parameters: - - type: - - text: IEnumerable - url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 - - < - - TValue - - '>' - description: An of TValue containing the decoded coordinate pairs. -- h4: Type Parameters -- parameters: - - name: TValue - description: The coordinate type returned by the decoder. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when decoder or polyline is null. -languageId: csharp -metadata: - description: Provides extension methods for the interface to facilitate decoding encoded polylines. diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml deleted file mode 100644 index bd62ed13..00000000 --- a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml +++ /dev/null @@ -1,139 +0,0 @@ -### YamlMime:ApiPage -title: Class PolylineEncoderExtensions -body: -- api1: Class PolylineEncoderExtensions - id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L19 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions - commentId: T:PolylineAlgorithm.Extensions.PolylineEncoderExtensions -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Extensions - url: PolylineAlgorithm.Extensions.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines. -- code: public static class PolylineEncoderExtensions -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: PolylineEncoderExtensions - url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.MemberwiseClone() - url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Methods -- api3: Encode(IPolylineEncoder, List) - id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L37 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},System.Collections.Generic.List{``0}) - commentId: M:PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},System.Collections.Generic.List{``0}) -- markdown: Encodes a of TCoordinate instances into an encoded polyline. -- code: >- - [SuppressMessage("Design", "CA1002:Do not expose generic lists", Justification = "We need a list as we do need to marshal it as span.")] - - [SuppressMessage("Design", "MA0016:Prefer using collection abstraction instead of implementation", Justification = "We need a list as we do need to marshal it as span.")] - - public static TPolyline Encode(this IPolylineEncoder encoder, List coordinates) -- h4: Parameters -- parameters: - - name: encoder - type: - - text: IPolylineEncoder - url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html - - < - - TCoordinate - - ',' - - " " - - TPolyline - - '>' - description: The instance used to perform the encoding operation. - - name: coordinates - type: - - text: List - url: https://learn.microsoft.com/dotnet/api/system.collections.generic.list-1 - - < - - TCoordinate - - '>' - description: The list of TCoordinate objects to encode. -- h4: Returns -- parameters: - - type: - - TPolyline - description: A TPolyline instance representing the encoded polyline for the provided coordinates. -- h4: Type Parameters -- parameters: - - name: TCoordinate - description: The type that represents a geographic coordinate to encode. - - name: TPolyline - description: The type that represents the encoded polyline output. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when encoder or coordinates is null. -- api3: Encode(IPolylineEncoder, TCoordinate[]) - id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L73 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},``0[]) - commentId: M:PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},``0[]) -- markdown: Encodes an array of TCoordinate instances into an encoded polyline. -- code: public static TPolyline Encode(this IPolylineEncoder encoder, TCoordinate[] coordinates) -- h4: Parameters -- parameters: - - name: encoder - type: - - text: IPolylineEncoder - url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html - - < - - TCoordinate - - ',' - - " " - - TPolyline - - '>' - description: The instance used to perform the encoding operation. - - name: coordinates - type: - - TCoordinate - - '[' - - ']' - description: The array of TCoordinate objects to encode. -- h4: Returns -- parameters: - - type: - - TPolyline - description: A TPolyline instance representing the encoded polyline for the provided coordinates. -- h4: Type Parameters -- parameters: - - name: TCoordinate - description: The type that represents a geographic coordinate to encode. - - name: TPolyline - description: The type that represents the encoded polyline output. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when encoder or coordinates is null. -languageId: csharp -metadata: - description: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines. diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.yml deleted file mode 100644 index c39da0ca..00000000 --- a/api-reference/0.0/PolylineAlgorithm.Extensions.yml +++ /dev/null @@ -1,19 +0,0 @@ -### YamlMime:ApiPage -title: Namespace PolylineAlgorithm.Extensions -body: -- api1: Namespace PolylineAlgorithm.Extensions - id: PolylineAlgorithm_Extensions - metadata: - uid: PolylineAlgorithm.Extensions - commentId: N:PolylineAlgorithm.Extensions -- h3: Classes -- parameters: - - type: - text: PolylineDecoderExtensions - url: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.html - description: Provides extension methods for the interface to facilitate decoding encoded polylines. - - type: - text: PolylineEncoderExtensions - url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html - description: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines. -languageId: csharp diff --git a/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml b/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml deleted file mode 100644 index 8f6b6e76..00000000 --- a/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml +++ /dev/null @@ -1,102 +0,0 @@ -### YamlMime:ApiPage -title: Class InvalidPolylineException -body: -- api1: Class InvalidPolylineException - id: PolylineAlgorithm_InvalidPolylineException - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/InvalidPolylineException.cs#L17 - metadata: - uid: PolylineAlgorithm.InvalidPolylineException - commentId: T:PolylineAlgorithm.InvalidPolylineException -- facts: - - name: Namespace - value: - text: PolylineAlgorithm - url: PolylineAlgorithm.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Exception thrown when a polyline is determined to be malformed or invalid during processing. -- code: 'public sealed class InvalidPolylineException : Exception, ISerializable' -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: Exception - url: https://learn.microsoft.com/dotnet/api/system.exception - - text: InvalidPolylineException - url: PolylineAlgorithm.InvalidPolylineException.html -- h4: Implements -- list: - - text: ISerializable - url: https://learn.microsoft.com/dotnet/api/system.runtime.serialization.iserializable -- h4: Inherited Members -- list: - - text: Exception.GetBaseException() - url: https://learn.microsoft.com/dotnet/api/system.exception.getbaseexception - - text: Exception.GetObjectData(SerializationInfo, StreamingContext) - url: https://learn.microsoft.com/dotnet/api/system.exception.getobjectdata - - text: Exception.GetType() - url: https://learn.microsoft.com/dotnet/api/system.exception.gettype - - text: Exception.ToString() - url: https://learn.microsoft.com/dotnet/api/system.exception.tostring - - text: Exception.Data - url: https://learn.microsoft.com/dotnet/api/system.exception.data - - text: Exception.HelpLink - url: https://learn.microsoft.com/dotnet/api/system.exception.helplink - - text: Exception.HResult - url: https://learn.microsoft.com/dotnet/api/system.exception.hresult - - text: Exception.InnerException - url: https://learn.microsoft.com/dotnet/api/system.exception.innerexception - - text: Exception.Message - url: https://learn.microsoft.com/dotnet/api/system.exception.message - - text: Exception.Source - url: https://learn.microsoft.com/dotnet/api/system.exception.source - - text: Exception.StackTrace - url: https://learn.microsoft.com/dotnet/api/system.exception.stacktrace - - text: Exception.TargetSite - url: https://learn.microsoft.com/dotnet/api/system.exception.targetsite - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Remarks -- markdown: This exception is used internally to indicate that a polyline string does not conform to the expected format or contains errors. -- h2: Constructors -- api3: InvalidPolylineException() - id: PolylineAlgorithm_InvalidPolylineException__ctor - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/InvalidPolylineException.cs#L22 - metadata: - uid: PolylineAlgorithm.InvalidPolylineException.#ctor - commentId: M:PolylineAlgorithm.InvalidPolylineException.#ctor -- markdown: Initializes a new instance of the class. -- code: public InvalidPolylineException() -- api3: InvalidPolylineException(string, Exception) - id: PolylineAlgorithm_InvalidPolylineException__ctor_System_String_System_Exception_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/InvalidPolylineException.cs#L43 - metadata: - uid: PolylineAlgorithm.InvalidPolylineException.#ctor(System.String,System.Exception) - commentId: M:PolylineAlgorithm.InvalidPolylineException.#ctor(System.String,System.Exception) -- markdown: Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. -- code: public InvalidPolylineException(string message, Exception innerException) -- h4: Parameters -- parameters: - - name: message - type: - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - description: The error message that explains the reason for the exception. - - name: innerException - type: - - text: Exception - url: https://learn.microsoft.com/dotnet/api/system.exception - description: The exception that is the cause of the current exception, or a null reference if no inner exception is specified. -languageId: csharp -metadata: - description: Exception thrown when a polyline is determined to be malformed or invalid during processing. diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml deleted file mode 100644 index 56818e4c..00000000 --- a/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml +++ /dev/null @@ -1,529 +0,0 @@ -### YamlMime:ApiPage -title: Class PolylineEncoding -body: -- api1: Class PolylineEncoding - id: PolylineAlgorithm_PolylineEncoding - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L23 - metadata: - uid: PolylineAlgorithm.PolylineEncoding - commentId: T:PolylineAlgorithm.PolylineEncoding -- facts: - - name: Namespace - value: - text: PolylineAlgorithm - url: PolylineAlgorithm.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: >- - Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing - - geographic coordinate values. -- code: public static class PolylineEncoding -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: PolylineEncoding - url: PolylineAlgorithm.PolylineEncoding.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.MemberwiseClone() - url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Remarks -- markdown: >- - The class includes functionality for working with encoded polyline - data, such as reading and writing encoded values, as well as methods for normalizing and de-normalizing geographic - coordinates. It also provides validation utilities to ensure values conform to expected ranges for latitude and - longitude. -- h2: Methods -- api3: Denormalize(int, uint) - id: PolylineAlgorithm_PolylineEncoding_Denormalize_System_Int32_System_UInt32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L122 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32) - commentId: M:PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32) -- markdown: Converts a normalized integer coordinate value back to its floating-point representation based on the specified precision. -- code: public static double Denormalize(int value, uint precision = 5) -- h4: Parameters -- parameters: - - name: value - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: The integer value to denormalize. Typically produced by the method. - - name: precision - type: - - text: uint - url: https://learn.microsoft.com/dotnet/api/system.uint32 - description: The number of decimal places used during normalization. Default is 5, matching standard polyline encoding precision. - optional: true -- h4: Returns -- parameters: - - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The denormalized floating-point coordinate value. -- h4: Remarks -- markdown: >- -

- - This method reverses the normalization performed by . It takes an integer value and converts it - - to a double by dividing it by 10 raised to the power of the specified precision. If precision is 0, - - the value is returned as a double without division. - -

- -

- - The calculation is performed inside a checked block to ensure that any arithmetic overflow is detected - - and an is thrown. - -

- -

- - For example, with a precision of 5: - - -

  • A value of 3778903 becomes 37.78903
  • A value of -12241230 becomes -122.4123
- -

- -

- - If the input value is 0, the method returns 0.0 immediately. - -

-- h4: Exceptions -- parameters: - - type: - - text: OverflowException - url: https://learn.microsoft.com/dotnet/api/system.overflowexception - description: Thrown if the arithmetic operation overflows during conversion. -- api3: GetRequiredBufferSize(int) - id: PolylineAlgorithm_PolylineEncoding_GetRequiredBufferSize_System_Int32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L298 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32) - commentId: M:PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32) -- markdown: Calculates the number of characters required to encode a delta value in polyline format. -- code: public static int GetRequiredBufferSize(int delta) -- h4: Parameters -- parameters: - - name: delta - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: >- - The integer delta value to calculate the encoded size for. This value typically represents the difference between - - consecutive coordinate values in polyline encoding. -- h4: Returns -- parameters: - - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: The number of characters required to encode the specified delta value. The minimum return value is 1. -- h4: Remarks -- markdown: >- -

- - This method determines how many characters will be needed to represent an integer delta value when encoded - - using the polyline encoding algorithm. It performs the same zigzag encoding transformation as - - but only calculates the required buffer size without actually writing any data. - -

- -

- - The calculation process: - - -

  1. Applies zigzag encoding: left-shifts the value by 1 bit, then inverts all bits if the original value was negative
  2. Counts how many 5-bit chunks are needed to represent the encoded value
  3. Each chunk requires one character, with a minimum of 1 character for any value
- -

- -

- - This method is useful for pre-allocating buffers of the correct size before encoding polyline data, helping to avoid - - buffer overflow checks during the actual encoding process. - -

- -

- - The method uses a long internally to prevent overflow during the left-shift operation on large negative values. - -

-- h4: See Also -- list: - - - text: PolylineEncoding - url: PolylineAlgorithm.PolylineEncoding.html - - . - - text: TryWriteValue - url: PolylineAlgorithm.PolylineEncoding.html#PolylineAlgorithm_PolylineEncoding_TryWriteValue_System_Int32_System_Span_System_Char__System_Int32__ - - ( - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - - ',' - - " " - - text: Span - url: https://learn.microsoft.com/dotnet/api/system.span-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - - ',' - - " " - - ref - - " " - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - - ) -- api3: Normalize(double, uint) - id: PolylineAlgorithm_PolylineEncoding_Normalize_System_Double_System_UInt32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L61 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32) - commentId: M:PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32) -- markdown: Normalizes a geographic coordinate value to an integer representation based on the specified precision. -- code: public static int Normalize(double value, uint precision = 5) -- h4: Parameters -- parameters: - - name: value - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The numeric value to normalize. Must be a finite number (not NaN or infinity). - - name: precision - type: - - text: uint - url: https://learn.microsoft.com/dotnet/api/system.uint32 - description: >- - The number of decimal places of precision to preserve in the normalized value. - - The value is multiplied by 10^precision before rounding. - - Default is 5, which is standard for polyline encoding. - optional: true -- h4: Returns -- parameters: - - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: An integer representing the normalized value. Returns 0 if the input value is 0.0. -- h4: Remarks -- markdown: >- -

- - This method converts a floating-point coordinate value into a normalized integer by multiplying it by 10 raised - - to the power of the specified precision, then truncating the result to an integer. - -

- -

- - For example, with the default precision of 5: - - -

  • A value of 37.78903 becomes 3778903
  • A value of -122.4123 becomes -12241230
- -

- -

- - The method validates that the input value is finite (not NaN or infinity) before performing normalization. - - If the precision is 0, the value is rounded without multiplication. - -

-- h4: Exceptions -- parameters: - - type: - - text: ArgumentOutOfRangeException - url: https://learn.microsoft.com/dotnet/api/system.argumentoutofrangeexception - description: Thrown when value is not a finite number (NaN or infinity). - - type: - - text: OverflowException - url: https://learn.microsoft.com/dotnet/api/system.overflowexception - description: Thrown when the normalized result exceeds the range of a 32-bit signed integer during the conversion from double to int. -- api3: TryReadValue(ref int, ReadOnlyMemory, ref int) - id: PolylineAlgorithm_PolylineEncoding_TryReadValue_System_Int32__System_ReadOnlyMemory_System_Char__System_Int32__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L169 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@) - commentId: M:PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@) -- markdown: Attempts to read an encoded integer value from a polyline buffer, updating the specified delta and position. -- code: public static bool TryReadValue(ref int delta, ReadOnlyMemory buffer, ref int position) -- h4: Parameters -- parameters: - - name: delta - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: Reference to the integer accumulator that will be updated with the decoded value. - - name: buffer - type: - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: The buffer containing polyline-encoded characters. - - name: position - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: Reference to the current position in the buffer. This value is updated as characters are read. -- h4: Returns -- parameters: - - type: - - text: bool - url: https://learn.microsoft.com/dotnet/api/system.boolean - description: true if a value was successfully read and decoded; false if the buffer ended before a complete value was read. -- h4: Remarks -- markdown: >- -

- - This method decodes a value from a polyline-encoded character buffer, starting at the given position. It reads - - characters sequentially, applying the polyline decoding algorithm, and updates the delta with - - the decoded value. The position is advanced as characters are processed. - -

- -

- - The decoding process continues until a character with a value less than the algorithm's space constant is encountered, - - which signals the end of the encoded value. If the buffer is exhausted before a complete value is read, the method returns false. - -

- -

- - The decoded value is added to delta using zigzag decoding, which handles both positive and negative values. - -

-- api3: TryWriteValue(int, Span, ref int) - id: PolylineAlgorithm_PolylineEncoding_TryWriteValue_System_Int32_System_Span_System_Char__System_Int32__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L237 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@) - commentId: M:PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@) -- markdown: Attempts to write an encoded integer value to a polyline buffer, updating the specified position. -- code: public static bool TryWriteValue(int delta, Span buffer, ref int position) -- h4: Parameters -- parameters: - - name: delta - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: >- - The integer value to encode and write to the buffer. This value typically represents the difference between consecutive - - coordinate values in polyline encoding. - - name: buffer - type: - - text: Span - url: https://learn.microsoft.com/dotnet/api/system.span-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: The destination buffer where the encoded characters will be written. Must have sufficient capacity to hold the encoded value. - - name: position - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: >- - Reference to the current position in the buffer. This value is updated as characters are written to reflect the new position - - after encoding is complete. -- h4: Returns -- parameters: - - type: - - text: bool - url: https://learn.microsoft.com/dotnet/api/system.boolean - description: >- - true if the value was successfully encoded and written to the buffer; false if the buffer - - does not have sufficient remaining capacity to hold the encoded value. -- h4: Remarks -- markdown: >- -

- - This method encodes an integer delta value into a polyline-encoded format and writes it to the provided character buffer, - - starting at the given position. It applies zigzag encoding followed by the polyline encoding algorithm to represent - - both positive and negative values efficiently. - -

- -

- - The encoding process first converts the value using zigzag encoding (left shift by 1, with bitwise inversion for negative values), - - then writes it as a sequence of characters. Each character encodes 5 bits of data, with continuation bits indicating whether - - more characters follow. The position is advanced as characters are written. - -

- -

- - Before writing, the method validates that sufficient space is available in the buffer by calling . - - If the buffer does not have enough remaining capacity, the method returns false without modifying the buffer or position. - -

- -

- - This method is the inverse of and can be used to encode coordinate deltas for polyline serialization. - -

-- api3: ValidateBlockLength(ReadOnlySpan) - id: PolylineAlgorithm_PolylineEncoding_ValidateBlockLength_System_ReadOnlySpan_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L438 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char}) - commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char}) -- markdown: Validates the block structure of a polyline segment, ensuring each encoded value does not exceed 7 characters and the polyline ends correctly. -- code: public static void ValidateBlockLength(ReadOnlySpan polyline) -- h4: Parameters -- parameters: - - name: polyline - type: - - text: ReadOnlySpan - url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: A span representing the polyline segment to validate. -- h4: Remarks -- markdown: >- -

- - Iterates through the polyline, counting the length of each block (a sequence of characters representing an encoded value). - - Throws an if any block exceeds 7 characters or if the polyline does not end with a valid block terminator. - -

-- h4: Exceptions -- parameters: - - type: - - text: ArgumentException - url: https://learn.microsoft.com/dotnet/api/system.argumentexception - description: Thrown when a block exceeds 7 characters or the polyline does not end with a valid block terminator. -- api3: ValidateCharRange(ReadOnlySpan) - id: PolylineAlgorithm_PolylineEncoding_ValidateCharRange_System_ReadOnlySpan_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L392 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char}) - commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char}) -- markdown: Validates that all characters in the polyline segment are within the allowed ASCII range for polyline encoding. -- code: public static void ValidateCharRange(ReadOnlySpan polyline) -- h4: Parameters -- parameters: - - name: polyline - type: - - text: ReadOnlySpan - url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: A span representing the polyline segment to validate. -- h4: Remarks -- markdown: >- -

- - Uses SIMD vectorization for efficient validation of large spans. Falls back to scalar checks for any block where an invalid character is detected. - -

- -

- - The valid range is from '?' (63) to '_' (95), inclusive. If an invalid character is found, an is thrown. - -

-- h4: Exceptions -- parameters: - - type: - - text: ArgumentException - url: https://learn.microsoft.com/dotnet/api/system.argumentexception - description: Thrown when an invalid character is found in the polyline segment. -- api3: ValidateFormat(ReadOnlySpan) - id: PolylineAlgorithm_PolylineEncoding_ValidateFormat_System_ReadOnlySpan_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L370 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char}) - commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char}) -- markdown: Validates the format of a polyline segment, ensuring all characters are valid and block structure is correct. -- code: public static void ValidateFormat(ReadOnlySpan polyline) -- h4: Parameters -- parameters: - - name: polyline - type: - - text: ReadOnlySpan - url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: A span representing the polyline segment to validate. -- h4: Remarks -- markdown: >- -

- - This method performs two levels of validation on the provided polyline segment: - -

- -
  1. - Character Range Validation: Checks that every character in the polyline is within the valid ASCII range for polyline encoding ('?' [63] to '_' [95], inclusive). - Uses SIMD acceleration for efficient validation of large segments. -
  2. - Block Structure Validation: Ensures that each encoded value (block) does not exceed 7 characters and that the polyline ends with a valid block terminator. -
-

- - If an invalid character or block structure is detected, an is thrown with details about the error. - -

-- h4: Exceptions -- parameters: - - type: - - text: ArgumentException - url: https://learn.microsoft.com/dotnet/api/system.argumentexception - description: Thrown when an invalid character is found or the block structure is invalid. -languageId: csharp -metadata: - description: >- - Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing - - geographic coordinate values. diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml deleted file mode 100644 index 90dc279b..00000000 --- a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml +++ /dev/null @@ -1,127 +0,0 @@ -### YamlMime:ApiPage -title: Class PolylineEncodingOptions -body: -- api1: Class PolylineEncodingOptions - id: PolylineAlgorithm_PolylineEncodingOptions - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L29 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptions - commentId: T:PolylineAlgorithm.PolylineEncodingOptions -- facts: - - name: Namespace - value: - text: PolylineAlgorithm - url: PolylineAlgorithm.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Provides configuration options for polyline encoding operations. -- code: public sealed class PolylineEncodingOptions -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Remarks -- markdown: >- -

- - This class allows you to configure various aspects of polyline encoding, including: - -

- -
  • The level for coordinate encoding
  • The for memory allocation strategy
  • The for diagnostic logging
- -

- - All properties have internal setters and should be configured through a builder or factory pattern. - -

-- h2: Properties -- api3: LoggerFactory - id: PolylineAlgorithm_PolylineEncodingOptions_LoggerFactory - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L41 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory - commentId: P:PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory -- markdown: Gets the logger factory used for diagnostic logging during encoding operations. -- code: public ILoggerFactory LoggerFactory { get; } -- h4: Property Value -- parameters: - - type: - - text: ILoggerFactory - url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggerfactory -- h4: Remarks -- markdown: >- - The default logger factory is , which does not log any messages. - - To enable logging, provide a custom implementation. -- api3: Precision - id: PolylineAlgorithm_PolylineEncodingOptions_Precision - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L60 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptions.Precision - commentId: P:PolylineAlgorithm.PolylineEncodingOptions.Precision -- markdown: Gets the precision level used for encoding coordinate values. -- code: public uint Precision { get; } -- h4: Property Value -- parameters: - - type: - - text: uint - url: https://learn.microsoft.com/dotnet/api/system.uint32 -- h4: Remarks -- markdown: >- -

- - The precision determines the number of decimal places to which each coordinate value (latitude or longitude) - - is multiplied and truncated (not rounded) before encoding. For example, a precision of 5 means each coordinate is multiplied by 10^5 - - and truncated to an integer before encoding. - -

- -

- - This setting does not directly correspond to a physical distance or accuracy in meters, but rather controls - - the granularity of the encoded values. - -

-- api3: StackAllocLimit - id: PolylineAlgorithm_PolylineEncodingOptions_StackAllocLimit - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L73 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit - commentId: P:PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit -- markdown: Gets the maximum buffer size (in characters) that can be allocated on the stack for encoding operations. -- code: public int StackAllocLimit { get; } -- h4: Property Value -- parameters: - - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 -- h4: Remarks -- markdown: >- - When the required buffer size for encoding exceeds this limit, memory will be allocated on the heap instead of the stack. - - This setting specifically applies to stack allocation of character arrays (stackalloc char[]) used during polyline encoding, - - balancing performance and stack safety. -languageId: csharp -metadata: - description: Provides configuration options for polyline encoding operations. diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml deleted file mode 100644 index 2c959bdb..00000000 --- a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml +++ /dev/null @@ -1,141 +0,0 @@ -### YamlMime:ApiPage -title: Class PolylineEncodingOptionsBuilder -body: -- api1: Class PolylineEncodingOptionsBuilder - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L15 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder - commentId: T:PolylineAlgorithm.PolylineEncodingOptionsBuilder -- facts: - - name: Namespace - value: - text: PolylineAlgorithm - url: PolylineAlgorithm.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Provides a builder for configuring options for polyline encoding operations. -- code: public sealed class PolylineEncodingOptionsBuilder -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Methods -- api3: Build() - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Build - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L38 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build - commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build -- markdown: Builds a new instance using the configured options. -- code: public PolylineEncodingOptions Build() -- h4: Returns -- parameters: - - type: - - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html - description: A configured instance. -- api3: Create() - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Create - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L28 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create - commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create -- markdown: Creates a new instance for the specified coordinate type. -- code: public static PolylineEncodingOptionsBuilder Create() -- h4: Returns -- parameters: - - type: - - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html - description: An instance for configuring polyline encoding options. -- api3: WithLoggerFactory(ILoggerFactory) - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithLoggerFactory_Microsoft_Extensions_Logging_ILoggerFactory_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L97 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory) - commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory) -- markdown: Configures the to be used for logging during polyline encoding operations. -- code: public PolylineEncodingOptionsBuilder WithLoggerFactory(ILoggerFactory loggerFactory) -- h4: Parameters -- parameters: - - name: loggerFactory - type: - - text: ILoggerFactory - url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggerfactory - description: The instance to use for logging. If null, a will be used instead. -- h4: Returns -- parameters: - - type: - - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html - description: The current instance for method chaining. -- api3: WithPrecision(uint) - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithPrecision_System_UInt32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L82 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32) - commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32) -- markdown: Sets the coordinate encoding precision. -- code: public PolylineEncodingOptionsBuilder WithPrecision(uint precision) -- h4: Parameters -- parameters: - - name: precision - type: - - text: uint - url: https://learn.microsoft.com/dotnet/api/system.uint32 - description: The number of decimal places to use for encoding coordinate values. Default is 5. -- h4: Returns -- parameters: - - type: - - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html - description: The current instance for method chaining. -- api3: WithStackAllocLimit(int) - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithStackAllocLimit_System_Int32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L61 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32) - commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32) -- markdown: Configures the buffer size used for stack allocation during polyline encoding operations. -- code: public PolylineEncodingOptionsBuilder WithStackAllocLimit(int stackAllocLimit) -- h4: Parameters -- parameters: - - name: stackAllocLimit - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: The maximum buffer size to use for stack allocation. Must be greater than or equal to 1. -- h4: Returns -- parameters: - - type: - - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html - description: The current instance for method chaining. -- h4: Remarks -- markdown: This method allows customization of the internal buffer size for encoding, which can impact performance and memory usage. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentOutOfRangeException - url: https://learn.microsoft.com/dotnet/api/system.argumentoutofrangeexception - description: Thrown if stackAllocLimit is less than 1. -languageId: csharp -metadata: - description: Provides a builder for configuring options for polyline encoding operations. diff --git a/api-reference/0.0/PolylineAlgorithm.yml b/api-reference/0.0/PolylineAlgorithm.yml deleted file mode 100644 index b60dc3c0..00000000 --- a/api-reference/0.0/PolylineAlgorithm.yml +++ /dev/null @@ -1,38 +0,0 @@ -### YamlMime:ApiPage -title: Namespace PolylineAlgorithm -body: -- api1: Namespace PolylineAlgorithm - id: PolylineAlgorithm - metadata: - uid: PolylineAlgorithm - commentId: N:PolylineAlgorithm -- h3: Namespaces -- parameters: - - type: - text: PolylineAlgorithm.Abstraction - url: PolylineAlgorithm.Abstraction.html - - type: - text: PolylineAlgorithm.Extensions - url: PolylineAlgorithm.Extensions.html -- h3: Classes -- parameters: - - type: - text: InvalidPolylineException - url: PolylineAlgorithm.InvalidPolylineException.html - description: Exception thrown when a polyline is determined to be malformed or invalid during processing. - - type: - text: PolylineEncoding - url: PolylineAlgorithm.PolylineEncoding.html - description: >- - Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing - - geographic coordinate values. - - type: - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html - description: Provides configuration options for polyline encoding operations. - - type: - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html - description: Provides a builder for configuring options for polyline encoding operations. -languageId: csharp diff --git a/api-reference/0.0/toc.yml b/api-reference/0.0/toc.yml deleted file mode 100644 index d1ffc58a..00000000 --- a/api-reference/0.0/toc.yml +++ /dev/null @@ -1,34 +0,0 @@ -### YamlMime:TableOfContent -- name: PolylineAlgorithm - href: PolylineAlgorithm.yml - items: - - name: Classes - - name: InvalidPolylineException - href: PolylineAlgorithm.InvalidPolylineException.yml - - name: PolylineEncoding - href: PolylineAlgorithm.PolylineEncoding.yml - - name: PolylineEncodingOptions - href: PolylineAlgorithm.PolylineEncodingOptions.yml - - name: PolylineEncodingOptionsBuilder - href: PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml -- name: PolylineAlgorithm.Abstraction - href: PolylineAlgorithm.Abstraction.yml - items: - - name: Classes - - name: AbstractPolylineDecoder - href: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml - - name: AbstractPolylineEncoder - href: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml - - name: Interfaces - - name: IPolylineDecoder - href: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml - - name: IPolylineEncoder - href: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml -- name: PolylineAlgorithm.Extensions - href: PolylineAlgorithm.Extensions.yml - items: - - name: Classes - - name: PolylineDecoderExtensions - href: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml - - name: PolylineEncoderExtensions - href: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml From 5d88f1ecc00b6711d63961963771c33dc8111b35 Mon Sep 17 00:00:00 2001 From: Pete Sramek <2333452+petesramek@users.noreply.github.com> Date: Mon, 6 Apr 2026 00:15:03 +0200 Subject: [PATCH 09/24] fixe slnx --- PolylineAlgorithm.slnx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PolylineAlgorithm.slnx b/PolylineAlgorithm.slnx index 2be9e3c1..3c54b2a7 100644 --- a/PolylineAlgorithm.slnx +++ b/PolylineAlgorithm.slnx @@ -7,7 +7,8 @@ - + + From a7b33186446e227a25c719bed989ffa0d78af33d Mon Sep 17 00:00:00 2001 From: Pete Sramek <2333452+petesramek@users.noreply.github.com> Date: Mon, 6 Apr 2026 00:17:08 +0200 Subject: [PATCH 10/24] removed 1.0 --- ....Abstraction.AbstractPolylineDecoder-2.yml | 233 -------- ....Abstraction.AbstractPolylineEncoder-2.yml | 219 -------- ...gorithm.Abstraction.IPolylineDecoder-2.yml | 90 --- ...gorithm.Abstraction.IPolylineEncoder-2.yml | 142 ----- .../1.0/PolylineAlgorithm.Abstraction.yml | 34 -- ...m.Extensions.PolylineDecoderExtensions.yml | 195 ------- ...m.Extensions.PolylineEncoderExtensions.yml | 139 ----- .../1.0/PolylineAlgorithm.Extensions.yml | 19 - ...hm.Internal.Diagnostics.ExceptionGuard.yml | 313 ----------- ...PolylineAlgorithm.Internal.Diagnostics.yml | 15 - ...lineAlgorithm.InvalidPolylineException.yml | 102 ---- .../PolylineAlgorithm.PolylineEncoding.yml | 529 ------------------ ...ylineAlgorithm.PolylineEncodingOptions.yml | 127 ----- ...gorithm.PolylineEncodingOptionsBuilder.yml | 141 ----- api-reference/1.0/PolylineAlgorithm.yml | 38 -- api-reference/1.0/toc.yml | 34 -- 16 files changed, 2370 deletions(-) delete mode 100644 api-reference/1.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml delete mode 100644 api-reference/1.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml delete mode 100644 api-reference/1.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml delete mode 100644 api-reference/1.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml delete mode 100644 api-reference/1.0/PolylineAlgorithm.Abstraction.yml delete mode 100644 api-reference/1.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml delete mode 100644 api-reference/1.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml delete mode 100644 api-reference/1.0/PolylineAlgorithm.Extensions.yml delete mode 100644 api-reference/1.0/PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.yml delete mode 100644 api-reference/1.0/PolylineAlgorithm.Internal.Diagnostics.yml delete mode 100644 api-reference/1.0/PolylineAlgorithm.InvalidPolylineException.yml delete mode 100644 api-reference/1.0/PolylineAlgorithm.PolylineEncoding.yml delete mode 100644 api-reference/1.0/PolylineAlgorithm.PolylineEncodingOptions.yml delete mode 100644 api-reference/1.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml delete mode 100644 api-reference/1.0/PolylineAlgorithm.yml delete mode 100644 api-reference/1.0/toc.yml diff --git a/api-reference/1.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml b/api-reference/1.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml deleted file mode 100644 index 6349f59c..00000000 --- a/api-reference/1.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml +++ /dev/null @@ -1,233 +0,0 @@ -### YamlMime:ApiPage -title: Class AbstractPolylineDecoder -body: -- api1: Class AbstractPolylineDecoder - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2 - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L22 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2 - commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2 -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Abstraction - url: PolylineAlgorithm.Abstraction.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates. -- code: 'public abstract class AbstractPolylineDecoder : IPolylineDecoder' -- h4: Type Parameters -- parameters: - - name: TPolyline - description: The type that represents the encoded polyline input. - - name: TCoordinate - description: The type that represents a decoded geographic coordinate. -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: AbstractPolylineDecoder - url: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.html -- h4: Implements -- list: - - text: IPolylineDecoder - url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.MemberwiseClone() - url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Remarks -- markdown: >- - Derive from this class to implement a decoder for a specific polyline type. Override - - and to provide type-specific behavior. -- h2: Constructors -- api3: AbstractPolylineDecoder() - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L28 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor -- markdown: Initializes a new instance of the class with default encoding options. -- code: protected AbstractPolylineDecoder() -- api3: AbstractPolylineDecoder(PolylineEncodingOptions) - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L40 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) -- markdown: Initializes a new instance of the class with the specified encoding options. -- code: protected AbstractPolylineDecoder(PolylineEncodingOptions options) -- h4: Parameters -- parameters: - - name: options - type: - - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html - description: The to use for encoding operations. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when options is null. -- h2: Properties -- api3: Options - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Options - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L54 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options - commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options -- markdown: Gets the encoding options used by this polyline decoder. -- code: public PolylineEncodingOptions Options { get; } -- h4: Property Value -- parameters: - - type: - - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html -- h2: Methods -- api3: CreateCoordinate(double, double) - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_CreateCoordinate_System_Double_System_Double_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L202 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateCoordinate(System.Double,System.Double) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateCoordinate(System.Double,System.Double) -- markdown: Creates a TCoordinate instance from the specified latitude and longitude values. -- code: protected abstract TCoordinate CreateCoordinate(double latitude, double longitude) -- h4: Parameters -- parameters: - - name: latitude - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The latitude component of the coordinate, in degrees. - - name: longitude - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The longitude component of the coordinate, in degrees. -- h4: Returns -- parameters: - - type: - - TCoordinate - description: A TCoordinate instance representing the specified geographic coordinate. -- api3: Decode(TPolyline, CancellationToken) - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L81 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) -- markdown: >- - Decodes an encoded TPolyline into a sequence of TCoordinate instances, - - with support for cancellation. -- code: public IEnumerable Decode(TPolyline polyline, CancellationToken cancellationToken = default) -- h4: Parameters -- parameters: - - name: polyline - type: - - TPolyline - description: The TPolyline instance containing the encoded polyline string to decode. - - name: cancellationToken - type: - - text: CancellationToken - url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken - description: A that can be used to cancel the decoding operation. - optional: true -- h4: Returns -- parameters: - - type: - - text: IEnumerable - url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 - - < - - TCoordinate - - '>' - description: An of TCoordinate representing the decoded latitude and longitude pairs. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when polyline is null. - - type: - - text: ArgumentException - url: https://learn.microsoft.com/dotnet/api/system.argumentexception - description: Thrown when polyline is empty. - - type: - - text: InvalidPolylineException - url: PolylineAlgorithm.InvalidPolylineException.html - description: Thrown when the polyline format is invalid or malformed at a specific position. - - type: - - text: OperationCanceledException - url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception - description: Thrown when cancellationToken is canceled during decoding. -- api3: GetReadOnlyMemory(in TPolyline) - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_GetReadOnlyMemory__0__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L187 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@) -- markdown: Extracts the underlying read-only memory region of characters from the specified polyline instance. -- code: protected abstract ReadOnlyMemory GetReadOnlyMemory(in TPolyline polyline) -- h4: Parameters -- parameters: - - name: polyline - type: - - TPolyline - description: The TPolyline instance from which to extract the character sequence. -- h4: Returns -- parameters: - - type: - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: A of representing the encoded polyline characters. -- api3: ValidateFormat(ReadOnlyMemory, ILogger?) - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_ValidateFormat_System_ReadOnlyMemory_System_Char__Microsoft_Extensions_Logging_ILogger_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L167 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger) -- markdown: Validates the format of the polyline character sequence, ensuring all characters are within the allowed range. -- code: protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? logger) -- h4: Parameters -- parameters: - - name: sequence - type: - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: The read-only memory region of characters representing the polyline to validate. - - name: logger - type: - - text: ILogger - url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger - - '?' - description: An optional used to log a warning when format validation fails. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentException - url: https://learn.microsoft.com/dotnet/api/system.argumentexception - description: Thrown when the polyline contains characters outside the valid encoding range or has an invalid block structure. -languageId: csharp -metadata: - description: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates. diff --git a/api-reference/1.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml b/api-reference/1.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml deleted file mode 100644 index ec0a65e9..00000000 --- a/api-reference/1.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml +++ /dev/null @@ -1,219 +0,0 @@ -### YamlMime:ApiPage -title: Class AbstractPolylineEncoder -body: -- api1: Class AbstractPolylineEncoder - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2 - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L27 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2 - commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2 -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Abstraction - url: PolylineAlgorithm.Abstraction.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings. -- code: 'public abstract class AbstractPolylineEncoder : IPolylineEncoder' -- h4: Type Parameters -- parameters: - - name: TCoordinate - description: The type that represents a geographic coordinate to encode. - - name: TPolyline - description: The type that represents the encoded polyline output. -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: AbstractPolylineEncoder - url: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.html -- h4: Implements -- list: - - text: IPolylineEncoder - url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.MemberwiseClone() - url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h4: Extension Methods -- list: - - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, List) - url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__ - - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, TCoordinate[]) - url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___ -- h2: Remarks -- markdown: >- - Derive from this class to implement an encoder for a specific coordinate and polyline type. Override - - , , and to provide type-specific behavior. -- h2: Constructors -- api3: AbstractPolylineEncoder() - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L33 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor -- markdown: Initializes a new instance of the class with default encoding options. -- code: protected AbstractPolylineEncoder() -- api3: AbstractPolylineEncoder(PolylineEncodingOptions) - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L43 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) -- markdown: Initializes a new instance of the class with the specified encoding options. -- code: protected AbstractPolylineEncoder(PolylineEncodingOptions options) -- h4: Parameters -- parameters: - - name: options - type: - - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html - description: The to use for encoding operations. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when options is null -- h2: Properties -- api3: Options - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Options - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L57 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options - commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options -- markdown: Gets the encoding options used by this polyline encoder. -- code: public PolylineEncodingOptions Options { get; } -- h4: Property Value -- parameters: - - type: - - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html -- h2: Methods -- api3: CreatePolyline(ReadOnlyMemory) - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_CreatePolyline_System_ReadOnlyMemory_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L174 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char}) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char}) -- markdown: Creates a polyline instance from the provided read-only sequence of characters. -- code: protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline) -- h4: Parameters -- parameters: - - name: polyline - type: - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: A containing the encoded polyline characters. -- h4: Returns -- parameters: - - type: - - TPolyline - description: An instance of TPolyline representing the encoded polyline. -- api3: Encode(ReadOnlySpan, CancellationToken) - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L80 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) -- markdown: Encodes a collection of TCoordinate instances into an encoded TPolyline string. -- code: >- - [SuppressMessage("Design", "MA0051:Method is too long", Justification = "Method contains local methods. Actual method only 55 lines.")] - - public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default) -- h4: Parameters -- parameters: - - name: coordinates - type: - - text: ReadOnlySpan - url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 - - < - - TCoordinate - - '>' - description: The collection of TCoordinate objects to encode. - - name: cancellationToken - type: - - text: CancellationToken - url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken - description: A that can be used to cancel the encoding operation. - optional: true -- h4: Returns -- parameters: - - type: - - TPolyline - description: An instance of TPolyline representing the encoded coordinates. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when coordinates is null. - - type: - - text: ArgumentException - url: https://learn.microsoft.com/dotnet/api/system.argumentexception - description: Thrown when coordinates is an empty enumeration. - - type: - - text: InvalidOperationException - url: https://learn.microsoft.com/dotnet/api/system.invalidoperationexception - description: Thrown when the internal encoding buffer cannot accommodate the encoded value. -- api3: GetLatitude(TCoordinate) - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetLatitude__0_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L194 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLatitude(`0) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLatitude(`0) -- markdown: Extracts the latitude value from the specified coordinate. -- code: protected abstract double GetLatitude(TCoordinate current) -- h4: Parameters -- parameters: - - name: current - type: - - TCoordinate - description: The coordinate from which to extract the latitude. -- h4: Returns -- parameters: - - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The latitude value as a . -- api3: GetLongitude(TCoordinate) - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetLongitude__0_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L184 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLongitude(`0) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLongitude(`0) -- markdown: Extracts the longitude value from the specified coordinate. -- code: protected abstract double GetLongitude(TCoordinate current) -- h4: Parameters -- parameters: - - name: current - type: - - TCoordinate - description: The coordinate from which to extract the longitude. -- h4: Returns -- parameters: - - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The longitude value as a . -languageId: csharp -metadata: - description: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings. diff --git a/api-reference/1.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml b/api-reference/1.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml deleted file mode 100644 index 704f92b2..00000000 --- a/api-reference/1.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml +++ /dev/null @@ -1,90 +0,0 @@ -### YamlMime:ApiPage -title: Interface IPolylineDecoder -body: -- api1: Interface IPolylineDecoder - id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2 - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L22 - metadata: - uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2 - commentId: T:PolylineAlgorithm.Abstraction.IPolylineDecoder`2 -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Abstraction - url: PolylineAlgorithm.Abstraction.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates. -- code: public interface IPolylineDecoder -- h4: Type Parameters -- parameters: - - name: TPolyline - description: >- - The type that represents the encoded polyline input. Common implementations use , - - but custom wrapper types are allowed to carry additional metadata. - - name: TValue - description: >- - The coordinate type returned by the decoder. Typical implementations return a struct or class that - - contains latitude and longitude (for example a LatLng type or a ValueTuple<double,double>). -- h2: Methods -- api3: Decode(TPolyline, CancellationToken) - id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L48 - metadata: - uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) - commentId: M:PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) -- markdown: >- - Decodes the specified encoded polyline into an ordered sequence of geographic coordinates. - - The sequence preserves the original vertex order encoded by the polyline. -- code: IEnumerable Decode(TPolyline polyline, CancellationToken cancellationToken = default) -- h4: Parameters -- parameters: - - name: polyline - type: - - TPolyline - description: >- - The TPolyline instance containing the encoded polyline to decode. - - Implementations SHOULD validate the input and may throw - - or for invalid formats. - - name: cancellationToken - type: - - text: CancellationToken - url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken - description: >- - A to observe while decoding. If cancellation is requested, - - implementations SHOULD stop work and throw an . - optional: true -- h4: Returns -- parameters: - - type: - - text: IEnumerable - url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 - - < - - TValue - - '>' - description: >- - An of TValue representing the decoded - - latitude/longitude pairs (or equivalent coordinates) in the same order they were encoded. -- h4: Remarks -- markdown: >- - Implementations commonly follow the Google Encoded Polyline Algorithm Format, but this interface - - does not mandate a specific encoding. Consumers should rely on a concrete decoder's documentation - - to understand the exact encoding supported. -- h4: Exceptions -- parameters: - - type: - - text: OperationCanceledException - url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception - description: Thrown when the provided cancellationToken requests cancellation. -languageId: csharp -metadata: - description: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates. diff --git a/api-reference/1.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml b/api-reference/1.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml deleted file mode 100644 index 979fe774..00000000 --- a/api-reference/1.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml +++ /dev/null @@ -1,142 +0,0 @@ -### YamlMime:ApiPage -title: Interface IPolylineEncoder -body: -- api1: Interface IPolylineEncoder - id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2 - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L36 - metadata: - uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2 - commentId: T:PolylineAlgorithm.Abstraction.IPolylineEncoder`2 -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Abstraction - url: PolylineAlgorithm.Abstraction.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: >- - Contract for encoding a sequence of geographic coordinates into an encoded polyline representation. - - Implementations interpret the generic TValue type and produce an encoded - - representation of those coordinates as TPolyline. -- code: public interface IPolylineEncoder -- h4: Type Parameters -- parameters: - - name: TValue - description: >- - The concrete coordinate representation used by the encoder (for example a struct or class containing - - Latitude and Longitude values). Implementations must document the expected shape, - - units (typically decimal degrees), and any required fields for TValue. - - Common shapes: - - - A struct or class with two double properties named Latitude and Longitude. - - - A tuple-like type (for example ValueTuple<double,double>) where the encoder documents - which element represents latitude and longitude. - - name: TPolyline - description: >- - The encoded polyline representation returned by the encoder (for example string, - - ReadOnlyMemory<char>, or a custom wrapper type). Concrete implementations should document - - the chosen representation and any memory / ownership expectations. -- h4: Extension Methods -- list: - - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, List) - url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__ - - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, TValue[]) - url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___ -- h2: Remarks -- markdown: >- - - This interface is intentionally minimal to allow different encoding strategies (Google encoded polyline, - precision/scale variants, or custom compressed formats) to be expressed behind a common contract. - - Implementations should document: - - Coordinate precision and rounding rules (for example 1e-5 for 5-decimal precision). - - Coordinate ordering and whether altitude or additional dimensions are supported. - - Thread-safety guarantees: whether instances are safe to reuse concurrently or must be instantiated per-call. - - Implementations are encouraged to be memory-efficient; the API accepts a - to avoid forced allocations when callers already have contiguous memory. -- h2: Methods -- api3: Encode(ReadOnlySpan, CancellationToken) - id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L76 - metadata: - uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) - commentId: M:PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) -- markdown: >- - Encodes a sequence of geographic coordinates into an encoded polyline representation. - - The order of coordinates in coordinates is preserved in the encoded result. -- code: TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default) -- h4: Parameters -- parameters: - - name: coordinates - type: - - text: ReadOnlySpan - url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 - - < - - TValue - - '>' - description: >- - The collection of TValue instances to encode into a polyline. - - The span may be empty; implementations should return an appropriate empty encoded representation - - (for example an empty string or an empty memory slice) rather than null. - - name: cancellationToken - type: - - text: CancellationToken - url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken - description: >- - A that can be used to cancel the encoding operation. - - Implementations should observe this token and throw - - when cancellation is requested. For fast, in-memory encoders cancellation may be best-effort. - optional: true -- h4: Returns -- parameters: - - type: - - TPolyline - description: >- - A TPolyline containing the encoded polyline that represents the input coordinates. - - The exact format and any delimiting/terminating characters are implementation-specific and must be - - documented by concrete encoder types. -- h4: Examples -- markdown: >- -
// Example pseudocode for typical usage with a string-based encoder:
-
-    var coords = new[] {
-        new Coordinate { Latitude = 47.6219, Longitude = -122.3503 },
-        new Coordinate { Latitude = 47.6220, Longitude = -122.3504 }
-    };
-
-    IPolylineEncoder<Coordinate,string> encoder = new GoogleEncodedPolylineEncoder();
-
-    string encoded = encoder.Encode(coords, CancellationToken.None);
-- h4: Remarks -- markdown: >- - - Implementations should validate input as appropriate and document any preconditions (for example - if coordinates must be within [-90,90] latitude and [-180,180] longitude). - - For large input sequences, implementations may provide streaming or incremental encoders; those - variants can still implement this interface by materializing the final encoded result. -- h4: Exceptions -- parameters: - - type: - - text: OperationCanceledException - url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception - description: Thrown if the operation is canceled via cancellationToken. -languageId: csharp -metadata: - description: >- - Contract for encoding a sequence of geographic coordinates into an encoded polyline representation. - - Implementations interpret the generic TValue type and produce an encoded - - representation of those coordinates as TPolyline. diff --git a/api-reference/1.0/PolylineAlgorithm.Abstraction.yml b/api-reference/1.0/PolylineAlgorithm.Abstraction.yml deleted file mode 100644 index e9de48f7..00000000 --- a/api-reference/1.0/PolylineAlgorithm.Abstraction.yml +++ /dev/null @@ -1,34 +0,0 @@ -### YamlMime:ApiPage -title: Namespace PolylineAlgorithm.Abstraction -body: -- api1: Namespace PolylineAlgorithm.Abstraction - id: PolylineAlgorithm_Abstraction - metadata: - uid: PolylineAlgorithm.Abstraction - commentId: N:PolylineAlgorithm.Abstraction -- h3: Classes -- parameters: - - type: - text: AbstractPolylineDecoder - url: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.html - description: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates. - - type: - text: AbstractPolylineEncoder - url: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.html - description: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings. -- h3: Interfaces -- parameters: - - type: - text: IPolylineDecoder - url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html - description: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates. - - type: - text: IPolylineEncoder - url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html - description: >- - Contract for encoding a sequence of geographic coordinates into an encoded polyline representation. - - Implementations interpret the generic TValue type and produce an encoded - - representation of those coordinates as TPolyline. -languageId: csharp diff --git a/api-reference/1.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml b/api-reference/1.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml deleted file mode 100644 index 4b97f584..00000000 --- a/api-reference/1.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml +++ /dev/null @@ -1,195 +0,0 @@ -### YamlMime:ApiPage -title: Class PolylineDecoderExtensions -body: -- api1: Class PolylineDecoderExtensions - id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L16 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions - commentId: T:PolylineAlgorithm.Extensions.PolylineDecoderExtensions -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Extensions - url: PolylineAlgorithm.Extensions.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Provides extension methods for the interface to facilitate decoding encoded polylines. -- code: public static class PolylineDecoderExtensions -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: PolylineDecoderExtensions - url: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.MemberwiseClone() - url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Methods -- api3: Decode(IPolylineDecoder, char[]) - id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_String___0__System_Char___ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L33 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.Char[]) - commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.Char[]) -- markdown: Decodes an encoded polyline represented as a character array into a sequence of geographic coordinates. -- code: public static IEnumerable Decode(this IPolylineDecoder decoder, char[] polyline) -- h4: Parameters -- parameters: - - name: decoder - type: - - text: IPolylineDecoder - url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html - - < - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - - ',' - - " " - - TValue - - '>' - description: The instance used to perform the decoding operation. - - name: polyline - type: - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '[' - - ']' - description: The encoded polyline as a character array to decode. The array is converted to a string internally. -- h4: Returns -- parameters: - - type: - - text: IEnumerable - url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 - - < - - TValue - - '>' - description: An of TValue containing the decoded coordinate pairs. -- h4: Type Parameters -- parameters: - - name: TValue - description: The coordinate type returned by the decoder. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when decoder or polyline is null. -- api3: Decode(IPolylineDecoder, ReadOnlyMemory) - id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_String___0__System_ReadOnlyMemory_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L61 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.ReadOnlyMemory{System.Char}) - commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.ReadOnlyMemory{System.Char}) -- markdown: Decodes an encoded polyline represented as a read-only memory of characters into a sequence of geographic coordinates. -- code: public static IEnumerable Decode(this IPolylineDecoder decoder, ReadOnlyMemory polyline) -- h4: Parameters -- parameters: - - name: decoder - type: - - text: IPolylineDecoder - url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html - - < - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - - ',' - - " " - - TValue - - '>' - description: The instance used to perform the decoding operation. - - name: polyline - type: - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: The encoded polyline as a read-only memory of characters to decode. The memory is converted to a string internally. -- h4: Returns -- parameters: - - type: - - text: IEnumerable - url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 - - < - - TValue - - '>' - description: An of TValue containing the decoded coordinate pairs. -- h4: Type Parameters -- parameters: - - name: TValue - description: The coordinate type returned by the decoder. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when decoder is null. -- api3: Decode(IPolylineDecoder, TValue>, string) - id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_ReadOnlyMemory_System_Char____0__System_String_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L86 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.ReadOnlyMemory{System.Char},``0},System.String) - commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.ReadOnlyMemory{System.Char},``0},System.String) -- markdown: >- - Decodes an encoded polyline string into a sequence of geographic coordinates, - - using a decoder that accepts of . -- code: public static IEnumerable Decode(this IPolylineDecoder, TValue> decoder, string polyline) -- h4: Parameters -- parameters: - - name: decoder - type: - - text: IPolylineDecoder - url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html - - < - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - - ',' - - " " - - TValue - - '>' - description: The instance used to perform the decoding operation. - - name: polyline - type: - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - description: The encoded polyline string to decode. The string is converted to internally. -- h4: Returns -- parameters: - - type: - - text: IEnumerable - url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 - - < - - TValue - - '>' - description: An of TValue containing the decoded coordinate pairs. -- h4: Type Parameters -- parameters: - - name: TValue - description: The coordinate type returned by the decoder. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when decoder or polyline is null. -languageId: csharp -metadata: - description: Provides extension methods for the interface to facilitate decoding encoded polylines. diff --git a/api-reference/1.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml b/api-reference/1.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml deleted file mode 100644 index aeba23f9..00000000 --- a/api-reference/1.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml +++ /dev/null @@ -1,139 +0,0 @@ -### YamlMime:ApiPage -title: Class PolylineEncoderExtensions -body: -- api1: Class PolylineEncoderExtensions - id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L19 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions - commentId: T:PolylineAlgorithm.Extensions.PolylineEncoderExtensions -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Extensions - url: PolylineAlgorithm.Extensions.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines. -- code: public static class PolylineEncoderExtensions -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: PolylineEncoderExtensions - url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.MemberwiseClone() - url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Methods -- api3: Encode(IPolylineEncoder, List) - id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L37 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},System.Collections.Generic.List{``0}) - commentId: M:PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},System.Collections.Generic.List{``0}) -- markdown: Encodes a of TCoordinate instances into an encoded polyline. -- code: >- - [SuppressMessage("Design", "CA1002:Do not expose generic lists", Justification = "We need a list as we do need to marshal it as span.")] - - [SuppressMessage("Design", "MA0016:Prefer using collection abstraction instead of implementation", Justification = "We need a list as we do need to marshal it as span.")] - - public static TPolyline Encode(this IPolylineEncoder encoder, List coordinates) -- h4: Parameters -- parameters: - - name: encoder - type: - - text: IPolylineEncoder - url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html - - < - - TCoordinate - - ',' - - " " - - TPolyline - - '>' - description: The instance used to perform the encoding operation. - - name: coordinates - type: - - text: List - url: https://learn.microsoft.com/dotnet/api/system.collections.generic.list-1 - - < - - TCoordinate - - '>' - description: The list of TCoordinate objects to encode. -- h4: Returns -- parameters: - - type: - - TPolyline - description: A TPolyline instance representing the encoded polyline for the provided coordinates. -- h4: Type Parameters -- parameters: - - name: TCoordinate - description: The type that represents a geographic coordinate to encode. - - name: TPolyline - description: The type that represents the encoded polyline output. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when encoder or coordinates is null. -- api3: Encode(IPolylineEncoder, TCoordinate[]) - id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L73 - metadata: - uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},``0[]) - commentId: M:PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},``0[]) -- markdown: Encodes an array of TCoordinate instances into an encoded polyline. -- code: public static TPolyline Encode(this IPolylineEncoder encoder, TCoordinate[] coordinates) -- h4: Parameters -- parameters: - - name: encoder - type: - - text: IPolylineEncoder - url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html - - < - - TCoordinate - - ',' - - " " - - TPolyline - - '>' - description: The instance used to perform the encoding operation. - - name: coordinates - type: - - TCoordinate - - '[' - - ']' - description: The array of TCoordinate objects to encode. -- h4: Returns -- parameters: - - type: - - TPolyline - description: A TPolyline instance representing the encoded polyline for the provided coordinates. -- h4: Type Parameters -- parameters: - - name: TCoordinate - description: The type that represents a geographic coordinate to encode. - - name: TPolyline - description: The type that represents the encoded polyline output. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentNullException - url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception - description: Thrown when encoder or coordinates is null. -languageId: csharp -metadata: - description: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines. diff --git a/api-reference/1.0/PolylineAlgorithm.Extensions.yml b/api-reference/1.0/PolylineAlgorithm.Extensions.yml deleted file mode 100644 index c39da0ca..00000000 --- a/api-reference/1.0/PolylineAlgorithm.Extensions.yml +++ /dev/null @@ -1,19 +0,0 @@ -### YamlMime:ApiPage -title: Namespace PolylineAlgorithm.Extensions -body: -- api1: Namespace PolylineAlgorithm.Extensions - id: PolylineAlgorithm_Extensions - metadata: - uid: PolylineAlgorithm.Extensions - commentId: N:PolylineAlgorithm.Extensions -- h3: Classes -- parameters: - - type: - text: PolylineDecoderExtensions - url: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.html - description: Provides extension methods for the interface to facilitate decoding encoded polylines. - - type: - text: PolylineEncoderExtensions - url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html - description: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines. -languageId: csharp diff --git a/api-reference/1.0/PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.yml b/api-reference/1.0/PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.yml deleted file mode 100644 index 45962074..00000000 --- a/api-reference/1.0/PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.yml +++ /dev/null @@ -1,313 +0,0 @@ -### YamlMime:ApiPage -title: Class ExceptionGuard -body: -- api1: Class ExceptionGuard - id: PolylineAlgorithm_Internal_Diagnostics_ExceptionGuard - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Internal/Diagnostics/ExceptionGuard.cs#L29 - metadata: - uid: PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard - commentId: T:PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard -- facts: - - name: Namespace - value: - text: PolylineAlgorithm.Internal.Diagnostics - url: PolylineAlgorithm.Internal.Diagnostics.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Centralizes exception throwing for common validation and error scenarios used across the library. -- code: public static class ExceptionGuard -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: ExceptionGuard - url: PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.MemberwiseClone() - url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Remarks -- markdown: >- - Methods in this class are intentionally small and annotated so that they can act as single - - call sites for throwing exceptions (improving inlining and stack traces). Many members have - - attributes to avoid polluting callers' stack traces (__StackTraceHidden__ on supported targets) - - or to prevent inlining on older targets. -- h2: Methods -- api3: StackAllocLimitMustBeEqualOrGreaterThan(int, string) - id: PolylineAlgorithm_Internal_Diagnostics_ExceptionGuard_StackAllocLimitMustBeEqualOrGreaterThan_System_Int32_System_String_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Internal/Diagnostics/ExceptionGuard.cs#L97 - metadata: - uid: PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.StackAllocLimitMustBeEqualOrGreaterThan(System.Int32,System.String) - commentId: M:PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.StackAllocLimitMustBeEqualOrGreaterThan(System.Int32,System.String) -- markdown: Throws an when a stack allocation limit is below the required minimum. -- code: >- - [DoesNotReturn] - - public static void StackAllocLimitMustBeEqualOrGreaterThan(int minValue, string paramName) -- h4: Parameters -- parameters: - - name: minValue - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: Minimum required stack allocation limit. - - name: paramName - type: - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - description: Name of the parameter representing the limit. -- api3: ThrowArgumentCannotBeEmptyEnumerationMessage(string) - id: PolylineAlgorithm_Internal_Diagnostics_ExceptionGuard_ThrowArgumentCannotBeEmptyEnumerationMessage_System_String_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Internal/Diagnostics/ExceptionGuard.cs#L111 - metadata: - uid: PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowArgumentCannotBeEmptyEnumerationMessage(System.String) - commentId: M:PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowArgumentCannotBeEmptyEnumerationMessage(System.String) -- markdown: Throws an when an enumeration argument is empty but must contain at least one element. -- code: >- - [DoesNotReturn] - - public static void ThrowArgumentCannotBeEmptyEnumerationMessage(string paramName) -- h4: Parameters -- parameters: - - name: paramName - type: - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - description: Name of the parameter representing the enumeration. -- api3: ThrowArgumentNull(string) - id: PolylineAlgorithm_Internal_Diagnostics_ExceptionGuard_ThrowArgumentNull_System_String_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Internal/Diagnostics/ExceptionGuard.cs#L51 - metadata: - uid: PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowArgumentNull(System.String) - commentId: M:PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowArgumentNull(System.String) -- markdown: Throws an for a null argument. -- code: >- - [DoesNotReturn] - - public static void ThrowArgumentNull(string paramName) -- h4: Parameters -- parameters: - - name: paramName - type: - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - description: Name of the parameter that was null. -- api3: ThrowBufferOverflow(string) - id: PolylineAlgorithm_Internal_Diagnostics_ExceptionGuard_ThrowBufferOverflow_System_String_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Internal/Diagnostics/ExceptionGuard.cs#L65 - metadata: - uid: PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowBufferOverflow(System.String) - commentId: M:PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowBufferOverflow(System.String) -- markdown: Throws an with a provided message. -- code: >- - [DoesNotReturn] - - public static void ThrowBufferOverflow(string message) -- h4: Parameters -- parameters: - - name: message - type: - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - description: Message that describes the overflow condition. -- api3: ThrowCoordinateValueOutOfRange(double, double, double, string) - id: PolylineAlgorithm_Internal_Diagnostics_ExceptionGuard_ThrowCoordinateValueOutOfRange_System_Double_System_Double_System_Double_System_String_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Internal/Diagnostics/ExceptionGuard.cs#L82 - metadata: - uid: PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowCoordinateValueOutOfRange(System.Double,System.Double,System.Double,System.String) - commentId: M:PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowCoordinateValueOutOfRange(System.Double,System.Double,System.Double,System.String) -- markdown: Throws an when a coordinate value is outside the allowed range. -- code: >- - [DoesNotReturn] - - public static void ThrowCoordinateValueOutOfRange(double value, double min, double max, string paramName) -- h4: Parameters -- parameters: - - name: value - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The coordinate value that was out of range. - - name: min - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: Inclusive minimum allowed value. - - name: max - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: Inclusive maximum allowed value. - - name: paramName - type: - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - description: Name of the parameter containing the coordinate. -- api3: ThrowCouldNotWriteEncodedValueToBuffer() - id: PolylineAlgorithm_Internal_Diagnostics_ExceptionGuard_ThrowCouldNotWriteEncodedValueToBuffer - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Internal/Diagnostics/ExceptionGuard.cs#L124 - metadata: - uid: PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer - commentId: M:PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer -- markdown: Throws an when an encoded value could not be written to the destination buffer. -- code: >- - [DoesNotReturn] - - public static void ThrowCouldNotWriteEncodedValueToBuffer() -- api3: ThrowDestinationArrayLengthMustBeEqualOrGreaterThanPolylineLength(int, int, string) - id: PolylineAlgorithm_Internal_Diagnostics_ExceptionGuard_ThrowDestinationArrayLengthMustBeEqualOrGreaterThanPolylineLength_System_Int32_System_Int32_System_String_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Internal/Diagnostics/ExceptionGuard.cs#L140 - metadata: - uid: PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowDestinationArrayLengthMustBeEqualOrGreaterThanPolylineLength(System.Int32,System.Int32,System.String) - commentId: M:PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowDestinationArrayLengthMustBeEqualOrGreaterThanPolylineLength(System.Int32,System.Int32,System.String) -- markdown: Throws an when a destination array is not large enough to contain the polyline data. -- code: >- - [DoesNotReturn] - - public static void ThrowDestinationArrayLengthMustBeEqualOrGreaterThanPolylineLength(int destinationLength, int polylineLength, string paramName) -- h4: Parameters -- parameters: - - name: destinationLength - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: The length of the destination array. - - name: polylineLength - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: The required polyline length. - - name: paramName - type: - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - description: Name of the parameter representing the destination array. -- api3: ThrowInvalidPolylineBlockTerminator() - id: PolylineAlgorithm_Internal_Diagnostics_ExceptionGuard_ThrowInvalidPolylineBlockTerminator - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Internal/Diagnostics/ExceptionGuard.cs#L212 - metadata: - uid: PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowInvalidPolylineBlockTerminator - commentId: M:PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowInvalidPolylineBlockTerminator -- markdown: Throws an when the polyline block terminator is invalid. -- code: >- - [DoesNotReturn] - - public static void ThrowInvalidPolylineBlockTerminator() -- api3: ThrowInvalidPolylineCharacter(char, int) - id: PolylineAlgorithm_Internal_Diagnostics_ExceptionGuard_ThrowInvalidPolylineCharacter_System_Char_System_Int32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Internal/Diagnostics/ExceptionGuard.cs#L171 - metadata: - uid: PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowInvalidPolylineCharacter(System.Char,System.Int32) - commentId: M:PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowInvalidPolylineCharacter(System.Char,System.Int32) -- markdown: Throws an when an unexpected character is encountered in the polyline. -- code: >- - [DoesNotReturn] - - public static void ThrowInvalidPolylineCharacter(char character, int position) -- h4: Parameters -- parameters: - - name: character - type: - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - description: The invalid character. - - name: position - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: Position in the polyline where the character was found. -- api3: ThrowInvalidPolylineFormat(long) - id: PolylineAlgorithm_Internal_Diagnostics_ExceptionGuard_ThrowInvalidPolylineFormat_System_Int64_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Internal/Diagnostics/ExceptionGuard.cs#L199 - metadata: - uid: PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowInvalidPolylineFormat(System.Int64) - commentId: M:PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowInvalidPolylineFormat(System.Int64) -- markdown: Throws an when the polyline format is malformed. -- code: >- - [DoesNotReturn] - - public static void ThrowInvalidPolylineFormat(long position) -- h4: Parameters -- parameters: - - name: position - type: - - text: long - url: https://learn.microsoft.com/dotnet/api/system.int64 - description: Approximate position where the polyline became malformed. -- api3: ThrowInvalidPolylineLength(int, int) - id: PolylineAlgorithm_Internal_Diagnostics_ExceptionGuard_ThrowInvalidPolylineLength_System_Int32_System_Int32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Internal/Diagnostics/ExceptionGuard.cs#L156 - metadata: - uid: PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowInvalidPolylineLength(System.Int32,System.Int32) - commentId: M:PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowInvalidPolylineLength(System.Int32,System.Int32) -- markdown: Throws an when the polyline length is invalid. -- code: >- - [DoesNotReturn] - - public static void ThrowInvalidPolylineLength(int length, int min) -- h4: Parameters -- parameters: - - name: length - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: The invalid length. - - name: min - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: The minimum required length. -- api3: ThrowNotFiniteNumber(string) - id: PolylineAlgorithm_Internal_Diagnostics_ExceptionGuard_ThrowNotFiniteNumber_System_String_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Internal/Diagnostics/ExceptionGuard.cs#L37 - metadata: - uid: PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowNotFiniteNumber(System.String) - commentId: M:PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowNotFiniteNumber(System.String) -- markdown: Throws an when a numeric argument is not a finite value. -- code: >- - [DoesNotReturn] - - public static void ThrowNotFiniteNumber(string paramName) -- h4: Parameters -- parameters: - - name: paramName - type: - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - description: Name of the parameter that had a non-finite value. -- api3: ThrowPolylineBlockTooLong(int) - id: PolylineAlgorithm_Internal_Diagnostics_ExceptionGuard_ThrowPolylineBlockTooLong_System_Int32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/Internal/Diagnostics/ExceptionGuard.cs#L185 - metadata: - uid: PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowPolylineBlockTooLong(System.Int32) - commentId: M:PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.ThrowPolylineBlockTooLong(System.Int32) -- markdown: Throws an when a polyline block is longer than allowed. -- code: >- - [DoesNotReturn] - - public static void ThrowPolylineBlockTooLong(int position) -- h4: Parameters -- parameters: - - name: position - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: Position in the polyline where the block exceeded the allowed length. -languageId: csharp -metadata: - description: Centralizes exception throwing for common validation and error scenarios used across the library. diff --git a/api-reference/1.0/PolylineAlgorithm.Internal.Diagnostics.yml b/api-reference/1.0/PolylineAlgorithm.Internal.Diagnostics.yml deleted file mode 100644 index dabb499a..00000000 --- a/api-reference/1.0/PolylineAlgorithm.Internal.Diagnostics.yml +++ /dev/null @@ -1,15 +0,0 @@ -### YamlMime:ApiPage -title: Namespace PolylineAlgorithm.Internal.Diagnostics -body: -- api1: Namespace PolylineAlgorithm.Internal.Diagnostics - id: PolylineAlgorithm_Internal_Diagnostics - metadata: - uid: PolylineAlgorithm.Internal.Diagnostics - commentId: N:PolylineAlgorithm.Internal.Diagnostics -- h3: Classes -- parameters: - - type: - text: ExceptionGuard - url: PolylineAlgorithm.Internal.Diagnostics.ExceptionGuard.html - description: Centralizes exception throwing for common validation and error scenarios used across the library. -languageId: csharp diff --git a/api-reference/1.0/PolylineAlgorithm.InvalidPolylineException.yml b/api-reference/1.0/PolylineAlgorithm.InvalidPolylineException.yml deleted file mode 100644 index b776c617..00000000 --- a/api-reference/1.0/PolylineAlgorithm.InvalidPolylineException.yml +++ /dev/null @@ -1,102 +0,0 @@ -### YamlMime:ApiPage -title: Class InvalidPolylineException -body: -- api1: Class InvalidPolylineException - id: PolylineAlgorithm_InvalidPolylineException - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/InvalidPolylineException.cs#L17 - metadata: - uid: PolylineAlgorithm.InvalidPolylineException - commentId: T:PolylineAlgorithm.InvalidPolylineException -- facts: - - name: Namespace - value: - text: PolylineAlgorithm - url: PolylineAlgorithm.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Exception thrown when a polyline is determined to be malformed or invalid during processing. -- code: 'public sealed class InvalidPolylineException : Exception, ISerializable' -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: Exception - url: https://learn.microsoft.com/dotnet/api/system.exception - - text: InvalidPolylineException - url: PolylineAlgorithm.InvalidPolylineException.html -- h4: Implements -- list: - - text: ISerializable - url: https://learn.microsoft.com/dotnet/api/system.runtime.serialization.iserializable -- h4: Inherited Members -- list: - - text: Exception.GetBaseException() - url: https://learn.microsoft.com/dotnet/api/system.exception.getbaseexception - - text: Exception.GetObjectData(SerializationInfo, StreamingContext) - url: https://learn.microsoft.com/dotnet/api/system.exception.getobjectdata - - text: Exception.GetType() - url: https://learn.microsoft.com/dotnet/api/system.exception.gettype - - text: Exception.ToString() - url: https://learn.microsoft.com/dotnet/api/system.exception.tostring - - text: Exception.Data - url: https://learn.microsoft.com/dotnet/api/system.exception.data - - text: Exception.HelpLink - url: https://learn.microsoft.com/dotnet/api/system.exception.helplink - - text: Exception.HResult - url: https://learn.microsoft.com/dotnet/api/system.exception.hresult - - text: Exception.InnerException - url: https://learn.microsoft.com/dotnet/api/system.exception.innerexception - - text: Exception.Message - url: https://learn.microsoft.com/dotnet/api/system.exception.message - - text: Exception.Source - url: https://learn.microsoft.com/dotnet/api/system.exception.source - - text: Exception.StackTrace - url: https://learn.microsoft.com/dotnet/api/system.exception.stacktrace - - text: Exception.TargetSite - url: https://learn.microsoft.com/dotnet/api/system.exception.targetsite - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Remarks -- markdown: This exception is used internally to indicate that a polyline string does not conform to the expected format or contains errors. -- h2: Constructors -- api3: InvalidPolylineException() - id: PolylineAlgorithm_InvalidPolylineException__ctor - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/InvalidPolylineException.cs#L22 - metadata: - uid: PolylineAlgorithm.InvalidPolylineException.#ctor - commentId: M:PolylineAlgorithm.InvalidPolylineException.#ctor -- markdown: Initializes a new instance of the class. -- code: public InvalidPolylineException() -- api3: InvalidPolylineException(string, Exception) - id: PolylineAlgorithm_InvalidPolylineException__ctor_System_String_System_Exception_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/InvalidPolylineException.cs#L43 - metadata: - uid: PolylineAlgorithm.InvalidPolylineException.#ctor(System.String,System.Exception) - commentId: M:PolylineAlgorithm.InvalidPolylineException.#ctor(System.String,System.Exception) -- markdown: Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. -- code: public InvalidPolylineException(string message, Exception innerException) -- h4: Parameters -- parameters: - - name: message - type: - - text: string - url: https://learn.microsoft.com/dotnet/api/system.string - description: The error message that explains the reason for the exception. - - name: innerException - type: - - text: Exception - url: https://learn.microsoft.com/dotnet/api/system.exception - description: The exception that is the cause of the current exception, or a null reference if no inner exception is specified. -languageId: csharp -metadata: - description: Exception thrown when a polyline is determined to be malformed or invalid during processing. diff --git a/api-reference/1.0/PolylineAlgorithm.PolylineEncoding.yml b/api-reference/1.0/PolylineAlgorithm.PolylineEncoding.yml deleted file mode 100644 index 127dbf53..00000000 --- a/api-reference/1.0/PolylineAlgorithm.PolylineEncoding.yml +++ /dev/null @@ -1,529 +0,0 @@ -### YamlMime:ApiPage -title: Class PolylineEncoding -body: -- api1: Class PolylineEncoding - id: PolylineAlgorithm_PolylineEncoding - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncoding.cs#L23 - metadata: - uid: PolylineAlgorithm.PolylineEncoding - commentId: T:PolylineAlgorithm.PolylineEncoding -- facts: - - name: Namespace - value: - text: PolylineAlgorithm - url: PolylineAlgorithm.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: >- - Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing - - geographic coordinate values. -- code: public static class PolylineEncoding -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: PolylineEncoding - url: PolylineAlgorithm.PolylineEncoding.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.MemberwiseClone() - url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Remarks -- markdown: >- - The class includes functionality for working with encoded polyline - data, such as reading and writing encoded values, as well as methods for normalizing and de-normalizing geographic - coordinates. It also provides validation utilities to ensure values conform to expected ranges for latitude and - longitude. -- h2: Methods -- api3: Denormalize(int, uint) - id: PolylineAlgorithm_PolylineEncoding_Denormalize_System_Int32_System_UInt32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncoding.cs#L121 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32) - commentId: M:PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32) -- markdown: Converts a normalized integer coordinate value back to its floating-point representation based on the specified precision. -- code: public static double Denormalize(int value, uint precision = 5) -- h4: Parameters -- parameters: - - name: value - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: The integer value to denormalize. Typically produced by the method. - - name: precision - type: - - text: uint - url: https://learn.microsoft.com/dotnet/api/system.uint32 - description: The number of decimal places used during normalization. Default is 5, matching standard polyline encoding precision. - optional: true -- h4: Returns -- parameters: - - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The denormalized floating-point coordinate value. -- h4: Remarks -- markdown: >- -

- - This method reverses the normalization performed by . It takes an integer value and converts it - - to a double by dividing it by 10 raised to the power of the specified precision. If precision is 0, - - the value is returned as a double without division. - -

- -

- - The calculation is performed inside a checked block to ensure that any arithmetic overflow is detected - - and an is thrown. - -

- -

- - For example, with a precision of 5: - - -

  • A value of 3778903 becomes 37.78903
  • A value of -12241230 becomes -122.4123
- -

- -

- - If the input value is 0, the method returns 0.0 immediately. - -

-- h4: Exceptions -- parameters: - - type: - - text: OverflowException - url: https://learn.microsoft.com/dotnet/api/system.overflowexception - description: Thrown if the arithmetic operation overflows during conversion. -- api3: GetRequiredBufferSize(int) - id: PolylineAlgorithm_PolylineEncoding_GetRequiredBufferSize_System_Int32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncoding.cs#L297 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32) - commentId: M:PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32) -- markdown: Calculates the number of characters required to encode a delta value in polyline format. -- code: public static int GetRequiredBufferSize(int delta) -- h4: Parameters -- parameters: - - name: delta - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: >- - The integer delta value to calculate the encoded size for. This value typically represents the difference between - - consecutive coordinate values in polyline encoding. -- h4: Returns -- parameters: - - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: The number of characters required to encode the specified delta value. The minimum return value is 1. -- h4: Remarks -- markdown: >- -

- - This method determines how many characters will be needed to represent an integer delta value when encoded - - using the polyline encoding algorithm. It performs the same zigzag encoding transformation as - - but only calculates the required buffer size without actually writing any data. - -

- -

- - The calculation process: - - -

  1. Applies zigzag encoding: left-shifts the value by 1 bit, then inverts all bits if the original value was negative
  2. Counts how many 5-bit chunks are needed to represent the encoded value
  3. Each chunk requires one character, with a minimum of 1 character for any value
- -

- -

- - This method is useful for pre-allocating buffers of the correct size before encoding polyline data, helping to avoid - - buffer overflow checks during the actual encoding process. - -

- -

- - The method uses a long internally to prevent overflow during the left-shift operation on large negative values. - -

-- h4: See Also -- list: - - - text: PolylineEncoding - url: PolylineAlgorithm.PolylineEncoding.html - - . - - text: TryWriteValue - url: PolylineAlgorithm.PolylineEncoding.html#PolylineAlgorithm_PolylineEncoding_TryWriteValue_System_Int32_System_Span_System_Char__System_Int32__ - - ( - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - - ',' - - " " - - text: Span - url: https://learn.microsoft.com/dotnet/api/system.span-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - - ',' - - " " - - ref - - " " - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - - ) -- api3: Normalize(double, uint) - id: PolylineAlgorithm_PolylineEncoding_Normalize_System_Double_System_UInt32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncoding.cs#L61 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32) - commentId: M:PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32) -- markdown: Normalizes a geographic coordinate value to an integer representation based on the specified precision. -- code: public static int Normalize(double value, uint precision = 5) -- h4: Parameters -- parameters: - - name: value - type: - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - description: The numeric value to normalize. Must be a finite number (not NaN or infinity). - - name: precision - type: - - text: uint - url: https://learn.microsoft.com/dotnet/api/system.uint32 - description: >- - The number of decimal places of precision to preserve in the normalized value. - - The value is multiplied by 10^precision before rounding. - - Default is 5, which is standard for polyline encoding. - optional: true -- h4: Returns -- parameters: - - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: An integer representing the normalized value. Returns 0 if the input value is 0.0. -- h4: Remarks -- markdown: >- -

- - This method converts a floating-point coordinate value into a normalized integer by multiplying it by 10 raised - - to the power of the specified precision, then truncating the result to an integer. - -

- -

- - For example, with the default precision of 5: - - -

  • A value of 37.78903 becomes 3778903
  • A value of -122.4123 becomes -12241230
- -

- -

- - The method validates that the input value is finite (not NaN or infinity) before performing normalization. - - If the precision is 0, the value is rounded without multiplication. - -

-- h4: Exceptions -- parameters: - - type: - - text: ArgumentOutOfRangeException - url: https://learn.microsoft.com/dotnet/api/system.argumentoutofrangeexception - description: Thrown when value is not a finite number (NaN or infinity). - - type: - - text: OverflowException - url: https://learn.microsoft.com/dotnet/api/system.overflowexception - description: Thrown when the normalized result exceeds the range of a 32-bit signed integer during the conversion from double to int. -- api3: TryReadValue(ref int, ReadOnlyMemory, ref int) - id: PolylineAlgorithm_PolylineEncoding_TryReadValue_System_Int32__System_ReadOnlyMemory_System_Char__System_Int32__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncoding.cs#L168 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@) - commentId: M:PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@) -- markdown: Attempts to read an encoded integer value from a polyline buffer, updating the specified delta and position. -- code: public static bool TryReadValue(ref int delta, ReadOnlyMemory buffer, ref int position) -- h4: Parameters -- parameters: - - name: delta - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: Reference to the integer accumulator that will be updated with the decoded value. - - name: buffer - type: - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: The buffer containing polyline-encoded characters. - - name: position - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: Reference to the current position in the buffer. This value is updated as characters are read. -- h4: Returns -- parameters: - - type: - - text: bool - url: https://learn.microsoft.com/dotnet/api/system.boolean - description: true if a value was successfully read and decoded; false if the buffer ended before a complete value was read. -- h4: Remarks -- markdown: >- -

- - This method decodes a value from a polyline-encoded character buffer, starting at the given position. It reads - - characters sequentially, applying the polyline decoding algorithm, and updates the delta with - - the decoded value. The position is advanced as characters are processed. - -

- -

- - The decoding process continues until a character with a value less than the algorithm's space constant is encountered, - - which signals the end of the encoded value. If the buffer is exhausted before a complete value is read, the method returns false. - -

- -

- - The decoded value is added to delta using zigzag decoding, which handles both positive and negative values. - -

-- api3: TryWriteValue(int, Span, ref int) - id: PolylineAlgorithm_PolylineEncoding_TryWriteValue_System_Int32_System_Span_System_Char__System_Int32__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncoding.cs#L236 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@) - commentId: M:PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@) -- markdown: Attempts to write an encoded integer value to a polyline buffer, updating the specified position. -- code: public static bool TryWriteValue(int delta, Span buffer, ref int position) -- h4: Parameters -- parameters: - - name: delta - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: >- - The integer value to encode and write to the buffer. This value typically represents the difference between consecutive - - coordinate values in polyline encoding. - - name: buffer - type: - - text: Span - url: https://learn.microsoft.com/dotnet/api/system.span-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: The destination buffer where the encoded characters will be written. Must have sufficient capacity to hold the encoded value. - - name: position - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: >- - Reference to the current position in the buffer. This value is updated as characters are written to reflect the new position - - after encoding is complete. -- h4: Returns -- parameters: - - type: - - text: bool - url: https://learn.microsoft.com/dotnet/api/system.boolean - description: >- - true if the value was successfully encoded and written to the buffer; false if the buffer - - does not have sufficient remaining capacity to hold the encoded value. -- h4: Remarks -- markdown: >- -

- - This method encodes an integer delta value into a polyline-encoded format and writes it to the provided character buffer, - - starting at the given position. It applies zigzag encoding followed by the polyline encoding algorithm to represent - - both positive and negative values efficiently. - -

- -

- - The encoding process first converts the value using zigzag encoding (left shift by 1, with bitwise inversion for negative values), - - then writes it as a sequence of characters. Each character encodes 5 bits of data, with continuation bits indicating whether - - more characters follow. The position is advanced as characters are written. - -

- -

- - Before writing, the method validates that sufficient space is available in the buffer by calling . - - If the buffer does not have enough remaining capacity, the method returns false without modifying the buffer or position. - -

- -

- - This method is the inverse of and can be used to encode coordinate deltas for polyline serialization. - -

-- api3: ValidateBlockLength(ReadOnlySpan) - id: PolylineAlgorithm_PolylineEncoding_ValidateBlockLength_System_ReadOnlySpan_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncoding.cs#L437 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char}) - commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char}) -- markdown: Validates the block structure of a polyline segment, ensuring each encoded value does not exceed 7 characters and the polyline ends correctly. -- code: public static void ValidateBlockLength(ReadOnlySpan polyline) -- h4: Parameters -- parameters: - - name: polyline - type: - - text: ReadOnlySpan - url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: A span representing the polyline segment to validate. -- h4: Remarks -- markdown: >- -

- - Iterates through the polyline, counting the length of each block (a sequence of characters representing an encoded value). - - Throws an if any block exceeds 7 characters or if the polyline does not end with a valid block terminator. - -

-- h4: Exceptions -- parameters: - - type: - - text: ArgumentException - url: https://learn.microsoft.com/dotnet/api/system.argumentexception - description: Thrown when a block exceeds 7 characters or the polyline does not end with a valid block terminator. -- api3: ValidateCharRange(ReadOnlySpan) - id: PolylineAlgorithm_PolylineEncoding_ValidateCharRange_System_ReadOnlySpan_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncoding.cs#L391 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char}) - commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char}) -- markdown: Validates that all characters in the polyline segment are within the allowed ASCII range for polyline encoding. -- code: public static void ValidateCharRange(ReadOnlySpan polyline) -- h4: Parameters -- parameters: - - name: polyline - type: - - text: ReadOnlySpan - url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: A span representing the polyline segment to validate. -- h4: Remarks -- markdown: >- -

- - Uses SIMD vectorization for efficient validation of large spans. Falls back to scalar checks for any block where an invalid character is detected. - -

- -

- - The valid range is from '?' (63) to '_' (95), inclusive. If an invalid character is found, an is thrown. - -

-- h4: Exceptions -- parameters: - - type: - - text: ArgumentException - url: https://learn.microsoft.com/dotnet/api/system.argumentexception - description: Thrown when an invalid character is found in the polyline segment. -- api3: ValidateFormat(ReadOnlySpan) - id: PolylineAlgorithm_PolylineEncoding_ValidateFormat_System_ReadOnlySpan_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncoding.cs#L369 - metadata: - uid: PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char}) - commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char}) -- markdown: Validates the format of a polyline segment, ensuring all characters are valid and block structure is correct. -- code: public static void ValidateFormat(ReadOnlySpan polyline) -- h4: Parameters -- parameters: - - name: polyline - type: - - text: ReadOnlySpan - url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 - - < - - text: char - url: https://learn.microsoft.com/dotnet/api/system.char - - '>' - description: A span representing the polyline segment to validate. -- h4: Remarks -- markdown: >- -

- - This method performs two levels of validation on the provided polyline segment: - -

- -
  1. - Character Range Validation: Checks that every character in the polyline is within the valid ASCII range for polyline encoding ('?' [63] to '_' [95], inclusive). - Uses SIMD acceleration for efficient validation of large segments. -
  2. - Block Structure Validation: Ensures that each encoded value (block) does not exceed 7 characters and that the polyline ends with a valid block terminator. -
-

- - If an invalid character or block structure is detected, an is thrown with details about the error. - -

-- h4: Exceptions -- parameters: - - type: - - text: ArgumentException - url: https://learn.microsoft.com/dotnet/api/system.argumentexception - description: Thrown when an invalid character is found or the block structure is invalid. -languageId: csharp -metadata: - description: >- - Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing - - geographic coordinate values. diff --git a/api-reference/1.0/PolylineAlgorithm.PolylineEncodingOptions.yml b/api-reference/1.0/PolylineAlgorithm.PolylineEncodingOptions.yml deleted file mode 100644 index 2e3880ce..00000000 --- a/api-reference/1.0/PolylineAlgorithm.PolylineEncodingOptions.yml +++ /dev/null @@ -1,127 +0,0 @@ -### YamlMime:ApiPage -title: Class PolylineEncodingOptions -body: -- api1: Class PolylineEncodingOptions - id: PolylineAlgorithm_PolylineEncodingOptions - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L29 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptions - commentId: T:PolylineAlgorithm.PolylineEncodingOptions -- facts: - - name: Namespace - value: - text: PolylineAlgorithm - url: PolylineAlgorithm.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Provides configuration options for polyline encoding operations. -- code: public sealed class PolylineEncodingOptions -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Remarks -- markdown: >- -

- - This class allows you to configure various aspects of polyline encoding, including: - -

- -
  • The level for coordinate encoding
  • The for memory allocation strategy
  • The for diagnostic logging
- -

- - All properties have internal setters and should be configured through a builder or factory pattern. - -

-- h2: Properties -- api3: LoggerFactory - id: PolylineAlgorithm_PolylineEncodingOptions_LoggerFactory - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L41 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory - commentId: P:PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory -- markdown: Gets the logger factory used for diagnostic logging during encoding operations. -- code: public ILoggerFactory LoggerFactory { get; } -- h4: Property Value -- parameters: - - type: - - text: ILoggerFactory - url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggerfactory -- h4: Remarks -- markdown: >- - The default logger factory is , which does not log any messages. - - To enable logging, provide a custom implementation. -- api3: Precision - id: PolylineAlgorithm_PolylineEncodingOptions_Precision - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L60 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptions.Precision - commentId: P:PolylineAlgorithm.PolylineEncodingOptions.Precision -- markdown: Gets the precision level used for encoding coordinate values. -- code: public uint Precision { get; } -- h4: Property Value -- parameters: - - type: - - text: uint - url: https://learn.microsoft.com/dotnet/api/system.uint32 -- h4: Remarks -- markdown: >- -

- - The precision determines the number of decimal places to which each coordinate value (latitude or longitude) - - is multiplied and truncated (not rounded) before encoding. For example, a precision of 5 means each coordinate is multiplied by 10^5 - - and truncated to an integer before encoding. - -

- -

- - This setting does not directly correspond to a physical distance or accuracy in meters, but rather controls - - the granularity of the encoded values. - -

-- api3: StackAllocLimit - id: PolylineAlgorithm_PolylineEncodingOptions_StackAllocLimit - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L73 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit - commentId: P:PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit -- markdown: Gets the maximum buffer size (in characters) that can be allocated on the stack for encoding operations. -- code: public int StackAllocLimit { get; } -- h4: Property Value -- parameters: - - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 -- h4: Remarks -- markdown: >- - When the required buffer size for encoding exceeds this limit, memory will be allocated on the heap instead of the stack. - - This setting specifically applies to stack allocation of character arrays (stackalloc char[]) used during polyline encoding, - - balancing performance and stack safety. -languageId: csharp -metadata: - description: Provides configuration options for polyline encoding operations. diff --git a/api-reference/1.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml b/api-reference/1.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml deleted file mode 100644 index 92e6d942..00000000 --- a/api-reference/1.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml +++ /dev/null @@ -1,141 +0,0 @@ -### YamlMime:ApiPage -title: Class PolylineEncodingOptionsBuilder -body: -- api1: Class PolylineEncodingOptionsBuilder - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L15 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder - commentId: T:PolylineAlgorithm.PolylineEncodingOptionsBuilder -- facts: - - name: Namespace - value: - text: PolylineAlgorithm - url: PolylineAlgorithm.html - - name: Assembly - value: PolylineAlgorithm.dll -- markdown: Provides a builder for configuring options for polyline encoding operations. -- code: public sealed class PolylineEncodingOptionsBuilder -- h4: Inheritance -- inheritance: - - text: object - url: https://learn.microsoft.com/dotnet/api/system.object - - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html -- h4: Inherited Members -- list: - - text: object.Equals(object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) - - text: object.Equals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) - - text: object.GetHashCode() - url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode - - text: object.GetType() - url: https://learn.microsoft.com/dotnet/api/system.object.gettype - - text: object.ReferenceEquals(object, object) - url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals - - text: object.ToString() - url: https://learn.microsoft.com/dotnet/api/system.object.tostring -- h2: Methods -- api3: Build() - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Build - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L38 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build - commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build -- markdown: Builds a new instance using the configured options. -- code: public PolylineEncodingOptions Build() -- h4: Returns -- parameters: - - type: - - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html - description: A configured instance. -- api3: Create() - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Create - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L28 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create - commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create -- markdown: Creates a new instance for the specified coordinate type. -- code: public static PolylineEncodingOptionsBuilder Create() -- h4: Returns -- parameters: - - type: - - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html - description: An instance for configuring polyline encoding options. -- api3: WithLoggerFactory(ILoggerFactory) - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithLoggerFactory_Microsoft_Extensions_Logging_ILoggerFactory_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L97 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory) - commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory) -- markdown: Configures the to be used for logging during polyline encoding operations. -- code: public PolylineEncodingOptionsBuilder WithLoggerFactory(ILoggerFactory loggerFactory) -- h4: Parameters -- parameters: - - name: loggerFactory - type: - - text: ILoggerFactory - url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggerfactory - description: The instance to use for logging. If null, a will be used instead. -- h4: Returns -- parameters: - - type: - - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html - description: The current instance for method chaining. -- api3: WithPrecision(uint) - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithPrecision_System_UInt32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L82 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32) - commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32) -- markdown: Sets the coordinate encoding precision. -- code: public PolylineEncodingOptionsBuilder WithPrecision(uint precision) -- h4: Parameters -- parameters: - - name: precision - type: - - text: uint - url: https://learn.microsoft.com/dotnet/api/system.uint32 - description: The number of decimal places to use for encoding coordinate values. Default is 5. -- h4: Returns -- parameters: - - type: - - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html - description: The current instance for method chaining. -- api3: WithStackAllocLimit(int) - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithStackAllocLimit_System_Int32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/develop/1.0/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L61 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32) - commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32) -- markdown: Configures the buffer size used for stack allocation during polyline encoding operations. -- code: public PolylineEncodingOptionsBuilder WithStackAllocLimit(int stackAllocLimit) -- h4: Parameters -- parameters: - - name: stackAllocLimit - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: The maximum buffer size to use for stack allocation. Must be greater than or equal to 1. -- h4: Returns -- parameters: - - type: - - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html - description: The current instance for method chaining. -- h4: Remarks -- markdown: This method allows customization of the internal buffer size for encoding, which can impact performance and memory usage. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentOutOfRangeException - url: https://learn.microsoft.com/dotnet/api/system.argumentoutofrangeexception - description: Thrown if stackAllocLimit is less than 1. -languageId: csharp -metadata: - description: Provides a builder for configuring options for polyline encoding operations. diff --git a/api-reference/1.0/PolylineAlgorithm.yml b/api-reference/1.0/PolylineAlgorithm.yml deleted file mode 100644 index b60dc3c0..00000000 --- a/api-reference/1.0/PolylineAlgorithm.yml +++ /dev/null @@ -1,38 +0,0 @@ -### YamlMime:ApiPage -title: Namespace PolylineAlgorithm -body: -- api1: Namespace PolylineAlgorithm - id: PolylineAlgorithm - metadata: - uid: PolylineAlgorithm - commentId: N:PolylineAlgorithm -- h3: Namespaces -- parameters: - - type: - text: PolylineAlgorithm.Abstraction - url: PolylineAlgorithm.Abstraction.html - - type: - text: PolylineAlgorithm.Extensions - url: PolylineAlgorithm.Extensions.html -- h3: Classes -- parameters: - - type: - text: InvalidPolylineException - url: PolylineAlgorithm.InvalidPolylineException.html - description: Exception thrown when a polyline is determined to be malformed or invalid during processing. - - type: - text: PolylineEncoding - url: PolylineAlgorithm.PolylineEncoding.html - description: >- - Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing - - geographic coordinate values. - - type: - text: PolylineEncodingOptions - url: PolylineAlgorithm.PolylineEncodingOptions.html - description: Provides configuration options for polyline encoding operations. - - type: - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html - description: Provides a builder for configuring options for polyline encoding operations. -languageId: csharp diff --git a/api-reference/1.0/toc.yml b/api-reference/1.0/toc.yml deleted file mode 100644 index d1ffc58a..00000000 --- a/api-reference/1.0/toc.yml +++ /dev/null @@ -1,34 +0,0 @@ -### YamlMime:TableOfContent -- name: PolylineAlgorithm - href: PolylineAlgorithm.yml - items: - - name: Classes - - name: InvalidPolylineException - href: PolylineAlgorithm.InvalidPolylineException.yml - - name: PolylineEncoding - href: PolylineAlgorithm.PolylineEncoding.yml - - name: PolylineEncodingOptions - href: PolylineAlgorithm.PolylineEncodingOptions.yml - - name: PolylineEncodingOptionsBuilder - href: PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml -- name: PolylineAlgorithm.Abstraction - href: PolylineAlgorithm.Abstraction.yml - items: - - name: Classes - - name: AbstractPolylineDecoder - href: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml - - name: AbstractPolylineEncoder - href: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml - - name: Interfaces - - name: IPolylineDecoder - href: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml - - name: IPolylineEncoder - href: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml -- name: PolylineAlgorithm.Extensions - href: PolylineAlgorithm.Extensions.yml - items: - - name: Classes - - name: PolylineDecoderExtensions - href: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml - - name: PolylineEncoderExtensions - href: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml From 37db229f1a06e3590154e5bbfdc62e08d68d8317 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 5 Apr 2026 23:36:24 +0000 Subject: [PATCH 11/24] refactor: replace fixed lat/lon pair contract with N-value encoding abstraction Agent-Logs-Url: https://github.com/petesramek/polyline-algorithm-csharp/sessions/3af24e5a-f856-4f0c-9ce5-b4d12c2364ab Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com> --- .../PolylineDecoderBenchmark.cs | 21 ++-- .../PolylineEncoderBenchmark.cs | 7 +- .../NetTopologyPolylineDecoder.cs | 28 +++--- .../NetTopologyPolylineEncoder.cs | 29 +++--- .../Abstraction/AbstractPolylineDecoder.cs | 58 +++++++---- .../Abstraction/AbstractPolylineEncoder.cs | 71 +++++++------ .../Internal/CoordinateDelta.cs | 85 +++++++++------- .../Diagnostics/LogDebugExtensions.cs | 11 +-- src/PolylineAlgorithm/README.md | 13 ++- .../AbstractPolylineDecoderTests.cs | 12 ++- .../AbstractPolylineEncoderTests.cs | 7 +- .../PolylineDecoderExtensionsTests.cs | 12 ++- .../PolylineEncoderExtensionsTests.cs | 7 +- .../Internal/CoordinateDeltaTests.cs | 99 +++++++++++++------ .../Diagnostics/LogDebugExtensionsTests.cs | 34 +++---- .../RandomValueProvider.cs | 9 +- 16 files changed, 308 insertions(+), 195 deletions(-) diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs index f28c8141..0cfec808 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs @@ -93,32 +93,41 @@ public void PolylineDecoder_Decode_Memory() { } private sealed class StringPolylineDecoder : AbstractPolylineDecoder { - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) { - return (latitude, longitude); + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); } protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { return polyline?.AsMemory() ?? Memory.Empty; } + + protected override int ValuesPerItem => 2; } private sealed class CharArrayPolylineDecoder : AbstractPolylineDecoder { - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) { - return (latitude, longitude); + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); } protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) { return polyline?.AsMemory() ?? Memory.Empty; } + + protected override int ValuesPerItem => 2; } private sealed class MemoryCharPolylineDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) { - return (latitude, longitude); + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); } protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) { return polyline; } + + protected override int ValuesPerItem => 2; } } \ No newline at end of file diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs index e0b97c5c..bc428c1b 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs @@ -86,7 +86,10 @@ public void PolylineEncoder_Encode_List() { private sealed class StringPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude; - protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude; + protected override int ValuesPerItem => 2; + protected override void GetValues((double Latitude, double Longitude) item, Span values) { + values[0] = item.Latitude; + values[1] = item.Longitude; + } } } diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs index d7dcb13e..769da445 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs @@ -13,17 +13,6 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; /// Polyline decoder using NetTopologySuite. ///
internal sealed class NetTopologyPolylineDecoder : AbstractPolylineDecoder { - /// - /// Creates a NetTopologySuite point from latitude and longitude. - /// - /// Latitude value. - /// Longitude value. - /// Point instance. - protected override Point CreateCoordinate(double latitude, double longitude) { - // NetTopologySuite Point: x = longitude, y = latitude - return new Point(longitude, latitude); - } - /// /// Converts polyline string to read-only memory. /// @@ -32,4 +21,21 @@ protected override Point CreateCoordinate(double latitude, double longitude) { protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { return polyline.AsMemory(); } + + /// + /// Gets the number of values per point (latitude + longitude = 2). + /// + protected override int ValuesPerItem => 2; + + /// + /// Creates a NetTopologySuite Point from decoded values. + /// + /// Decoded values: values[0] = latitude, values[1] = longitude. + /// Point instance. + protected override Point CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + + // NetTopologySuite Point: x = longitude (values[1]), y = latitude (values[0]) + return new Point(span[1], span[0]); + } } \ No newline at end of file diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs index c6719000..afdac4ed 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs @@ -7,6 +7,7 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; using global::NetTopologySuite.Geometries; using PolylineAlgorithm.Abstraction; +using System; /// /// Polyline encoder using NetTopologySuite's Point type. @@ -26,26 +27,20 @@ protected override string CreatePolyline(ReadOnlyMemory polyline) { } /// - /// Gets latitude from point. + /// Gets the number of values per point (latitude + longitude = 2). /// - /// Point instance. - /// Latitude value. - protected override double GetLatitude(Point current) { - ArgumentNullException.ThrowIfNull(current); - - // NetTopologySuite Point: Y = latitude - return current.Y; - } + protected override int ValuesPerItem => 2; /// - /// Gets longitude from point. + /// Extracts latitude and longitude from a NetTopologySuite Point into the provided span. /// - /// Point instance. - /// Longitude value. - protected override double GetLongitude(Point current) { - ArgumentNullException.ThrowIfNull(current); - - // NetTopologySuite Point: X = longitude - return current.X; + /// The point to extract values from. + /// The span to receive the values: values[0] = latitude (Y), values[1] = longitude (X). + protected override void GetValues(Point item, Span values) { + ArgumentNullException.ThrowIfNull(item); + + // NetTopologySuite Point: Y = latitude, X = longitude + values[0] = item.Y; + values[1] = item.X; } } \ No newline at end of file diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs index 1059abb9..39f587ec 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs @@ -11,14 +11,14 @@ namespace PolylineAlgorithm.Abstraction; /// -/// Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates. +/// Provides a base implementation for decoding encoded polyline strings into sequences of items. /// /// -/// Derive from this class to implement a decoder for a specific polyline type. Override -/// and to provide type-specific behavior. +/// Derive from this class to implement a decoder for a specific polyline type. Override , +/// , and to provide type-specific behavior. /// /// The type that represents the encoded polyline input. -/// The type that represents a decoded geographic coordinate. +/// The type that represents a decoded item. public abstract class AbstractPolylineDecoder : IPolylineDecoder { private readonly ILogger> _logger; @@ -64,7 +64,7 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) { /// A that can be used to cancel the decoding operation. /// /// - /// An of representing the decoded latitude and longitude pairs. + /// An of representing the decoded items. /// /// /// Thrown when is . @@ -90,28 +90,37 @@ public IEnumerable Decode(TPolyline polyline, CancellationToken can ValidateSequence(sequence, _logger); ValidateFormat(sequence, _logger); + int valuesPerItem = ValuesPerItem; + int[] accumulated = new int[valuesPerItem]; + double[] decodedValues = new double[valuesPerItem]; int position = 0; - int encodedLatitude = 0; - int encodedLongitude = 0; try { while (position < sequence.Length) { cancellationToken.ThrowIfCancellationRequested(); - if (!PolylineEncoding.TryReadValue(ref encodedLatitude, sequence, ref position) - || !PolylineEncoding.TryReadValue(ref encodedLongitude, sequence, ref position)) { + bool allRead = true; + for (int v = 0; v < valuesPerItem; v++) { + if (!PolylineEncoding.TryReadValue(ref accumulated[v], sequence, ref position)) { + allRead = false; + break; + } + } + + if (!allRead) { _logger?.LogOperationFailedDebug(OperationName); _logger?.LogInvalidPolylineWarning(position); ExceptionGuard.ThrowInvalidPolylineFormat(position); } - double decodedLatitude = PolylineEncoding.Denormalize(encodedLatitude, Options.Precision); - double decodedLongitude = PolylineEncoding.Denormalize(encodedLongitude, Options.Precision); + for (int v = 0; v < valuesPerItem; v++) { + decodedValues[v] = PolylineEncoding.Denormalize(accumulated[v], Options.Precision); + } - _logger?.LogDecodedCoordinateDebug(decodedLatitude, decodedLongitude, position); + _logger?.LogDecodedItemDebug(valuesPerItem, position); - yield return CreateCoordinate(decodedLatitude, decodedLongitude); + yield return CreateItem(decodedValues.AsMemory()); } } finally { _logger?.LogOperationFinishedDebug(OperationName); @@ -188,17 +197,24 @@ protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? lo protected abstract ReadOnlyMemory GetReadOnlyMemory(in TPolyline polyline); /// - /// Creates a instance from the specified latitude and longitude values. + /// Gets the number of values decoded per item from the polyline. /// - /// - /// The latitude component of the coordinate, in degrees. - /// - /// - /// The longitude component of the coordinate, in degrees. + /// + /// Must be greater than zero. Each item in the decoded output is constructed from this many consecutive + /// delta-decoded values. For a standard geographic coordinate pair (latitude + longitude), return 2. + /// + protected abstract int ValuesPerItem { get; } + + /// + /// Creates a instance from the specified decoded values. + /// + /// + /// A of containing the decoded values for this item. + /// The length equals . Implementations should copy values out rather than store the memory. /// /// - /// A instance representing the specified geographic coordinate. + /// A instance representing the decoded item. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract TCoordinate CreateCoordinate(double latitude, double longitude); + protected abstract TCoordinate CreateItem(ReadOnlyMemory values); } diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs index 1bcdb0ee..7763dc5e 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs @@ -16,13 +16,13 @@ namespace PolylineAlgorithm.Abstraction; using System.Threading; /// -/// Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings. +/// Provides a base implementation for encoding sequences of items into encoded polyline strings. /// /// -/// Derive from this class to implement an encoder for a specific coordinate and polyline type. Override -/// , , and to provide type-specific behavior. +/// Derive from this class to implement an encoder for a specific item and polyline type. Override +/// , , and to provide type-specific behavior. /// -/// The type that represents a geographic coordinate to encode. +/// The type that represents an item to encode. /// The type that represents the encoded polyline output. public abstract class AbstractPolylineEncoder : IPolylineEncoder { private readonly ILogger> _logger; @@ -88,17 +88,21 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken ValidateEmptyCoordinates(ref coordinates, _logger); - CoordinateDelta delta = new(); + int valuesPerItem = ValuesPerItem; + + CoordinateDelta delta = new(valuesPerItem); int position = 0; int consumed = 0; - int length = GetMaxBufferLength(coordinates.Length); + int length = GetMaxBufferLength(coordinates.Length, valuesPerItem); char[]? temp = length <= Options.StackAllocLimit ? null : ArrayPool.Shared.Rent(length); Span buffer = temp is null ? stackalloc char[length] : temp.AsSpan(0, length); + Span doubleValues = stackalloc double[valuesPerItem]; + Span intValues = stackalloc int[valuesPerItem]; string encodedResult; @@ -106,15 +110,23 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken for (var i = 0; i < coordinates.Length; i++) { cancellationToken.ThrowIfCancellationRequested(); - delta - .Next( - PolylineEncoding.Normalize(GetLatitude(coordinates[i]), Options.Precision), - PolylineEncoding.Normalize(GetLongitude(coordinates[i]), Options.Precision) - ); + GetValues(coordinates[i], doubleValues); + + for (int v = 0; v < valuesPerItem; v++) { + intValues[v] = PolylineEncoding.Normalize(doubleValues[v], Options.Precision); + } + + delta.Next(intValues); - if (!PolylineEncoding.TryWriteValue(delta.Latitude, buffer, ref position) - || !PolylineEncoding.TryWriteValue(delta.Longitude, buffer, ref position) - ) { + bool writeSucceeded = true; + for (int v = 0; v < valuesPerItem; v++) { + if (!PolylineEncoding.TryWriteValue(delta.Deltas[v], buffer, ref position)) { + writeSucceeded = false; + break; + } + } + + if (!writeSucceeded) { // This shouldn't happen, but if it does, log the error and throw an exception. _logger .LogOperationFailedDebug(OperationName); @@ -122,7 +134,6 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken .LogCannotWriteValueToBufferWarning(position, consumed); ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer(); - } consumed++; @@ -141,10 +152,11 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken return CreatePolyline(encodedResult.AsMemory()); [MethodImpl(MethodImplOptions.AggressiveInlining)] - static int GetMaxBufferLength(int count) { + static int GetMaxBufferLength(int count, int valuesPerItem) { Debug.Assert(count > 0, "Count must be greater than zero."); + Debug.Assert(valuesPerItem > 0, "ValuesPerItem must be greater than zero."); - int requestedBufferLength = count * 2 * Defaults.Polyline.Block.Length.Max; + int requestedBufferLength = count * valuesPerItem * Defaults.Polyline.Block.Length.Max; Debug.Assert(requestedBufferLength > 0, "Requested buffer length must be greater than zero."); @@ -175,23 +187,22 @@ static void ValidateEmptyCoordinates(ref ReadOnlySpan coordinates, protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline); /// - /// Extracts the longitude value from the specified coordinate. + /// Gets the number of values extracted from each item during encoding. /// - /// The coordinate from which to extract the longitude. - /// - /// The longitude value as a . - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract double GetLongitude(TCoordinate current); + /// + /// Must be greater than zero. Each value is written as a separate delta-encoded block in the output polyline. + /// For a standard geographic coordinate pair (latitude + longitude), return 2. + /// + protected abstract int ValuesPerItem { get; } /// - /// Extracts the latitude value from the specified coordinate. + /// Extracts the encoded values from the specified item into the provided span. /// - /// The coordinate from which to extract the latitude. - /// - /// The latitude value as a . - /// + /// The item from which to extract values. + /// + /// A span that receives the extracted values. Its length equals . + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract double GetLatitude(TCoordinate current); + protected abstract void GetValues(TCoordinate item, Span values); } diff --git a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs index ae217c57..e86bbe77 100644 --- a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs +++ b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs @@ -7,66 +7,79 @@ namespace PolylineAlgorithm.Internal; using System.Diagnostics; using System.Runtime.InteropServices; +using System.Text; /// -/// Represents the difference (delta) in latitude and longitude between consecutive geographic coordinates. +/// Represents the differences (deltas) between consecutive sets of N encoded values. /// /// -/// This struct computes and stores the change in coordinate values as integer deltas between successive coordinates. +/// This struct computes and stores the change in coordinate values as integer deltas between successive items. +/// The number of values per item is fixed at construction time. /// [DebuggerDisplay("{ToString(),nq}")] [StructLayout(LayoutKind.Auto)] internal struct CoordinateDelta { - private (int Latitude, int Longitude) _current; + private readonly int[] _current; + private readonly int[] _deltas; /// - /// Initializes a new instance of the struct with the default latitude and longitude deltas. + /// Initializes a new instance of the struct for items with the specified number of values. /// - public CoordinateDelta() { - _current = (default, default); - } + /// The number of values per item. Must be greater than zero. + public CoordinateDelta(int count) { + Debug.Assert(count > 0, "Count must be greater than zero."); - /// - /// Gets the current delta in latitude between the most recent and previous coordinate. - /// - public int Latitude { get; private set; } + _current = new int[count]; + _deltas = new int[count]; + } /// - /// Gets the current delta in longitude between the most recent and previous coordinate. + /// Gets the current delta values between the most recent and previous item. /// - public int Longitude { get; private set; } + public ReadOnlySpan Deltas => _deltas; /// - /// Updates the delta values based on the next latitude and longitude, and sets the current coordinate as next delta baseline. + /// Updates the delta values based on the next set of encoded values, and sets those values as the new baseline. /// - /// The next latitude value. - /// The next longitude value. - public void Next(int latitude, int longitude) { - Latitude = Delta(_current.Latitude, latitude); - Longitude = Delta(_current.Longitude, longitude); + /// The next set of encoded integer values. Length must equal the count passed to the constructor. + public void Next(ReadOnlySpan values) { + Debug.Assert(values.Length == _current.Length, "Values length must match the count passed to the constructor."); - _current.Latitude = latitude; - _current.Longitude = longitude; + for (int i = 0; i < values.Length; i++) { + _deltas[i] = values[i] - _current[i]; + _current[i] = values[i]; + } } - /// - /// Calculates the delta between two coordinate values. - /// - /// - /// This method computes the difference between two integer coordinate values, handling cases where the values may be positive or negative. - /// - /// The previous coordinate value. - /// The next coordinate value. - /// The computed delta between and . - private static int Delta(int initial, int next) => next - initial; - /// /// Returns a string representation of the current coordinate delta. /// /// - /// A string in the format { Coordinate: { Latitude: [int], Longitude: [int] }, Delta: { Latitude: [int], Longitude: [int] } } representing the current coordinate and deltas to previous coordinate. + /// A string in the format { Coordinate: [v0, v1, ...], Delta: [d0, d1, ...] } representing the current values and their deltas to the previous item. /// - public override readonly string ToString() => - $"{{ Coordinate: {{ Latitude: {_current.Latitude}, Longitude: {_current.Longitude} }}, " + - $"Delta: {{ Latitude: {Latitude}, Longitude: {Longitude} }} }}"; + public override readonly string ToString() { + StringBuilder sb = new(); + + sb.Append("{ Coordinate: ["); + for (int i = 0; i < _current.Length; i++) { + if (i > 0) { + sb.Append(", "); + } + + sb.Append(_current[i]); + } + + sb.Append("], Delta: ["); + for (int i = 0; i < _deltas.Length; i++) { + if (i > 0) { + sb.Append(", "); + } + + sb.Append(_deltas[i]); + } + + sb.Append("] }"); + + return sb.ToString(); + } } \ No newline at end of file diff --git a/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs b/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs index cc58c702..1b21e2ae 100644 --- a/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs +++ b/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs @@ -46,12 +46,11 @@ internal static partial class LogDebugExtensions { internal static partial void LogOperationFinishedDebug(this ILogger logger, string operationName); /// - /// Logs a debug message containing the decoded coordinate values and position. + /// Logs a debug message containing the count of decoded values and the current position in the buffer. /// /// The used to write the log entry. - /// The decoded latitude value. - /// The decoded longitude value. - /// The position in the polyline buffer at which the coordinate was decoded. - [LoggerMessage(EVENT_ID_BASE + 4, LOG_LEVEL, "Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}.")] - internal static partial void LogDecodedCoordinateDebug(this ILogger logger, double latitude, double longitude, int position); + /// The number of values decoded for the current item. + /// The position in the polyline buffer at which the item was decoded. + [LoggerMessage(EVENT_ID_BASE + 4, LOG_LEVEL, "Decoded item with {valuesCount} values at position {position}.")] + internal static partial void LogDecodedItemDebug(this ILogger logger, int valuesCount, int position); } diff --git a/src/PolylineAlgorithm/README.md b/src/PolylineAlgorithm/README.md index 97c4bb98..099caa52 100644 --- a/src/PolylineAlgorithm/README.md +++ b/src/PolylineAlgorithm/README.md @@ -40,8 +40,11 @@ using PolylineAlgorithm; using PolylineAlgorithm.Abstraction; public sealed class MyPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - protected override double GetLatitude((double Latitude, double Longitude) coordinate) => coordinate.Latitude; - protected override double GetLongitude((double Latitude, double Longitude) coordinate) => coordinate.Longitude; + protected override int ValuesPerItem => 2; + protected override void GetValues((double Latitude, double Longitude) item, Span values) { + values[0] = item.Latitude; + values[1] = item.Longitude; + } protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); } ``` @@ -71,7 +74,11 @@ using PolylineAlgorithm; using PolylineAlgorithm.Abstraction; public sealed class MyPolylineDecoder : AbstractPolylineDecoder { - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); + protected override int ValuesPerItem => 2; + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); + } protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); } ``` diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs index c6734c6c..b0017ee5 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs @@ -17,7 +17,11 @@ namespace PolylineAlgorithm.Tests.Abstraction; public sealed class AbstractPolylineDecoderTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); + protected override int ValuesPerItem => 2; + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); + } } private sealed class TestStringDecoderWithOptions : AbstractPolylineDecoder { @@ -25,7 +29,11 @@ public TestStringDecoderWithOptions(PolylineEncodingOptions options) : base(options) { } protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); + protected override int ValuesPerItem => 2; + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); + } } /// diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs index f537dda2..9988012f 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs @@ -22,8 +22,11 @@ public TestStringEncoder(PolylineEncodingOptions options) : base(options) { } protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude; - protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude; + protected override int ValuesPerItem => 2; + protected override void GetValues((double Latitude, double Longitude) item, Span values) { + values[0] = item.Latitude; + values[1] = item.Longitude; + } } /// diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs index c44c914d..f651e65c 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs @@ -18,12 +18,20 @@ namespace PolylineAlgorithm.Tests.Extensions; public sealed class PolylineDecoderExtensionsTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); + protected override int ValuesPerItem => 2; + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); + } } private sealed class TestMemoryDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) => polyline; - protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude); + protected override int ValuesPerItem => 2; + protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { + ReadOnlySpan span = values.Span; + return (span[0], span[1]); + } } // ----- Decode(char[]) for IPolylineDecoder ----- diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs index da8a622e..3f322efe 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs @@ -18,8 +18,11 @@ namespace PolylineAlgorithm.Tests.Extensions; public sealed class PolylineEncoderExtensionsTests { private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude; - protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude; + protected override int ValuesPerItem => 2; + protected override void GetValues((double Latitude, double Longitude) item, Span values) { + values[0] = item.Latitude; + values[1] = item.Longitude; + } } // ----- Encode(List) ----- diff --git a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs index 1e915fe2..2109ffa8 100644 --- a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs +++ b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs @@ -14,16 +14,34 @@ namespace PolylineAlgorithm.Tests.Internal; [TestClass] public sealed class CoordinateDeltaTests { /// - /// Tests that the default constructor initializes delta values to zero. + /// Tests that the constructor with count 2 initializes delta values to zero. /// [TestMethod] - public void Constructor_Default_Initializes_Latitude_And_Longitude_To_Zero() { + public void Constructor_With_Count_Two_Initializes_Deltas_To_Zero() { // Act - CoordinateDelta delta = new(); + CoordinateDelta delta = new(2); // Assert - Assert.AreEqual(0, delta.Latitude); - Assert.AreEqual(0, delta.Longitude); + ReadOnlySpan deltas = delta.Deltas; + Assert.AreEqual(2, deltas.Length); + Assert.AreEqual(0, deltas[0]); + Assert.AreEqual(0, deltas[1]); + } + + /// + /// Tests that the constructor with count 3 initializes delta values to zero. + /// + [TestMethod] + public void Constructor_With_Count_Three_Initializes_Deltas_To_Zero() { + // Act + CoordinateDelta delta = new(3); + + // Assert + ReadOnlySpan deltas = delta.Deltas; + Assert.AreEqual(3, deltas.Length); + for (int i = 0; i < deltas.Length; i++) { + Assert.AreEqual(0, deltas[i]); + } } /// @@ -35,16 +53,17 @@ public void Constructor_Default_Initializes_Latitude_And_Longitude_To_Zero() { [DataRow(0, 0, 0, 0)] [DataRow(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue)] [DataRow(int.MinValue, int.MinValue, int.MinValue, int.MinValue)] - public void Next_Single_Call_From_Zero_Computes_Expected_Delta(int latitude, int longitude, int expectedLatitude, int expectedLongitude) { + public void Next_Single_Call_From_Zero_Computes_Expected_Delta(int first, int second, int expectedFirst, int expectedSecond) { // Arrange - CoordinateDelta delta = new(); + CoordinateDelta delta = new(2); // Act - delta.Next(latitude, longitude); + delta.Next([first, second]); // Assert - Assert.AreEqual(expectedLatitude, delta.Latitude); - Assert.AreEqual(expectedLongitude, delta.Longitude); + ReadOnlySpan deltas = delta.Deltas; + Assert.AreEqual(expectedFirst, deltas[0]); + Assert.AreEqual(expectedSecond, deltas[1]); } /// @@ -56,28 +75,48 @@ public void Next_Single_Call_From_Zero_Computes_Expected_Delta(int latitude, int [DataRow(42, 84, 42, 84, 0, 0)] [DataRow(-50, 100, 25, -75, 75, -175)] public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value( - int firstLatitude, int firstLongitude, - int secondLatitude, int secondLongitude, - int expectedLatitude, int expectedLongitude) { + int firstA, int firstB, + int secondA, int secondB, + int expectedA, int expectedB) { + // Arrange + CoordinateDelta delta = new(2); + delta.Next([firstA, firstB]); + + // Act + delta.Next([secondA, secondB]); + + // Assert + ReadOnlySpan deltas = delta.Deltas; + Assert.AreEqual(expectedA, deltas[0]); + Assert.AreEqual(expectedB, deltas[1]); + } + + /// + /// Tests that Next works correctly for N-value items (N > 2). + /// + [TestMethod] + public void Next_With_Three_Values_Computes_Expected_Deltas() { // Arrange - CoordinateDelta delta = new(); - delta.Next(firstLatitude, firstLongitude); + CoordinateDelta delta = new(3); // Act - delta.Next(secondLatitude, secondLongitude); + delta.Next([10, 20, 30]); + delta.Next([15, 25, 35]); // Assert - Assert.AreEqual(expectedLatitude, delta.Latitude); - Assert.AreEqual(expectedLongitude, delta.Longitude); + ReadOnlySpan deltas = delta.Deltas; + Assert.AreEqual(5, deltas[0]); + Assert.AreEqual(5, deltas[1]); + Assert.AreEqual(5, deltas[2]); } /// - /// Tests that ToString on a default instance returns a string containing expected structural keywords and a zero value. + /// Tests that ToString on a new instance returns a string containing expected structural keywords and zero values. /// [TestMethod] - public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zeros() { + public void ToString_With_New_Instance_Returns_Formatted_String_With_Zeros() { // Arrange - CoordinateDelta delta = new(); + CoordinateDelta delta = new(2); // Act string result = delta.ToString(); @@ -86,8 +125,6 @@ public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zero Assert.IsNotNull(result); Assert.IsTrue(result.Contains("Coordinate", StringComparison.Ordinal)); Assert.IsTrue(result.Contains("Delta", StringComparison.Ordinal)); - Assert.IsTrue(result.Contains("Latitude", StringComparison.Ordinal)); - Assert.IsTrue(result.Contains("Longitude", StringComparison.Ordinal)); Assert.Contains('0', result); } @@ -99,18 +136,18 @@ public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zero [DataRow(-100, -200)] [DataRow(int.MaxValue, int.MaxValue)] [DataRow(int.MinValue, int.MinValue)] - public void ToString_After_Next_Contains_Expected_Values(int latitude, int longitude) { + public void ToString_After_Next_Contains_Expected_Values(int first, int second) { // Arrange - CoordinateDelta delta = new(); - delta.Next(latitude, longitude); + CoordinateDelta delta = new(2); + delta.Next([first, second]); // Act string result = delta.ToString(); // Assert Assert.IsNotNull(result); - Assert.IsTrue(result.Contains(latitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal)); - Assert.IsTrue(result.Contains(longitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal)); + Assert.IsTrue(result.Contains(first.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal)); + Assert.IsTrue(result.Contains(second.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal)); } /// @@ -119,9 +156,9 @@ public void ToString_After_Next_Contains_Expected_Values(int latitude, int longi [TestMethod] public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Latest_Values() { // Arrange - CoordinateDelta delta = new(); - delta.Next(10, 20); - delta.Next(30, 50); + CoordinateDelta delta = new(2); + delta.Next([10, 20]); + delta.Next([30, 50]); // Act string result = delta.ToString(); diff --git a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs index 0dff7193..2b4b7023 100644 --- a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs @@ -9,7 +9,6 @@ namespace PolylineAlgorithm.Tests.Internal.Diagnostics; using PolylineAlgorithm.Internal.Diagnostics; using System; using System.Collections.Generic; -using System.Globalization; /// /// Tests for . @@ -80,20 +79,19 @@ public void LogOperationFinishedDebug_With_Operation_Name_Logs_Finished_Message( } /// - /// Tests that LogDecodedCoordinateDebug WithCoordinatesAndPosition LogsDecodedCoordinateMessage. + /// Tests that LogDecodedItemDebug with values count and position logs a decoded item message. /// [TestMethod] - public void LogDecodedCoordinateDebug_With_Coordinates_And_Position_Logs_Decoded_Coordinate_Message() { + public void LogDecodedItemDebug_With_Values_Count_And_Position_Logs_Decoded_Item_Message() { var logger = new TestLogger(); - const double latitude = 38.5; - const double longitude = -120.2; + const int valuesCount = 2; const int position = 42; - logger.LogDecodedCoordinateDebug(latitude, longitude, position); + logger.LogDecodedItemDebug(valuesCount, position); Assert.HasCount(1, logger.Logs); Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level); - Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}."), logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains($"Decoded item with {valuesCount} values at position {position}.", logger.Logs[0].Message, StringComparison.Ordinal); } /// @@ -142,37 +140,35 @@ public void LogOperationFinishedDebug_With_Null_Operation_Name_Logs_Message() { } /// - /// Tests that LogDecodedCoordinateDebug WithZeroCoordinates LogsMessage. + /// Tests that LogDecodedItemDebug with zero count logs a message. /// [TestMethod] - public void LogDecodedCoordinateDebug_With_Zero_Coordinates_Logs_Message() { + public void LogDecodedItemDebug_With_Zero_Values_Count_Logs_Message() { var logger = new TestLogger(); - const double latitude = 0.0; - const double longitude = 0.0; + const int valuesCount = 0; const int position = 0; - logger.LogDecodedCoordinateDebug(latitude, longitude, position); + logger.LogDecodedItemDebug(valuesCount, position); Assert.HasCount(1, logger.Logs); Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level); - Assert.Contains("Decoded coordinate", logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains("Decoded item", logger.Logs[0].Message, StringComparison.Ordinal); } /// - /// Tests that LogDecodedCoordinateDebug WithNegativeCoordinates LogsMessage. + /// Tests that LogDecodedItemDebug with large values count logs a message. /// [TestMethod] - public void LogDecodedCoordinateDebug_With_Negative_Coordinates_Logs_Message() { + public void LogDecodedItemDebug_With_Large_Values_Count_Logs_Message() { var logger = new TestLogger(); - const double latitude = -90.0; - const double longitude = -180.0; + const int valuesCount = 10; const int position = 100; - logger.LogDecodedCoordinateDebug(latitude, longitude, position); + logger.LogDecodedItemDebug(valuesCount, position); Assert.HasCount(1, logger.Logs); Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level); - Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Latitude: {latitude}, Longitude: {longitude}"), logger.Logs[0].Message, StringComparison.Ordinal); + Assert.Contains($"values at position {position}", logger.Logs[0].Message, StringComparison.Ordinal); } /// diff --git a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs index d3d83b9e..8992c560 100644 --- a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs +++ b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs @@ -109,12 +109,11 @@ protected override string CreatePolyline(ReadOnlyMemory polyline) { return polyline.ToString(); } - protected override double GetLatitude((double Latitude, double Longitude) current) { - return current.Latitude; - } + protected override int ValuesPerItem => 2; - protected override double GetLongitude((double Latitude, double Longitude) current) { - return current.Longitude; + protected override void GetValues((double Latitude, double Longitude) item, Span values) { + values[0] = item.Latitude; + values[1] = item.Longitude; } } } \ No newline at end of file From 0bbd5d05a59347352448d3fa8f1f876d2e6025ec Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 00:35:06 +0000 Subject: [PATCH 12/24] Updated docs for version 0.0 --- ....Abstraction.AbstractPolylineDecoder-2.yml | 253 +++++++++ ....Abstraction.AbstractPolylineEncoder-2.yml | 220 ++++++++ ...gorithm.Abstraction.IPolylineDecoder-2.yml | 90 +++ ...gorithm.Abstraction.IPolylineEncoder-2.yml | 142 +++++ .../0.0/PolylineAlgorithm.Abstraction.yml | 34 ++ ...m.Extensions.PolylineDecoderExtensions.yml | 195 +++++++ ...m.Extensions.PolylineEncoderExtensions.yml | 139 +++++ .../0.0/PolylineAlgorithm.Extensions.yml | 19 + ...lineAlgorithm.InvalidPolylineException.yml | 102 ++++ .../PolylineAlgorithm.PolylineEncoding.yml | 529 ++++++++++++++++++ ...ylineAlgorithm.PolylineEncodingOptions.yml | 127 +++++ ...gorithm.PolylineEncodingOptionsBuilder.yml | 141 +++++ api-reference/0.0/PolylineAlgorithm.yml | 38 ++ api-reference/0.0/toc.yml | 34 ++ 14 files changed, 2063 insertions(+) create mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.yml create mode 100644 api-reference/0.0/toc.yml diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml new file mode 100644 index 00000000..f868e1f9 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml @@ -0,0 +1,253 @@ +### YamlMime:ApiPage +title: Class AbstractPolylineDecoder +body: +- api1: Class AbstractPolylineDecoder + id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L22 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2 + commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2 +- facts: + - name: Namespace + value: + text: PolylineAlgorithm.Abstraction + url: PolylineAlgorithm.Abstraction.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: Provides a base implementation for decoding encoded polyline strings into sequences of items. +- code: 'public abstract class AbstractPolylineDecoder : IPolylineDecoder' +- h4: Type Parameters +- parameters: + - name: TPolyline + description: The type that represents the encoded polyline input. + - name: TCoordinate + description: The type that represents a decoded item. +- h4: Inheritance +- inheritance: + - text: object + url: https://learn.microsoft.com/dotnet/api/system.object + - text: AbstractPolylineDecoder + url: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.html +- h4: Implements +- list: + - text: IPolylineDecoder + url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html +- h4: Inherited Members +- list: + - text: object.Equals(object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - text: object.Equals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - text: object.GetHashCode() + url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - text: object.GetType() + url: https://learn.microsoft.com/dotnet/api/system.object.gettype + - text: object.MemberwiseClone() + url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone + - text: object.ReferenceEquals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - text: object.ToString() + url: https://learn.microsoft.com/dotnet/api/system.object.tostring +- h2: Remarks +- markdown: >- + Derive from this class to implement a decoder for a specific polyline type. Override , + + , and to provide type-specific behavior. +- h2: Constructors +- api3: AbstractPolylineDecoder() + id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L28 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor +- markdown: Initializes a new instance of the class with default encoding options. +- code: protected AbstractPolylineDecoder() +- api3: AbstractPolylineDecoder(PolylineEncodingOptions) + id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L40 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) +- markdown: Initializes a new instance of the class with the specified encoding options. +- code: protected AbstractPolylineDecoder(PolylineEncodingOptions options) +- h4: Parameters +- parameters: + - name: options + type: + - text: PolylineEncodingOptions + url: PolylineAlgorithm.PolylineEncodingOptions.html + description: The to use for encoding operations. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentNullException + url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception + description: Thrown when options is null. +- h2: Properties +- api3: Options + id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Options + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L54 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options + commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options +- markdown: Gets the encoding options used by this polyline decoder. +- code: public PolylineEncodingOptions Options { get; } +- h4: Property Value +- parameters: + - type: + - text: PolylineEncodingOptions + url: PolylineAlgorithm.PolylineEncodingOptions.html +- api3: ValuesPerItem + id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_ValuesPerItem + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L206 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValuesPerItem + commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValuesPerItem +- markdown: Gets the number of values decoded per item from the polyline. +- code: protected abstract int ValuesPerItem { get; } +- h4: Property Value +- parameters: + - type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 +- h4: Remarks +- markdown: >- + Must be greater than zero. Each item in the decoded output is constructed from this many consecutive + + delta-decoded values. For a standard geographic coordinate pair (latitude + longitude), return 2. +- h2: Methods +- api3: CreateItem(ReadOnlyMemory) + id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_CreateItem_System_ReadOnlyMemory_System_Double__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L218 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateItem(System.ReadOnlyMemory{System.Double}) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateItem(System.ReadOnlyMemory{System.Double}) +- markdown: Creates a TCoordinate instance from the specified decoded values. +- code: protected abstract TCoordinate CreateItem(ReadOnlyMemory values) +- h4: Parameters +- parameters: + - name: values + type: + - text: ReadOnlyMemory + url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 + - < + - text: double + url: https://learn.microsoft.com/dotnet/api/system.double + - '>' + description: >- + A of containing the decoded values for this item. + + The length equals . Implementations should copy values out rather than store the memory. +- h4: Returns +- parameters: + - type: + - TCoordinate + description: A TCoordinate instance representing the decoded item. +- api3: Decode(TPolyline, CancellationToken) + id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L81 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) +- markdown: >- + Decodes an encoded TPolyline into a sequence of TCoordinate instances, + + with support for cancellation. +- code: public IEnumerable Decode(TPolyline polyline, CancellationToken cancellationToken = default) +- h4: Parameters +- parameters: + - name: polyline + type: + - TPolyline + description: The TPolyline instance containing the encoded polyline string to decode. + - name: cancellationToken + type: + - text: CancellationToken + url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken + description: A that can be used to cancel the decoding operation. + optional: true +- h4: Returns +- parameters: + - type: + - text: IEnumerable + url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 + - < + - TCoordinate + - '>' + description: An of TCoordinate representing the decoded items. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentNullException + url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception + description: Thrown when polyline is null. + - type: + - text: ArgumentException + url: https://learn.microsoft.com/dotnet/api/system.argumentexception + description: Thrown when polyline is empty. + - type: + - text: InvalidPolylineException + url: PolylineAlgorithm.InvalidPolylineException.html + description: Thrown when the polyline format is invalid or malformed at a specific position. + - type: + - text: OperationCanceledException + url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception + description: Thrown when cancellationToken is canceled during decoding. +- api3: GetReadOnlyMemory(in TPolyline) + id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_GetReadOnlyMemory__0__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L196 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@) +- markdown: Extracts the underlying read-only memory region of characters from the specified polyline instance. +- code: protected abstract ReadOnlyMemory GetReadOnlyMemory(in TPolyline polyline) +- h4: Parameters +- parameters: + - name: polyline + type: + - TPolyline + description: The TPolyline instance from which to extract the character sequence. +- h4: Returns +- parameters: + - type: + - text: ReadOnlyMemory + url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + description: A of representing the encoded polyline characters. +- api3: ValidateFormat(ReadOnlyMemory, ILogger?) + id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_ValidateFormat_System_ReadOnlyMemory_System_Char__Microsoft_Extensions_Logging_ILogger_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L176 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger) +- markdown: Validates the format of the polyline character sequence, ensuring all characters are within the allowed range. +- code: protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? logger) +- h4: Parameters +- parameters: + - name: sequence + type: + - text: ReadOnlyMemory + url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + description: The read-only memory region of characters representing the polyline to validate. + - name: logger + type: + - text: ILogger + url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger + - '?' + description: An optional used to log a warning when format validation fails. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentException + url: https://learn.microsoft.com/dotnet/api/system.argumentexception + description: Thrown when the polyline contains characters outside the valid encoding range or has an invalid block structure. +languageId: csharp +metadata: + description: Provides a base implementation for decoding encoded polyline strings into sequences of items. diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml new file mode 100644 index 00000000..39cf4dd4 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml @@ -0,0 +1,220 @@ +### YamlMime:ApiPage +title: Class AbstractPolylineEncoder +body: +- api1: Class AbstractPolylineEncoder + id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L27 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2 + commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2 +- facts: + - name: Namespace + value: + text: PolylineAlgorithm.Abstraction + url: PolylineAlgorithm.Abstraction.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: Provides a base implementation for encoding sequences of items into encoded polyline strings. +- code: 'public abstract class AbstractPolylineEncoder : IPolylineEncoder' +- h4: Type Parameters +- parameters: + - name: TCoordinate + description: The type that represents an item to encode. + - name: TPolyline + description: The type that represents the encoded polyline output. +- h4: Inheritance +- inheritance: + - text: object + url: https://learn.microsoft.com/dotnet/api/system.object + - text: AbstractPolylineEncoder + url: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.html +- h4: Implements +- list: + - text: IPolylineEncoder + url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html +- h4: Inherited Members +- list: + - text: object.Equals(object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - text: object.Equals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - text: object.GetHashCode() + url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - text: object.GetType() + url: https://learn.microsoft.com/dotnet/api/system.object.gettype + - text: object.MemberwiseClone() + url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone + - text: object.ReferenceEquals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - text: object.ToString() + url: https://learn.microsoft.com/dotnet/api/system.object.tostring +- h4: Extension Methods +- list: + - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, List) + url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__ + - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, TCoordinate[]) + url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___ +- h2: Remarks +- markdown: >- + Derive from this class to implement an encoder for a specific item and polyline type. Override + + , , and to provide type-specific behavior. +- h2: Constructors +- api3: AbstractPolylineEncoder() + id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L33 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor +- markdown: Initializes a new instance of the class with default encoding options. +- code: protected AbstractPolylineEncoder() +- api3: AbstractPolylineEncoder(PolylineEncodingOptions) + id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L43 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions) +- markdown: Initializes a new instance of the class with the specified encoding options. +- code: protected AbstractPolylineEncoder(PolylineEncodingOptions options) +- h4: Parameters +- parameters: + - name: options + type: + - text: PolylineEncodingOptions + url: PolylineAlgorithm.PolylineEncodingOptions.html + description: The to use for encoding operations. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentNullException + url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception + description: Thrown when options is null +- h2: Properties +- api3: Options + id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Options + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L57 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options + commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options +- markdown: Gets the encoding options used by this polyline encoder. +- code: public PolylineEncodingOptions Options { get; } +- h4: Property Value +- parameters: + - type: + - text: PolylineEncodingOptions + url: PolylineAlgorithm.PolylineEncodingOptions.html +- api3: ValuesPerItem + id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_ValuesPerItem + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L196 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.ValuesPerItem + commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.ValuesPerItem +- markdown: Gets the number of values extracted from each TCoordinate item during encoding. +- code: protected abstract int ValuesPerItem { get; } +- h4: Property Value +- parameters: + - type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 +- h4: Remarks +- markdown: >- + Must be greater than zero. Each value is written as a separate delta-encoded block in the output polyline. + + For a standard geographic coordinate pair (latitude + longitude), return 2. +- h2: Methods +- api3: CreatePolyline(ReadOnlyMemory) + id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_CreatePolyline_System_ReadOnlyMemory_System_Char__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L186 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char}) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char}) +- markdown: Creates a polyline instance from the provided read-only sequence of characters. +- code: protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline) +- h4: Parameters +- parameters: + - name: polyline + type: + - text: ReadOnlyMemory + url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + description: A containing the encoded polyline characters. +- h4: Returns +- parameters: + - type: + - TPolyline + description: An instance of TPolyline representing the encoded polyline. +- api3: Encode(ReadOnlySpan, CancellationToken) + id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L80 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) +- markdown: Encodes a collection of TCoordinate instances into an encoded TPolyline string. +- code: >- + [SuppressMessage("Design", "MA0051:Method is too long", Justification = "Method contains local methods. Actual method only 55 lines.")] + + public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default) +- h4: Parameters +- parameters: + - name: coordinates + type: + - text: ReadOnlySpan + url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 + - < + - TCoordinate + - '>' + description: The collection of TCoordinate objects to encode. + - name: cancellationToken + type: + - text: CancellationToken + url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken + description: A that can be used to cancel the encoding operation. + optional: true +- h4: Returns +- parameters: + - type: + - TPolyline + description: An instance of TPolyline representing the encoded coordinates. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentNullException + url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception + description: Thrown when coordinates is null. + - type: + - text: ArgumentException + url: https://learn.microsoft.com/dotnet/api/system.argumentexception + description: Thrown when coordinates is an empty enumeration. + - type: + - text: InvalidOperationException + url: https://learn.microsoft.com/dotnet/api/system.invalidoperationexception + description: Thrown when the internal encoding buffer cannot accommodate the encoded value. +- api3: GetValues(TCoordinate, Span) + id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetValues__0_System_Span_System_Double__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L205 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetValues(`0,System.Span{System.Double}) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetValues(`0,System.Span{System.Double}) +- markdown: Extracts the encoded values from the specified item into the provided span. +- code: protected abstract void GetValues(TCoordinate item, Span values) +- h4: Parameters +- parameters: + - name: item + type: + - TCoordinate + description: The item from which to extract values. + - name: values + type: + - text: Span + url: https://learn.microsoft.com/dotnet/api/system.span-1 + - < + - text: double + url: https://learn.microsoft.com/dotnet/api/system.double + - '>' + description: A span that receives the extracted values. Its length equals . +languageId: csharp +metadata: + description: Provides a base implementation for encoding sequences of items into encoded polyline strings. diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml new file mode 100644 index 00000000..c3a0cc71 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml @@ -0,0 +1,90 @@ +### YamlMime:ApiPage +title: Interface IPolylineDecoder +body: +- api1: Interface IPolylineDecoder + id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L22 + metadata: + uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2 + commentId: T:PolylineAlgorithm.Abstraction.IPolylineDecoder`2 +- facts: + - name: Namespace + value: + text: PolylineAlgorithm.Abstraction + url: PolylineAlgorithm.Abstraction.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates. +- code: public interface IPolylineDecoder +- h4: Type Parameters +- parameters: + - name: TPolyline + description: >- + The type that represents the encoded polyline input. Common implementations use , + + but custom wrapper types are allowed to carry additional metadata. + - name: TValue + description: >- + The coordinate type returned by the decoder. Typical implementations return a struct or class that + + contains latitude and longitude (for example a LatLng type or a ValueTuple<double,double>). +- h2: Methods +- api3: Decode(TPolyline, CancellationToken) + id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L48 + metadata: + uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) + commentId: M:PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken) +- markdown: >- + Decodes the specified encoded polyline into an ordered sequence of geographic coordinates. + + The sequence preserves the original vertex order encoded by the polyline. +- code: IEnumerable Decode(TPolyline polyline, CancellationToken cancellationToken = default) +- h4: Parameters +- parameters: + - name: polyline + type: + - TPolyline + description: >- + The TPolyline instance containing the encoded polyline to decode. + + Implementations SHOULD validate the input and may throw + + or for invalid formats. + - name: cancellationToken + type: + - text: CancellationToken + url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken + description: >- + A to observe while decoding. If cancellation is requested, + + implementations SHOULD stop work and throw an . + optional: true +- h4: Returns +- parameters: + - type: + - text: IEnumerable + url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 + - < + - TValue + - '>' + description: >- + An of TValue representing the decoded + + latitude/longitude pairs (or equivalent coordinates) in the same order they were encoded. +- h4: Remarks +- markdown: >- + Implementations commonly follow the Google Encoded Polyline Algorithm Format, but this interface + + does not mandate a specific encoding. Consumers should rely on a concrete decoder's documentation + + to understand the exact encoding supported. +- h4: Exceptions +- parameters: + - type: + - text: OperationCanceledException + url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception + description: Thrown when the provided cancellationToken requests cancellation. +languageId: csharp +metadata: + description: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates. diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml new file mode 100644 index 00000000..952d1a27 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml @@ -0,0 +1,142 @@ +### YamlMime:ApiPage +title: Interface IPolylineEncoder +body: +- api1: Interface IPolylineEncoder + id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L36 + metadata: + uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2 + commentId: T:PolylineAlgorithm.Abstraction.IPolylineEncoder`2 +- facts: + - name: Namespace + value: + text: PolylineAlgorithm.Abstraction + url: PolylineAlgorithm.Abstraction.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: >- + Contract for encoding a sequence of geographic coordinates into an encoded polyline representation. + + Implementations interpret the generic TValue type and produce an encoded + + representation of those coordinates as TPolyline. +- code: public interface IPolylineEncoder +- h4: Type Parameters +- parameters: + - name: TValue + description: >- + The concrete coordinate representation used by the encoder (for example a struct or class containing + + Latitude and Longitude values). Implementations must document the expected shape, + + units (typically decimal degrees), and any required fields for TValue. + + Common shapes: + + - A struct or class with two double properties named Latitude and Longitude. + + - A tuple-like type (for example ValueTuple<double,double>) where the encoder documents + which element represents latitude and longitude. + - name: TPolyline + description: >- + The encoded polyline representation returned by the encoder (for example string, + + ReadOnlyMemory<char>, or a custom wrapper type). Concrete implementations should document + + the chosen representation and any memory / ownership expectations. +- h4: Extension Methods +- list: + - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, List) + url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__ + - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, TValue[]) + url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___ +- h2: Remarks +- markdown: >- + - This interface is intentionally minimal to allow different encoding strategies (Google encoded polyline, + precision/scale variants, or custom compressed formats) to be expressed behind a common contract. + - Implementations should document: + - Coordinate precision and rounding rules (for example 1e-5 for 5-decimal precision). + - Coordinate ordering and whether altitude or additional dimensions are supported. + - Thread-safety guarantees: whether instances are safe to reuse concurrently or must be instantiated per-call. + - Implementations are encouraged to be memory-efficient; the API accepts a + to avoid forced allocations when callers already have contiguous memory. +- h2: Methods +- api3: Encode(ReadOnlySpan, CancellationToken) + id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L76 + metadata: + uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) + commentId: M:PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) +- markdown: >- + Encodes a sequence of geographic coordinates into an encoded polyline representation. + + The order of coordinates in coordinates is preserved in the encoded result. +- code: TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default) +- h4: Parameters +- parameters: + - name: coordinates + type: + - text: ReadOnlySpan + url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 + - < + - TValue + - '>' + description: >- + The collection of TValue instances to encode into a polyline. + + The span may be empty; implementations should return an appropriate empty encoded representation + + (for example an empty string or an empty memory slice) rather than null. + - name: cancellationToken + type: + - text: CancellationToken + url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken + description: >- + A that can be used to cancel the encoding operation. + + Implementations should observe this token and throw + + when cancellation is requested. For fast, in-memory encoders cancellation may be best-effort. + optional: true +- h4: Returns +- parameters: + - type: + - TPolyline + description: >- + A TPolyline containing the encoded polyline that represents the input coordinates. + + The exact format and any delimiting/terminating characters are implementation-specific and must be + + documented by concrete encoder types. +- h4: Examples +- markdown: >- +
// Example pseudocode for typical usage with a string-based encoder:
+
+    var coords = new[] {
+        new Coordinate { Latitude = 47.6219, Longitude = -122.3503 },
+        new Coordinate { Latitude = 47.6220, Longitude = -122.3504 }
+    };
+
+    IPolylineEncoder<Coordinate,string> encoder = new GoogleEncodedPolylineEncoder();
+
+    string encoded = encoder.Encode(coords, CancellationToken.None);
+- h4: Remarks +- markdown: >- + - Implementations should validate input as appropriate and document any preconditions (for example + if coordinates must be within [-90,90] latitude and [-180,180] longitude). + - For large input sequences, implementations may provide streaming or incremental encoders; those + variants can still implement this interface by materializing the final encoded result. +- h4: Exceptions +- parameters: + - type: + - text: OperationCanceledException + url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception + description: Thrown if the operation is canceled via cancellationToken. +languageId: csharp +metadata: + description: >- + Contract for encoding a sequence of geographic coordinates into an encoded polyline representation. + + Implementations interpret the generic TValue type and produce an encoded + + representation of those coordinates as TPolyline. diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.yml new file mode 100644 index 00000000..760e007f --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.yml @@ -0,0 +1,34 @@ +### YamlMime:ApiPage +title: Namespace PolylineAlgorithm.Abstraction +body: +- api1: Namespace PolylineAlgorithm.Abstraction + id: PolylineAlgorithm_Abstraction + metadata: + uid: PolylineAlgorithm.Abstraction + commentId: N:PolylineAlgorithm.Abstraction +- h3: Classes +- parameters: + - type: + text: AbstractPolylineDecoder + url: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.html + description: Provides a base implementation for decoding encoded polyline strings into sequences of items. + - type: + text: AbstractPolylineEncoder + url: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.html + description: Provides a base implementation for encoding sequences of items into encoded polyline strings. +- h3: Interfaces +- parameters: + - type: + text: IPolylineDecoder + url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html + description: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates. + - type: + text: IPolylineEncoder + url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html + description: >- + Contract for encoding a sequence of geographic coordinates into an encoded polyline representation. + + Implementations interpret the generic TValue type and produce an encoded + + representation of those coordinates as TPolyline. +languageId: csharp diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml new file mode 100644 index 00000000..5b6e2da1 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml @@ -0,0 +1,195 @@ +### YamlMime:ApiPage +title: Class PolylineDecoderExtensions +body: +- api1: Class PolylineDecoderExtensions + id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L16 + metadata: + uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions + commentId: T:PolylineAlgorithm.Extensions.PolylineDecoderExtensions +- facts: + - name: Namespace + value: + text: PolylineAlgorithm.Extensions + url: PolylineAlgorithm.Extensions.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: Provides extension methods for the interface to facilitate decoding encoded polylines. +- code: public static class PolylineDecoderExtensions +- h4: Inheritance +- inheritance: + - text: object + url: https://learn.microsoft.com/dotnet/api/system.object + - text: PolylineDecoderExtensions + url: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.html +- h4: Inherited Members +- list: + - text: object.Equals(object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - text: object.Equals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - text: object.GetHashCode() + url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - text: object.GetType() + url: https://learn.microsoft.com/dotnet/api/system.object.gettype + - text: object.MemberwiseClone() + url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone + - text: object.ReferenceEquals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - text: object.ToString() + url: https://learn.microsoft.com/dotnet/api/system.object.tostring +- h2: Methods +- api3: Decode(IPolylineDecoder, char[]) + id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_String___0__System_Char___ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L33 + metadata: + uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.Char[]) + commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.Char[]) +- markdown: Decodes an encoded polyline represented as a character array into a sequence of geographic coordinates. +- code: public static IEnumerable Decode(this IPolylineDecoder decoder, char[] polyline) +- h4: Parameters +- parameters: + - name: decoder + type: + - text: IPolylineDecoder + url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html + - < + - text: string + url: https://learn.microsoft.com/dotnet/api/system.string + - ',' + - " " + - TValue + - '>' + description: The instance used to perform the decoding operation. + - name: polyline + type: + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '[' + - ']' + description: The encoded polyline as a character array to decode. The array is converted to a string internally. +- h4: Returns +- parameters: + - type: + - text: IEnumerable + url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 + - < + - TValue + - '>' + description: An of TValue containing the decoded coordinate pairs. +- h4: Type Parameters +- parameters: + - name: TValue + description: The coordinate type returned by the decoder. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentNullException + url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception + description: Thrown when decoder or polyline is null. +- api3: Decode(IPolylineDecoder, ReadOnlyMemory) + id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_String___0__System_ReadOnlyMemory_System_Char__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L61 + metadata: + uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.ReadOnlyMemory{System.Char}) + commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.ReadOnlyMemory{System.Char}) +- markdown: Decodes an encoded polyline represented as a read-only memory of characters into a sequence of geographic coordinates. +- code: public static IEnumerable Decode(this IPolylineDecoder decoder, ReadOnlyMemory polyline) +- h4: Parameters +- parameters: + - name: decoder + type: + - text: IPolylineDecoder + url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html + - < + - text: string + url: https://learn.microsoft.com/dotnet/api/system.string + - ',' + - " " + - TValue + - '>' + description: The instance used to perform the decoding operation. + - name: polyline + type: + - text: ReadOnlyMemory + url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + description: The encoded polyline as a read-only memory of characters to decode. The memory is converted to a string internally. +- h4: Returns +- parameters: + - type: + - text: IEnumerable + url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 + - < + - TValue + - '>' + description: An of TValue containing the decoded coordinate pairs. +- h4: Type Parameters +- parameters: + - name: TValue + description: The coordinate type returned by the decoder. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentNullException + url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception + description: Thrown when decoder is null. +- api3: Decode(IPolylineDecoder, TValue>, string) + id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_ReadOnlyMemory_System_Char____0__System_String_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L86 + metadata: + uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.ReadOnlyMemory{System.Char},``0},System.String) + commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.ReadOnlyMemory{System.Char},``0},System.String) +- markdown: >- + Decodes an encoded polyline string into a sequence of geographic coordinates, + + using a decoder that accepts of . +- code: public static IEnumerable Decode(this IPolylineDecoder, TValue> decoder, string polyline) +- h4: Parameters +- parameters: + - name: decoder + type: + - text: IPolylineDecoder + url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html + - < + - text: ReadOnlyMemory + url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + - ',' + - " " + - TValue + - '>' + description: The instance used to perform the decoding operation. + - name: polyline + type: + - text: string + url: https://learn.microsoft.com/dotnet/api/system.string + description: The encoded polyline string to decode. The string is converted to internally. +- h4: Returns +- parameters: + - type: + - text: IEnumerable + url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1 + - < + - TValue + - '>' + description: An of TValue containing the decoded coordinate pairs. +- h4: Type Parameters +- parameters: + - name: TValue + description: The coordinate type returned by the decoder. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentNullException + url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception + description: Thrown when decoder or polyline is null. +languageId: csharp +metadata: + description: Provides extension methods for the interface to facilitate decoding encoded polylines. diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml new file mode 100644 index 00000000..bd62ed13 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml @@ -0,0 +1,139 @@ +### YamlMime:ApiPage +title: Class PolylineEncoderExtensions +body: +- api1: Class PolylineEncoderExtensions + id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L19 + metadata: + uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions + commentId: T:PolylineAlgorithm.Extensions.PolylineEncoderExtensions +- facts: + - name: Namespace + value: + text: PolylineAlgorithm.Extensions + url: PolylineAlgorithm.Extensions.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines. +- code: public static class PolylineEncoderExtensions +- h4: Inheritance +- inheritance: + - text: object + url: https://learn.microsoft.com/dotnet/api/system.object + - text: PolylineEncoderExtensions + url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html +- h4: Inherited Members +- list: + - text: object.Equals(object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - text: object.Equals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - text: object.GetHashCode() + url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - text: object.GetType() + url: https://learn.microsoft.com/dotnet/api/system.object.gettype + - text: object.MemberwiseClone() + url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone + - text: object.ReferenceEquals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - text: object.ToString() + url: https://learn.microsoft.com/dotnet/api/system.object.tostring +- h2: Methods +- api3: Encode(IPolylineEncoder, List) + id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L37 + metadata: + uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},System.Collections.Generic.List{``0}) + commentId: M:PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},System.Collections.Generic.List{``0}) +- markdown: Encodes a of TCoordinate instances into an encoded polyline. +- code: >- + [SuppressMessage("Design", "CA1002:Do not expose generic lists", Justification = "We need a list as we do need to marshal it as span.")] + + [SuppressMessage("Design", "MA0016:Prefer using collection abstraction instead of implementation", Justification = "We need a list as we do need to marshal it as span.")] + + public static TPolyline Encode(this IPolylineEncoder encoder, List coordinates) +- h4: Parameters +- parameters: + - name: encoder + type: + - text: IPolylineEncoder + url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html + - < + - TCoordinate + - ',' + - " " + - TPolyline + - '>' + description: The instance used to perform the encoding operation. + - name: coordinates + type: + - text: List + url: https://learn.microsoft.com/dotnet/api/system.collections.generic.list-1 + - < + - TCoordinate + - '>' + description: The list of TCoordinate objects to encode. +- h4: Returns +- parameters: + - type: + - TPolyline + description: A TPolyline instance representing the encoded polyline for the provided coordinates. +- h4: Type Parameters +- parameters: + - name: TCoordinate + description: The type that represents a geographic coordinate to encode. + - name: TPolyline + description: The type that represents the encoded polyline output. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentNullException + url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception + description: Thrown when encoder or coordinates is null. +- api3: Encode(IPolylineEncoder, TCoordinate[]) + id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L73 + metadata: + uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},``0[]) + commentId: M:PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},``0[]) +- markdown: Encodes an array of TCoordinate instances into an encoded polyline. +- code: public static TPolyline Encode(this IPolylineEncoder encoder, TCoordinate[] coordinates) +- h4: Parameters +- parameters: + - name: encoder + type: + - text: IPolylineEncoder + url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html + - < + - TCoordinate + - ',' + - " " + - TPolyline + - '>' + description: The instance used to perform the encoding operation. + - name: coordinates + type: + - TCoordinate + - '[' + - ']' + description: The array of TCoordinate objects to encode. +- h4: Returns +- parameters: + - type: + - TPolyline + description: A TPolyline instance representing the encoded polyline for the provided coordinates. +- h4: Type Parameters +- parameters: + - name: TCoordinate + description: The type that represents a geographic coordinate to encode. + - name: TPolyline + description: The type that represents the encoded polyline output. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentNullException + url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception + description: Thrown when encoder or coordinates is null. +languageId: csharp +metadata: + description: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines. diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.yml new file mode 100644 index 00000000..c39da0ca --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Extensions.yml @@ -0,0 +1,19 @@ +### YamlMime:ApiPage +title: Namespace PolylineAlgorithm.Extensions +body: +- api1: Namespace PolylineAlgorithm.Extensions + id: PolylineAlgorithm_Extensions + metadata: + uid: PolylineAlgorithm.Extensions + commentId: N:PolylineAlgorithm.Extensions +- h3: Classes +- parameters: + - type: + text: PolylineDecoderExtensions + url: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.html + description: Provides extension methods for the interface to facilitate decoding encoded polylines. + - type: + text: PolylineEncoderExtensions + url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html + description: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines. +languageId: csharp diff --git a/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml b/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml new file mode 100644 index 00000000..8f6b6e76 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml @@ -0,0 +1,102 @@ +### YamlMime:ApiPage +title: Class InvalidPolylineException +body: +- api1: Class InvalidPolylineException + id: PolylineAlgorithm_InvalidPolylineException + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/InvalidPolylineException.cs#L17 + metadata: + uid: PolylineAlgorithm.InvalidPolylineException + commentId: T:PolylineAlgorithm.InvalidPolylineException +- facts: + - name: Namespace + value: + text: PolylineAlgorithm + url: PolylineAlgorithm.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: Exception thrown when a polyline is determined to be malformed or invalid during processing. +- code: 'public sealed class InvalidPolylineException : Exception, ISerializable' +- h4: Inheritance +- inheritance: + - text: object + url: https://learn.microsoft.com/dotnet/api/system.object + - text: Exception + url: https://learn.microsoft.com/dotnet/api/system.exception + - text: InvalidPolylineException + url: PolylineAlgorithm.InvalidPolylineException.html +- h4: Implements +- list: + - text: ISerializable + url: https://learn.microsoft.com/dotnet/api/system.runtime.serialization.iserializable +- h4: Inherited Members +- list: + - text: Exception.GetBaseException() + url: https://learn.microsoft.com/dotnet/api/system.exception.getbaseexception + - text: Exception.GetObjectData(SerializationInfo, StreamingContext) + url: https://learn.microsoft.com/dotnet/api/system.exception.getobjectdata + - text: Exception.GetType() + url: https://learn.microsoft.com/dotnet/api/system.exception.gettype + - text: Exception.ToString() + url: https://learn.microsoft.com/dotnet/api/system.exception.tostring + - text: Exception.Data + url: https://learn.microsoft.com/dotnet/api/system.exception.data + - text: Exception.HelpLink + url: https://learn.microsoft.com/dotnet/api/system.exception.helplink + - text: Exception.HResult + url: https://learn.microsoft.com/dotnet/api/system.exception.hresult + - text: Exception.InnerException + url: https://learn.microsoft.com/dotnet/api/system.exception.innerexception + - text: Exception.Message + url: https://learn.microsoft.com/dotnet/api/system.exception.message + - text: Exception.Source + url: https://learn.microsoft.com/dotnet/api/system.exception.source + - text: Exception.StackTrace + url: https://learn.microsoft.com/dotnet/api/system.exception.stacktrace + - text: Exception.TargetSite + url: https://learn.microsoft.com/dotnet/api/system.exception.targetsite + - text: object.Equals(object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - text: object.Equals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - text: object.GetHashCode() + url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - text: object.GetType() + url: https://learn.microsoft.com/dotnet/api/system.object.gettype + - text: object.ReferenceEquals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - text: object.ToString() + url: https://learn.microsoft.com/dotnet/api/system.object.tostring +- h2: Remarks +- markdown: This exception is used internally to indicate that a polyline string does not conform to the expected format or contains errors. +- h2: Constructors +- api3: InvalidPolylineException() + id: PolylineAlgorithm_InvalidPolylineException__ctor + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/InvalidPolylineException.cs#L22 + metadata: + uid: PolylineAlgorithm.InvalidPolylineException.#ctor + commentId: M:PolylineAlgorithm.InvalidPolylineException.#ctor +- markdown: Initializes a new instance of the class. +- code: public InvalidPolylineException() +- api3: InvalidPolylineException(string, Exception) + id: PolylineAlgorithm_InvalidPolylineException__ctor_System_String_System_Exception_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/InvalidPolylineException.cs#L43 + metadata: + uid: PolylineAlgorithm.InvalidPolylineException.#ctor(System.String,System.Exception) + commentId: M:PolylineAlgorithm.InvalidPolylineException.#ctor(System.String,System.Exception) +- markdown: Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception. +- code: public InvalidPolylineException(string message, Exception innerException) +- h4: Parameters +- parameters: + - name: message + type: + - text: string + url: https://learn.microsoft.com/dotnet/api/system.string + description: The error message that explains the reason for the exception. + - name: innerException + type: + - text: Exception + url: https://learn.microsoft.com/dotnet/api/system.exception + description: The exception that is the cause of the current exception, or a null reference if no inner exception is specified. +languageId: csharp +metadata: + description: Exception thrown when a polyline is determined to be malformed or invalid during processing. diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml new file mode 100644 index 00000000..56818e4c --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml @@ -0,0 +1,529 @@ +### YamlMime:ApiPage +title: Class PolylineEncoding +body: +- api1: Class PolylineEncoding + id: PolylineAlgorithm_PolylineEncoding + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L23 + metadata: + uid: PolylineAlgorithm.PolylineEncoding + commentId: T:PolylineAlgorithm.PolylineEncoding +- facts: + - name: Namespace + value: + text: PolylineAlgorithm + url: PolylineAlgorithm.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: >- + Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing + + geographic coordinate values. +- code: public static class PolylineEncoding +- h4: Inheritance +- inheritance: + - text: object + url: https://learn.microsoft.com/dotnet/api/system.object + - text: PolylineEncoding + url: PolylineAlgorithm.PolylineEncoding.html +- h4: Inherited Members +- list: + - text: object.Equals(object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - text: object.Equals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - text: object.GetHashCode() + url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - text: object.GetType() + url: https://learn.microsoft.com/dotnet/api/system.object.gettype + - text: object.MemberwiseClone() + url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone + - text: object.ReferenceEquals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - text: object.ToString() + url: https://learn.microsoft.com/dotnet/api/system.object.tostring +- h2: Remarks +- markdown: >- + The class includes functionality for working with encoded polyline + data, such as reading and writing encoded values, as well as methods for normalizing and de-normalizing geographic + coordinates. It also provides validation utilities to ensure values conform to expected ranges for latitude and + longitude. +- h2: Methods +- api3: Denormalize(int, uint) + id: PolylineAlgorithm_PolylineEncoding_Denormalize_System_Int32_System_UInt32_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L122 + metadata: + uid: PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32) + commentId: M:PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32) +- markdown: Converts a normalized integer coordinate value back to its floating-point representation based on the specified precision. +- code: public static double Denormalize(int value, uint precision = 5) +- h4: Parameters +- parameters: + - name: value + type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + description: The integer value to denormalize. Typically produced by the method. + - name: precision + type: + - text: uint + url: https://learn.microsoft.com/dotnet/api/system.uint32 + description: The number of decimal places used during normalization. Default is 5, matching standard polyline encoding precision. + optional: true +- h4: Returns +- parameters: + - type: + - text: double + url: https://learn.microsoft.com/dotnet/api/system.double + description: The denormalized floating-point coordinate value. +- h4: Remarks +- markdown: >- +

+ + This method reverses the normalization performed by . It takes an integer value and converts it + + to a double by dividing it by 10 raised to the power of the specified precision. If precision is 0, + + the value is returned as a double without division. + +

+ +

+ + The calculation is performed inside a checked block to ensure that any arithmetic overflow is detected + + and an is thrown. + +

+ +

+ + For example, with a precision of 5: + + +

  • A value of 3778903 becomes 37.78903
  • A value of -12241230 becomes -122.4123
+ +

+ +

+ + If the input value is 0, the method returns 0.0 immediately. + +

+- h4: Exceptions +- parameters: + - type: + - text: OverflowException + url: https://learn.microsoft.com/dotnet/api/system.overflowexception + description: Thrown if the arithmetic operation overflows during conversion. +- api3: GetRequiredBufferSize(int) + id: PolylineAlgorithm_PolylineEncoding_GetRequiredBufferSize_System_Int32_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L298 + metadata: + uid: PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32) + commentId: M:PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32) +- markdown: Calculates the number of characters required to encode a delta value in polyline format. +- code: public static int GetRequiredBufferSize(int delta) +- h4: Parameters +- parameters: + - name: delta + type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + description: >- + The integer delta value to calculate the encoded size for. This value typically represents the difference between + + consecutive coordinate values in polyline encoding. +- h4: Returns +- parameters: + - type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + description: The number of characters required to encode the specified delta value. The minimum return value is 1. +- h4: Remarks +- markdown: >- +

+ + This method determines how many characters will be needed to represent an integer delta value when encoded + + using the polyline encoding algorithm. It performs the same zigzag encoding transformation as + + but only calculates the required buffer size without actually writing any data. + +

+ +

+ + The calculation process: + + +

  1. Applies zigzag encoding: left-shifts the value by 1 bit, then inverts all bits if the original value was negative
  2. Counts how many 5-bit chunks are needed to represent the encoded value
  3. Each chunk requires one character, with a minimum of 1 character for any value
+ +

+ +

+ + This method is useful for pre-allocating buffers of the correct size before encoding polyline data, helping to avoid + + buffer overflow checks during the actual encoding process. + +

+ +

+ + The method uses a long internally to prevent overflow during the left-shift operation on large negative values. + +

+- h4: See Also +- list: + - - text: PolylineEncoding + url: PolylineAlgorithm.PolylineEncoding.html + - . + - text: TryWriteValue + url: PolylineAlgorithm.PolylineEncoding.html#PolylineAlgorithm_PolylineEncoding_TryWriteValue_System_Int32_System_Span_System_Char__System_Int32__ + - ( + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + - ',' + - " " + - text: Span + url: https://learn.microsoft.com/dotnet/api/system.span-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + - ',' + - " " + - ref + - " " + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + - ) +- api3: Normalize(double, uint) + id: PolylineAlgorithm_PolylineEncoding_Normalize_System_Double_System_UInt32_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L61 + metadata: + uid: PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32) + commentId: M:PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32) +- markdown: Normalizes a geographic coordinate value to an integer representation based on the specified precision. +- code: public static int Normalize(double value, uint precision = 5) +- h4: Parameters +- parameters: + - name: value + type: + - text: double + url: https://learn.microsoft.com/dotnet/api/system.double + description: The numeric value to normalize. Must be a finite number (not NaN or infinity). + - name: precision + type: + - text: uint + url: https://learn.microsoft.com/dotnet/api/system.uint32 + description: >- + The number of decimal places of precision to preserve in the normalized value. + + The value is multiplied by 10^precision before rounding. + + Default is 5, which is standard for polyline encoding. + optional: true +- h4: Returns +- parameters: + - type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + description: An integer representing the normalized value. Returns 0 if the input value is 0.0. +- h4: Remarks +- markdown: >- +

+ + This method converts a floating-point coordinate value into a normalized integer by multiplying it by 10 raised + + to the power of the specified precision, then truncating the result to an integer. + +

+ +

+ + For example, with the default precision of 5: + + +

  • A value of 37.78903 becomes 3778903
  • A value of -122.4123 becomes -12241230
+ +

+ +

+ + The method validates that the input value is finite (not NaN or infinity) before performing normalization. + + If the precision is 0, the value is rounded without multiplication. + +

+- h4: Exceptions +- parameters: + - type: + - text: ArgumentOutOfRangeException + url: https://learn.microsoft.com/dotnet/api/system.argumentoutofrangeexception + description: Thrown when value is not a finite number (NaN or infinity). + - type: + - text: OverflowException + url: https://learn.microsoft.com/dotnet/api/system.overflowexception + description: Thrown when the normalized result exceeds the range of a 32-bit signed integer during the conversion from double to int. +- api3: TryReadValue(ref int, ReadOnlyMemory, ref int) + id: PolylineAlgorithm_PolylineEncoding_TryReadValue_System_Int32__System_ReadOnlyMemory_System_Char__System_Int32__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L169 + metadata: + uid: PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@) + commentId: M:PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@) +- markdown: Attempts to read an encoded integer value from a polyline buffer, updating the specified delta and position. +- code: public static bool TryReadValue(ref int delta, ReadOnlyMemory buffer, ref int position) +- h4: Parameters +- parameters: + - name: delta + type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + description: Reference to the integer accumulator that will be updated with the decoded value. + - name: buffer + type: + - text: ReadOnlyMemory + url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + description: The buffer containing polyline-encoded characters. + - name: position + type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + description: Reference to the current position in the buffer. This value is updated as characters are read. +- h4: Returns +- parameters: + - type: + - text: bool + url: https://learn.microsoft.com/dotnet/api/system.boolean + description: true if a value was successfully read and decoded; false if the buffer ended before a complete value was read. +- h4: Remarks +- markdown: >- +

+ + This method decodes a value from a polyline-encoded character buffer, starting at the given position. It reads + + characters sequentially, applying the polyline decoding algorithm, and updates the delta with + + the decoded value. The position is advanced as characters are processed. + +

+ +

+ + The decoding process continues until a character with a value less than the algorithm's space constant is encountered, + + which signals the end of the encoded value. If the buffer is exhausted before a complete value is read, the method returns false. + +

+ +

+ + The decoded value is added to delta using zigzag decoding, which handles both positive and negative values. + +

+- api3: TryWriteValue(int, Span, ref int) + id: PolylineAlgorithm_PolylineEncoding_TryWriteValue_System_Int32_System_Span_System_Char__System_Int32__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L237 + metadata: + uid: PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@) + commentId: M:PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@) +- markdown: Attempts to write an encoded integer value to a polyline buffer, updating the specified position. +- code: public static bool TryWriteValue(int delta, Span buffer, ref int position) +- h4: Parameters +- parameters: + - name: delta + type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + description: >- + The integer value to encode and write to the buffer. This value typically represents the difference between consecutive + + coordinate values in polyline encoding. + - name: buffer + type: + - text: Span + url: https://learn.microsoft.com/dotnet/api/system.span-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + description: The destination buffer where the encoded characters will be written. Must have sufficient capacity to hold the encoded value. + - name: position + type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + description: >- + Reference to the current position in the buffer. This value is updated as characters are written to reflect the new position + + after encoding is complete. +- h4: Returns +- parameters: + - type: + - text: bool + url: https://learn.microsoft.com/dotnet/api/system.boolean + description: >- + true if the value was successfully encoded and written to the buffer; false if the buffer + + does not have sufficient remaining capacity to hold the encoded value. +- h4: Remarks +- markdown: >- +

+ + This method encodes an integer delta value into a polyline-encoded format and writes it to the provided character buffer, + + starting at the given position. It applies zigzag encoding followed by the polyline encoding algorithm to represent + + both positive and negative values efficiently. + +

+ +

+ + The encoding process first converts the value using zigzag encoding (left shift by 1, with bitwise inversion for negative values), + + then writes it as a sequence of characters. Each character encodes 5 bits of data, with continuation bits indicating whether + + more characters follow. The position is advanced as characters are written. + +

+ +

+ + Before writing, the method validates that sufficient space is available in the buffer by calling . + + If the buffer does not have enough remaining capacity, the method returns false without modifying the buffer or position. + +

+ +

+ + This method is the inverse of and can be used to encode coordinate deltas for polyline serialization. + +

+- api3: ValidateBlockLength(ReadOnlySpan) + id: PolylineAlgorithm_PolylineEncoding_ValidateBlockLength_System_ReadOnlySpan_System_Char__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L438 + metadata: + uid: PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char}) + commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char}) +- markdown: Validates the block structure of a polyline segment, ensuring each encoded value does not exceed 7 characters and the polyline ends correctly. +- code: public static void ValidateBlockLength(ReadOnlySpan polyline) +- h4: Parameters +- parameters: + - name: polyline + type: + - text: ReadOnlySpan + url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + description: A span representing the polyline segment to validate. +- h4: Remarks +- markdown: >- +

+ + Iterates through the polyline, counting the length of each block (a sequence of characters representing an encoded value). + + Throws an if any block exceeds 7 characters or if the polyline does not end with a valid block terminator. + +

+- h4: Exceptions +- parameters: + - type: + - text: ArgumentException + url: https://learn.microsoft.com/dotnet/api/system.argumentexception + description: Thrown when a block exceeds 7 characters or the polyline does not end with a valid block terminator. +- api3: ValidateCharRange(ReadOnlySpan) + id: PolylineAlgorithm_PolylineEncoding_ValidateCharRange_System_ReadOnlySpan_System_Char__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L392 + metadata: + uid: PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char}) + commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char}) +- markdown: Validates that all characters in the polyline segment are within the allowed ASCII range for polyline encoding. +- code: public static void ValidateCharRange(ReadOnlySpan polyline) +- h4: Parameters +- parameters: + - name: polyline + type: + - text: ReadOnlySpan + url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + description: A span representing the polyline segment to validate. +- h4: Remarks +- markdown: >- +

+ + Uses SIMD vectorization for efficient validation of large spans. Falls back to scalar checks for any block where an invalid character is detected. + +

+ +

+ + The valid range is from '?' (63) to '_' (95), inclusive. If an invalid character is found, an is thrown. + +

+- h4: Exceptions +- parameters: + - type: + - text: ArgumentException + url: https://learn.microsoft.com/dotnet/api/system.argumentexception + description: Thrown when an invalid character is found in the polyline segment. +- api3: ValidateFormat(ReadOnlySpan) + id: PolylineAlgorithm_PolylineEncoding_ValidateFormat_System_ReadOnlySpan_System_Char__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L370 + metadata: + uid: PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char}) + commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char}) +- markdown: Validates the format of a polyline segment, ensuring all characters are valid and block structure is correct. +- code: public static void ValidateFormat(ReadOnlySpan polyline) +- h4: Parameters +- parameters: + - name: polyline + type: + - text: ReadOnlySpan + url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 + - < + - text: char + url: https://learn.microsoft.com/dotnet/api/system.char + - '>' + description: A span representing the polyline segment to validate. +- h4: Remarks +- markdown: >- +

+ + This method performs two levels of validation on the provided polyline segment: + +

+ +
  1. + Character Range Validation: Checks that every character in the polyline is within the valid ASCII range for polyline encoding ('?' [63] to '_' [95], inclusive). + Uses SIMD acceleration for efficient validation of large segments. +
  2. + Block Structure Validation: Ensures that each encoded value (block) does not exceed 7 characters and that the polyline ends with a valid block terminator. +
+

+ + If an invalid character or block structure is detected, an is thrown with details about the error. + +

+- h4: Exceptions +- parameters: + - type: + - text: ArgumentException + url: https://learn.microsoft.com/dotnet/api/system.argumentexception + description: Thrown when an invalid character is found or the block structure is invalid. +languageId: csharp +metadata: + description: >- + Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing + + geographic coordinate values. diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml new file mode 100644 index 00000000..90dc279b --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml @@ -0,0 +1,127 @@ +### YamlMime:ApiPage +title: Class PolylineEncodingOptions +body: +- api1: Class PolylineEncodingOptions + id: PolylineAlgorithm_PolylineEncodingOptions + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L29 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptions + commentId: T:PolylineAlgorithm.PolylineEncodingOptions +- facts: + - name: Namespace + value: + text: PolylineAlgorithm + url: PolylineAlgorithm.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: Provides configuration options for polyline encoding operations. +- code: public sealed class PolylineEncodingOptions +- h4: Inheritance +- inheritance: + - text: object + url: https://learn.microsoft.com/dotnet/api/system.object + - text: PolylineEncodingOptions + url: PolylineAlgorithm.PolylineEncodingOptions.html +- h4: Inherited Members +- list: + - text: object.Equals(object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - text: object.Equals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - text: object.GetHashCode() + url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - text: object.GetType() + url: https://learn.microsoft.com/dotnet/api/system.object.gettype + - text: object.ReferenceEquals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - text: object.ToString() + url: https://learn.microsoft.com/dotnet/api/system.object.tostring +- h2: Remarks +- markdown: >- +

+ + This class allows you to configure various aspects of polyline encoding, including: + +

+ +
  • The level for coordinate encoding
  • The for memory allocation strategy
  • The for diagnostic logging
+ +

+ + All properties have internal setters and should be configured through a builder or factory pattern. + +

+- h2: Properties +- api3: LoggerFactory + id: PolylineAlgorithm_PolylineEncodingOptions_LoggerFactory + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L41 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory + commentId: P:PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory +- markdown: Gets the logger factory used for diagnostic logging during encoding operations. +- code: public ILoggerFactory LoggerFactory { get; } +- h4: Property Value +- parameters: + - type: + - text: ILoggerFactory + url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggerfactory +- h4: Remarks +- markdown: >- + The default logger factory is , which does not log any messages. + + To enable logging, provide a custom implementation. +- api3: Precision + id: PolylineAlgorithm_PolylineEncodingOptions_Precision + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L60 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptions.Precision + commentId: P:PolylineAlgorithm.PolylineEncodingOptions.Precision +- markdown: Gets the precision level used for encoding coordinate values. +- code: public uint Precision { get; } +- h4: Property Value +- parameters: + - type: + - text: uint + url: https://learn.microsoft.com/dotnet/api/system.uint32 +- h4: Remarks +- markdown: >- +

+ + The precision determines the number of decimal places to which each coordinate value (latitude or longitude) + + is multiplied and truncated (not rounded) before encoding. For example, a precision of 5 means each coordinate is multiplied by 10^5 + + and truncated to an integer before encoding. + +

+ +

+ + This setting does not directly correspond to a physical distance or accuracy in meters, but rather controls + + the granularity of the encoded values. + +

+- api3: StackAllocLimit + id: PolylineAlgorithm_PolylineEncodingOptions_StackAllocLimit + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L73 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit + commentId: P:PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit +- markdown: Gets the maximum buffer size (in characters) that can be allocated on the stack for encoding operations. +- code: public int StackAllocLimit { get; } +- h4: Property Value +- parameters: + - type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 +- h4: Remarks +- markdown: >- + When the required buffer size for encoding exceeds this limit, memory will be allocated on the heap instead of the stack. + + This setting specifically applies to stack allocation of character arrays (stackalloc char[]) used during polyline encoding, + + balancing performance and stack safety. +languageId: csharp +metadata: + description: Provides configuration options for polyline encoding operations. diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml new file mode 100644 index 00000000..2c959bdb --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml @@ -0,0 +1,141 @@ +### YamlMime:ApiPage +title: Class PolylineEncodingOptionsBuilder +body: +- api1: Class PolylineEncodingOptionsBuilder + id: PolylineAlgorithm_PolylineEncodingOptionsBuilder + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L15 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder + commentId: T:PolylineAlgorithm.PolylineEncodingOptionsBuilder +- facts: + - name: Namespace + value: + text: PolylineAlgorithm + url: PolylineAlgorithm.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: Provides a builder for configuring options for polyline encoding operations. +- code: public sealed class PolylineEncodingOptionsBuilder +- h4: Inheritance +- inheritance: + - text: object + url: https://learn.microsoft.com/dotnet/api/system.object + - text: PolylineEncodingOptionsBuilder + url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html +- h4: Inherited Members +- list: + - text: object.Equals(object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - text: object.Equals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - text: object.GetHashCode() + url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - text: object.GetType() + url: https://learn.microsoft.com/dotnet/api/system.object.gettype + - text: object.ReferenceEquals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - text: object.ToString() + url: https://learn.microsoft.com/dotnet/api/system.object.tostring +- h2: Methods +- api3: Build() + id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Build + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L38 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build + commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build +- markdown: Builds a new instance using the configured options. +- code: public PolylineEncodingOptions Build() +- h4: Returns +- parameters: + - type: + - text: PolylineEncodingOptions + url: PolylineAlgorithm.PolylineEncodingOptions.html + description: A configured instance. +- api3: Create() + id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Create + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L28 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create + commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create +- markdown: Creates a new instance for the specified coordinate type. +- code: public static PolylineEncodingOptionsBuilder Create() +- h4: Returns +- parameters: + - type: + - text: PolylineEncodingOptionsBuilder + url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html + description: An instance for configuring polyline encoding options. +- api3: WithLoggerFactory(ILoggerFactory) + id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithLoggerFactory_Microsoft_Extensions_Logging_ILoggerFactory_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L97 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory) + commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory) +- markdown: Configures the to be used for logging during polyline encoding operations. +- code: public PolylineEncodingOptionsBuilder WithLoggerFactory(ILoggerFactory loggerFactory) +- h4: Parameters +- parameters: + - name: loggerFactory + type: + - text: ILoggerFactory + url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggerfactory + description: The instance to use for logging. If null, a will be used instead. +- h4: Returns +- parameters: + - type: + - text: PolylineEncodingOptionsBuilder + url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html + description: The current instance for method chaining. +- api3: WithPrecision(uint) + id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithPrecision_System_UInt32_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L82 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32) + commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32) +- markdown: Sets the coordinate encoding precision. +- code: public PolylineEncodingOptionsBuilder WithPrecision(uint precision) +- h4: Parameters +- parameters: + - name: precision + type: + - text: uint + url: https://learn.microsoft.com/dotnet/api/system.uint32 + description: The number of decimal places to use for encoding coordinate values. Default is 5. +- h4: Returns +- parameters: + - type: + - text: PolylineEncodingOptionsBuilder + url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html + description: The current instance for method chaining. +- api3: WithStackAllocLimit(int) + id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithStackAllocLimit_System_Int32_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L61 + metadata: + uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32) + commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32) +- markdown: Configures the buffer size used for stack allocation during polyline encoding operations. +- code: public PolylineEncodingOptionsBuilder WithStackAllocLimit(int stackAllocLimit) +- h4: Parameters +- parameters: + - name: stackAllocLimit + type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 + description: The maximum buffer size to use for stack allocation. Must be greater than or equal to 1. +- h4: Returns +- parameters: + - type: + - text: PolylineEncodingOptionsBuilder + url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html + description: The current instance for method chaining. +- h4: Remarks +- markdown: This method allows customization of the internal buffer size for encoding, which can impact performance and memory usage. +- h4: Exceptions +- parameters: + - type: + - text: ArgumentOutOfRangeException + url: https://learn.microsoft.com/dotnet/api/system.argumentoutofrangeexception + description: Thrown if stackAllocLimit is less than 1. +languageId: csharp +metadata: + description: Provides a builder for configuring options for polyline encoding operations. diff --git a/api-reference/0.0/PolylineAlgorithm.yml b/api-reference/0.0/PolylineAlgorithm.yml new file mode 100644 index 00000000..b60dc3c0 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.yml @@ -0,0 +1,38 @@ +### YamlMime:ApiPage +title: Namespace PolylineAlgorithm +body: +- api1: Namespace PolylineAlgorithm + id: PolylineAlgorithm + metadata: + uid: PolylineAlgorithm + commentId: N:PolylineAlgorithm +- h3: Namespaces +- parameters: + - type: + text: PolylineAlgorithm.Abstraction + url: PolylineAlgorithm.Abstraction.html + - type: + text: PolylineAlgorithm.Extensions + url: PolylineAlgorithm.Extensions.html +- h3: Classes +- parameters: + - type: + text: InvalidPolylineException + url: PolylineAlgorithm.InvalidPolylineException.html + description: Exception thrown when a polyline is determined to be malformed or invalid during processing. + - type: + text: PolylineEncoding + url: PolylineAlgorithm.PolylineEncoding.html + description: >- + Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing + + geographic coordinate values. + - type: + text: PolylineEncodingOptions + url: PolylineAlgorithm.PolylineEncodingOptions.html + description: Provides configuration options for polyline encoding operations. + - type: + text: PolylineEncodingOptionsBuilder + url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html + description: Provides a builder for configuring options for polyline encoding operations. +languageId: csharp diff --git a/api-reference/0.0/toc.yml b/api-reference/0.0/toc.yml new file mode 100644 index 00000000..d1ffc58a --- /dev/null +++ b/api-reference/0.0/toc.yml @@ -0,0 +1,34 @@ +### YamlMime:TableOfContent +- name: PolylineAlgorithm + href: PolylineAlgorithm.yml + items: + - name: Classes + - name: InvalidPolylineException + href: PolylineAlgorithm.InvalidPolylineException.yml + - name: PolylineEncoding + href: PolylineAlgorithm.PolylineEncoding.yml + - name: PolylineEncodingOptions + href: PolylineAlgorithm.PolylineEncodingOptions.yml + - name: PolylineEncodingOptionsBuilder + href: PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml +- name: PolylineAlgorithm.Abstraction + href: PolylineAlgorithm.Abstraction.yml + items: + - name: Classes + - name: AbstractPolylineDecoder + href: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml + - name: AbstractPolylineEncoder + href: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml + - name: Interfaces + - name: IPolylineDecoder + href: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml + - name: IPolylineEncoder + href: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml +- name: PolylineAlgorithm.Extensions + href: PolylineAlgorithm.Extensions.yml + items: + - name: Classes + - name: PolylineDecoderExtensions + href: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml + - name: PolylineEncoderExtensions + href: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml From 645e52171a64d73dda6db46a8c57750c39b0060b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 00:44:32 +0000 Subject: [PATCH 13/24] feat: replace ValuesPerItem/GetValues/CreateItem with IPolylineWriter/IPolylineReader formatter pattern Agent-Logs-Url: https://github.com/petesramek/polyline-algorithm-csharp/sessions/42c3a29e-9300-4811-94c3-19414ab1fb5d Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com> --- .../PolylineDecoderBenchmark.cs | 24 +-- .../PolylineEncoderBenchmark.cs | 7 +- .../NetTopologyPolylineDecoder.cs | 18 +- .../NetTopologyPolylineEncoder.cs | 17 +- .../Abstraction/AbstractPolylineDecoder.cs | 62 ++----- .../Abstraction/AbstractPolylineEncoder.cs | 103 +++-------- .../Abstraction/IPolylineReader.cs | 39 ++++ .../Abstraction/IPolylineWriter.cs | 37 ++++ .../Internal/CoordinateDelta.cs | 85 --------- .../Internal/PolylineReader.cs | 78 ++++++++ .../Internal/PolylineWriter.cs | 94 ++++++++++ src/PolylineAlgorithm/PublicAPI.Unshipped.txt | 21 +++ src/PolylineAlgorithm/README.md | 15 +- .../AbstractPolylineDecoderTests.cs | 14 +- .../AbstractPolylineEncoderTests.cs | 7 +- .../PolylineDecoderExtensionsTests.cs | 14 +- .../PolylineEncoderExtensionsTests.cs | 7 +- .../Internal/CoordinateDeltaTests.cs | 173 ------------------ .../RandomValueProvider.cs | 8 +- 19 files changed, 357 insertions(+), 466 deletions(-) create mode 100644 src/PolylineAlgorithm/Abstraction/IPolylineReader.cs create mode 100644 src/PolylineAlgorithm/Abstraction/IPolylineWriter.cs delete mode 100644 src/PolylineAlgorithm/Internal/CoordinateDelta.cs create mode 100644 src/PolylineAlgorithm/Internal/PolylineReader.cs create mode 100644 src/PolylineAlgorithm/Internal/PolylineWriter.cs delete mode 100644 tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs index 0cfec808..9425eba8 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs @@ -93,41 +93,29 @@ public void PolylineDecoder_Decode_Memory() { } private sealed class StringPolylineDecoder : AbstractPolylineDecoder { - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); - } + protected override (double Latitude, double Longitude) Read(IPolylineReader reader) => + (reader.Read(), reader.Read()); protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { return polyline?.AsMemory() ?? Memory.Empty; } - - protected override int ValuesPerItem => 2; } private sealed class CharArrayPolylineDecoder : AbstractPolylineDecoder { - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); - } + protected override (double Latitude, double Longitude) Read(IPolylineReader reader) => + (reader.Read(), reader.Read()); protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) { return polyline?.AsMemory() ?? Memory.Empty; } - - protected override int ValuesPerItem => 2; } private sealed class MemoryCharPolylineDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); - } + protected override (double Latitude, double Longitude) Read(IPolylineReader reader) => + (reader.Read(), reader.Read()); protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) { return polyline; } - - protected override int ValuesPerItem => 2; } } \ No newline at end of file diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs index bc428c1b..a662d887 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs @@ -86,10 +86,9 @@ public void PolylineEncoder_Encode_List() { private sealed class StringPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override int ValuesPerItem => 2; - protected override void GetValues((double Latitude, double Longitude) item, Span values) { - values[0] = item.Latitude; - values[1] = item.Longitude; + protected override void Write((double Latitude, double Longitude) item, IPolylineWriter writer) { + writer.Write(item.Latitude); + writer.Write(item.Longitude); } } } diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs index 769da445..d37ccc0f 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs @@ -23,19 +23,15 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { } /// - /// Gets the number of values per point (latitude + longitude = 2). + /// Creates a NetTopologySuite Point from decoded field values. /// - protected override int ValuesPerItem => 2; - - /// - /// Creates a NetTopologySuite Point from decoded values. - /// - /// Decoded values: values[0] = latitude, values[1] = longitude. + /// The reader provided by the engine. Field 0 = latitude, field 1 = longitude. /// Point instance. - protected override Point CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; + protected override Point Read(IPolylineReader reader) { + double latitude = reader.Read(); + double longitude = reader.Read(); - // NetTopologySuite Point: x = longitude (values[1]), y = latitude (values[0]) - return new Point(span[1], span[0]); + // NetTopologySuite Point: x = longitude, y = latitude + return new Point(longitude, latitude); } } \ No newline at end of file diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs index afdac4ed..ff97f7e3 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs @@ -27,20 +27,15 @@ protected override string CreatePolyline(ReadOnlyMemory polyline) { } /// - /// Gets the number of values per point (latitude + longitude = 2). + /// Writes latitude and longitude from a NetTopologySuite Point into the polyline encoding pipeline. /// - protected override int ValuesPerItem => 2; - - /// - /// Extracts latitude and longitude from a NetTopologySuite Point into the provided span. - /// - /// The point to extract values from. - /// The span to receive the values: values[0] = latitude (Y), values[1] = longitude (X). - protected override void GetValues(Point item, Span values) { + /// The point to write. Field 0 = latitude (Y), field 1 = longitude (X). + /// The writer provided by the engine. + protected override void Write(Point item, IPolylineWriter writer) { ArgumentNullException.ThrowIfNull(item); // NetTopologySuite Point: Y = latitude, X = longitude - values[0] = item.Y; - values[1] = item.X; + writer.Write(item.Y); + writer.Write(item.X); } } \ No newline at end of file diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs index 39f587ec..bd302d2d 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs @@ -14,8 +14,8 @@ namespace PolylineAlgorithm.Abstraction; /// Provides a base implementation for decoding encoded polyline strings into sequences of items. ///
/// -/// Derive from this class to implement a decoder for a specific polyline type. Override , -/// , and to provide type-specific behavior. +/// Derive from this class to implement a decoder for a specific polyline type. Override +/// and to provide type-specific behavior. /// /// The type that represents the encoded polyline input. /// The type that represents a decoded item. @@ -90,37 +90,18 @@ public IEnumerable Decode(TPolyline polyline, CancellationToken can ValidateSequence(sequence, _logger); ValidateFormat(sequence, _logger); - int valuesPerItem = ValuesPerItem; - int[] accumulated = new int[valuesPerItem]; - double[] decodedValues = new double[valuesPerItem]; - int position = 0; + PolylineReader reader = new(sequence, Options.Precision); try { - while (position < sequence.Length) { + while (!reader.IsEmpty) { cancellationToken.ThrowIfCancellationRequested(); - bool allRead = true; - for (int v = 0; v < valuesPerItem; v++) { - if (!PolylineEncoding.TryReadValue(ref accumulated[v], sequence, ref position)) { - allRead = false; - break; - } - } + reader.BeginItem(); + TCoordinate item = Read(reader); - if (!allRead) { - _logger?.LogOperationFailedDebug(OperationName); - _logger?.LogInvalidPolylineWarning(position); + _logger?.LogDecodedItemDebug(reader.SlotIndex, reader.Position); - ExceptionGuard.ThrowInvalidPolylineFormat(position); - } - - for (int v = 0; v < valuesPerItem; v++) { - decodedValues[v] = PolylineEncoding.Denormalize(accumulated[v], Options.Precision); - } - - _logger?.LogDecodedItemDebug(valuesPerItem, position); - - yield return CreateItem(decodedValues.AsMemory()); + yield return item; } } finally { _logger?.LogOperationFinishedDebug(OperationName); @@ -197,24 +178,21 @@ protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? lo protected abstract ReadOnlyMemory GetReadOnlyMemory(in TPolyline polyline); /// - /// Gets the number of values decoded per item from the polyline. - /// - /// - /// Must be greater than zero. Each item in the decoded output is constructed from this many consecutive - /// delta-decoded values. For a standard geographic coordinate pair (latitude + longitude), return 2. - /// - protected abstract int ValuesPerItem { get; } - - /// - /// Creates a instance from the specified decoded values. + /// Reads field values from the polyline decoding pipeline and constructs one item. /// - /// - /// A of containing the decoded values for this item. - /// The length equals . Implementations should copy values out rather than store the memory. + /// + /// The cursor provided by the engine. Call + /// once for each expected field value, in the same order used by the corresponding encoder's + /// override. /// /// - /// A instance representing the decoded item. + /// A instance constructed from the decoded field values. /// + /// + /// Implementations must always call the same number of times, + /// in the same field order, for every item. The number of reads must match the number of writes + /// performed by the corresponding encoder's override. + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract TCoordinate CreateItem(ReadOnlyMemory values); + protected abstract TCoordinate Read(IPolylineReader reader); } diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs index 7763dc5e..6dc035b0 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs @@ -10,7 +10,6 @@ namespace PolylineAlgorithm.Abstraction; using PolylineAlgorithm.Internal; using PolylineAlgorithm.Internal.Diagnostics; using System; -using System.Buffers; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Threading; @@ -20,7 +19,7 @@ namespace PolylineAlgorithm.Abstraction; ///
/// /// Derive from this class to implement an encoder for a specific item and polyline type. Override -/// , , and to provide type-specific behavior. +/// , and to provide type-specific behavior. /// /// The type that represents an item to encode. /// The type that represents the encoded polyline output. @@ -77,7 +76,6 @@ protected AbstractPolylineEncoder(PolylineEncodingOptions options) { /// /// Thrown when the internal encoding buffer cannot accommodate the encoded value. /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "MA0051:Method is too long", Justification = "Method contains local methods. Actual method only 55 lines.")] public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default) { const string OperationName = nameof(Encode); @@ -86,88 +84,37 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken Debug.Assert(coordinates.Length >= 0, "Count must be non-negative."); - ValidateEmptyCoordinates(ref coordinates, _logger); + ValidateEmptyCoordinates(ref coordinates, _logger, OperationName); - int valuesPerItem = ValuesPerItem; + // Initial capacity assumes 2 values per item (typical lat/lon); the writer grows if needed. + int initialCapacity = coordinates.Length * 2 * Defaults.Polyline.Block.Length.Max; + PolylineWriter writer = new(initialCapacity, Options.Precision); - CoordinateDelta delta = new(valuesPerItem); - - int position = 0; - int consumed = 0; - int length = GetMaxBufferLength(coordinates.Length, valuesPerItem); - - char[]? temp = length <= Options.StackAllocLimit - ? null - : ArrayPool.Shared.Rent(length); - - Span buffer = temp is null ? stackalloc char[length] : temp.AsSpan(0, length); - Span doubleValues = stackalloc double[valuesPerItem]; - Span intValues = stackalloc int[valuesPerItem]; - - string encodedResult; + TPolyline result; try { for (var i = 0; i < coordinates.Length; i++) { cancellationToken.ThrowIfCancellationRequested(); - GetValues(coordinates[i], doubleValues); - - for (int v = 0; v < valuesPerItem; v++) { - intValues[v] = PolylineEncoding.Normalize(doubleValues[v], Options.Precision); - } - - delta.Next(intValues); - - bool writeSucceeded = true; - for (int v = 0; v < valuesPerItem; v++) { - if (!PolylineEncoding.TryWriteValue(delta.Deltas[v], buffer, ref position)) { - writeSucceeded = false; - break; - } - } - - if (!writeSucceeded) { - // This shouldn't happen, but if it does, log the error and throw an exception. - _logger - .LogOperationFailedDebug(OperationName); - _logger - .LogCannotWriteValueToBufferWarning(position, consumed); - - ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer(); - } - - consumed++; + writer.BeginItem(); + Write(coordinates[i], writer); } - encodedResult = buffer[..position].ToString(); + result = CreatePolyline(writer.WrittenMemory); } finally { - if (temp is not null) { - ArrayPool.Shared.Return(temp); - } + writer.ReturnBuffer(); } _logger .LogOperationFinishedDebug(OperationName); - return CreatePolyline(encodedResult.AsMemory()); + return result; [MethodImpl(MethodImplOptions.AggressiveInlining)] - static int GetMaxBufferLength(int count, int valuesPerItem) { - Debug.Assert(count > 0, "Count must be greater than zero."); - Debug.Assert(valuesPerItem > 0, "ValuesPerItem must be greater than zero."); - - int requestedBufferLength = count * valuesPerItem * Defaults.Polyline.Block.Length.Max; - - Debug.Assert(requestedBufferLength > 0, "Requested buffer length must be greater than zero."); - - return requestedBufferLength; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - static void ValidateEmptyCoordinates(ref ReadOnlySpan coordinates, ILogger logger) { + static void ValidateEmptyCoordinates(ref ReadOnlySpan coordinates, ILogger logger, string operationName) { if (coordinates.Length < 1) { logger - .LogOperationFailedDebug(OperationName); + .LogOperationFailedDebug(operationName); logger .LogEmptyArgumentWarning(nameof(coordinates)); @@ -187,22 +134,20 @@ static void ValidateEmptyCoordinates(ref ReadOnlySpan coordinates, protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline); /// - /// Gets the number of values extracted from each item during encoding. + /// Writes the field values of the specified item into the polyline encoding pipeline. /// + /// The item whose field values are to be encoded. + /// + /// The cursor provided by the engine. Call + /// once for each field value, in a fixed, consistent order. The engine handles delta computation, + /// zigzag encoding, and output buffering. + /// /// - /// Must be greater than zero. Each value is written as a separate delta-encoded block in the output polyline. - /// For a standard geographic coordinate pair (latitude + longitude), return 2. + /// Implementations must always call the same number of times, + /// in the same field order, for every item. The corresponding override must + /// call the same number of times in the same order. /// - protected abstract int ValuesPerItem { get; } - - /// - /// Extracts the encoded values from the specified item into the provided span. - /// - /// The item from which to extract values. - /// - /// A span that receives the extracted values. Its length equals . - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract void GetValues(TCoordinate item, Span values); + protected abstract void Write(TCoordinate item, IPolylineWriter writer); } diff --git a/src/PolylineAlgorithm/Abstraction/IPolylineReader.cs b/src/PolylineAlgorithm/Abstraction/IPolylineReader.cs new file mode 100644 index 00000000..8cde0f30 --- /dev/null +++ b/src/PolylineAlgorithm/Abstraction/IPolylineReader.cs @@ -0,0 +1,39 @@ +// +// Copyright © Pete Sramek. All rights reserved. +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace PolylineAlgorithm.Abstraction; + +/// +/// Defines a read-only cursor for consuming individual field values from the polyline decoding pipeline. +/// +/// +/// +/// Instances of are created and owned by the decoding engine. Formatter implementations +/// must not create readers directly. +/// +/// +/// During decoding, the engine reverses the ASCII shift, un-zigzags, and accumulates deltas for each +/// encoded chunk. The reader exposes the resulting absolute floating-point values one at a time. +/// Each call to returns the next value and advances the cursor. +/// +/// +/// The reader is shared across all items in the sequence, so the formatter's implementation of +/// must consume exactly as many values per item as the corresponding +/// encoder's formatter writes. +/// +/// +public interface IPolylineReader { + /// + /// Reads and returns the next field value from the polyline decoding pipeline. + /// + /// + /// The next decoded floating-point field value. + /// + /// + /// Thrown when the polyline data is exhausted or malformed before the expected number of fields + /// for the current item has been read. + /// + double Read(); +} diff --git a/src/PolylineAlgorithm/Abstraction/IPolylineWriter.cs b/src/PolylineAlgorithm/Abstraction/IPolylineWriter.cs new file mode 100644 index 00000000..a6eaaa5c --- /dev/null +++ b/src/PolylineAlgorithm/Abstraction/IPolylineWriter.cs @@ -0,0 +1,37 @@ +// +// Copyright © Pete Sramek. All rights reserved. +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace PolylineAlgorithm.Abstraction; + +/// +/// Defines a write-only cursor for emitting individual field values into the polyline encoding pipeline. +/// +/// +/// +/// Instances of are created and owned by the encoding engine. Formatter implementations +/// must not create writers directly. +/// +/// +/// During encoding, the engine creates one writer per encoding session and calls +/// once for every field of every item, in the order determined by the formatter. +/// Delta accumulation, zigzag encoding, and ASCII shifting are performed internally; the formatter +/// only sees raw floating-point field values. +/// +/// +/// The writer is shared across all items in the sequence so that delta state carries correctly +/// across item boundaries. +/// +/// +public interface IPolylineWriter { + /// + /// Emits one field value into the polyline encoding pipeline. + /// + /// + /// The field value to emit. The engine normalises the value, computes the delta against the + /// same-position field of the previous item, applies zigzag encoding, and writes the result + /// to the output buffer. + /// + void Write(double value); +} diff --git a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs deleted file mode 100644 index e86bbe77..00000000 --- a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs +++ /dev/null @@ -1,85 +0,0 @@ -// -// Copyright © Pete Sramek. All rights reserved. -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace PolylineAlgorithm.Internal; - -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Text; - -/// -/// Represents the differences (deltas) between consecutive sets of N encoded values. -/// -/// -/// This struct computes and stores the change in coordinate values as integer deltas between successive items. -/// The number of values per item is fixed at construction time. -/// -[DebuggerDisplay("{ToString(),nq}")] -[StructLayout(LayoutKind.Auto)] -internal struct CoordinateDelta { - private readonly int[] _current; - private readonly int[] _deltas; - - /// - /// Initializes a new instance of the struct for items with the specified number of values. - /// - /// The number of values per item. Must be greater than zero. - public CoordinateDelta(int count) { - Debug.Assert(count > 0, "Count must be greater than zero."); - - _current = new int[count]; - _deltas = new int[count]; - } - - /// - /// Gets the current delta values between the most recent and previous item. - /// - public ReadOnlySpan Deltas => _deltas; - - /// - /// Updates the delta values based on the next set of encoded values, and sets those values as the new baseline. - /// - /// The next set of encoded integer values. Length must equal the count passed to the constructor. - public void Next(ReadOnlySpan values) { - Debug.Assert(values.Length == _current.Length, "Values length must match the count passed to the constructor."); - - for (int i = 0; i < values.Length; i++) { - _deltas[i] = values[i] - _current[i]; - _current[i] = values[i]; - } - } - - /// - /// Returns a string representation of the current coordinate delta. - /// - /// - /// A string in the format { Coordinate: [v0, v1, ...], Delta: [d0, d1, ...] } representing the current values and their deltas to the previous item. - /// - public override readonly string ToString() { - StringBuilder sb = new(); - - sb.Append("{ Coordinate: ["); - for (int i = 0; i < _current.Length; i++) { - if (i > 0) { - sb.Append(", "); - } - - sb.Append(_current[i]); - } - - sb.Append("], Delta: ["); - for (int i = 0; i < _deltas.Length; i++) { - if (i > 0) { - sb.Append(", "); - } - - sb.Append(_deltas[i]); - } - - sb.Append("] }"); - - return sb.ToString(); - } -} \ No newline at end of file diff --git a/src/PolylineAlgorithm/Internal/PolylineReader.cs b/src/PolylineAlgorithm/Internal/PolylineReader.cs new file mode 100644 index 00000000..b85f5c8c --- /dev/null +++ b/src/PolylineAlgorithm/Internal/PolylineReader.cs @@ -0,0 +1,78 @@ +// +// Copyright © Pete Sramek. All rights reserved. +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace PolylineAlgorithm.Internal; + +using PolylineAlgorithm.Abstraction; +using PolylineAlgorithm.Internal.Diagnostics; +using System.Runtime.CompilerServices; + +/// +/// Engine-owned stateful cursor that delivers decoded field values to a formatter during polyline decoding. +/// +/// +/// The reader wraps the raw encoded character sequence and applies the full decoding pipeline +/// (ASCII shift reversal, un-zigzag, per-slot delta accumulation) on each call. +/// The engine calls before invoking the formatter for each item so that the +/// slot index resets correctly while delta state is preserved across item boundaries. +/// +internal sealed class PolylineReader : IPolylineReader { + private readonly ReadOnlyMemory _sequence; + private int _position; + private int[] _accumulated; + private int _slotIndex; + private readonly uint _precision; + + internal PolylineReader(ReadOnlyMemory sequence, uint precision) { + _sequence = sequence; + _precision = precision; + _accumulated = []; + _slotIndex = 0; + _position = 0; + } + + /// + /// Reads and returns the next decoded field value from the polyline sequence. + /// + /// + /// Thrown when the data runs out before the formatter has finished reading an item's fields. + /// + public double Read() { + // Grow the per-slot accumulator array on the first item (field discovery). + if (_slotIndex >= _accumulated.Length) { + Array.Resize(ref _accumulated, _slotIndex + 1); + } + + if (!PolylineEncoding.TryReadValue(ref _accumulated[_slotIndex], _sequence, ref _position)) { + ExceptionGuard.ThrowInvalidPolylineFormat(_position); + } + + double result = PolylineEncoding.Denormalize(_accumulated[_slotIndex], _precision); + _slotIndex++; + return result; + } + + /// + /// Resets the intra-item slot index so that delta accumulation is applied to the correct field slot + /// on the next item. Must be called by the engine before each call to the formatter's Read method. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void BeginItem() => _slotIndex = 0; + + /// + /// Gets the number of fields read in the current (or most recently completed) item. + /// + internal int SlotIndex => _slotIndex; + + /// + /// Gets the current character position in the encoded sequence. + /// + internal int Position => _position; + + /// + /// Returns when all encoded characters have been consumed. + /// + internal bool IsEmpty => _position >= _sequence.Length; +} diff --git a/src/PolylineAlgorithm/Internal/PolylineWriter.cs b/src/PolylineAlgorithm/Internal/PolylineWriter.cs new file mode 100644 index 00000000..3b1e1159 --- /dev/null +++ b/src/PolylineAlgorithm/Internal/PolylineWriter.cs @@ -0,0 +1,94 @@ +// +// Copyright © Pete Sramek. All rights reserved. +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace PolylineAlgorithm.Internal; + +using PolylineAlgorithm.Abstraction; +using PolylineAlgorithm.Internal.Diagnostics; +using System; +using System.Buffers; +using System.Runtime.CompilerServices; + +/// +/// Engine-owned stateful cursor that feeds values written by a formatter into the polyline encoding pipeline. +/// +/// +/// Each instance wraps a growable -backed output buffer and a per-slot delta accumulator. +/// The engine calls before invoking the formatter for each item so that the slot index +/// resets correctly while delta state is preserved across item boundaries. +/// +internal sealed class PolylineWriter : IPolylineWriter { + private char[] _buffer; + private int _position; + private readonly uint _precision; + private int[] _previous; + private int _slotIndex; + + internal PolylineWriter(int initialCapacity, uint precision) { + _buffer = ArrayPool.Shared.Rent(initialCapacity); + _precision = precision; + _previous = []; + _slotIndex = 0; + _position = 0; + } + + /// + /// Emits one field value into the encoding pipeline. + /// + public void Write(double value) { + // Grow the per-slot delta array on the first item (field discovery). + if (_slotIndex >= _previous.Length) { + Array.Resize(ref _previous, _slotIndex + 1); + } + + int normalized = PolylineEncoding.Normalize(value, _precision); + int delta = normalized - _previous[_slotIndex]; + _previous[_slotIndex] = normalized; + _slotIndex++; + + // Ensure the output buffer has room for the worst-case encoded chunk. + EnsureCapacity(_position + Defaults.Polyline.Block.Length.Max); + + if (!PolylineEncoding.TryWriteValue(delta, _buffer.AsSpan(), ref _position)) { + ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer(); + } + } + + /// + /// Resets the intra-item slot index so delta state is applied to the correct field on the next item. + /// Must be called by the engine before each call to the formatter's Write method. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void BeginItem() => _slotIndex = 0; + + /// + /// Gets the number of fields written in the current (or most recently completed) item. + /// + internal int SlotIndex => _slotIndex; + + /// + /// Returns the encoded polyline characters written so far. + /// The caller must not use this memory after is called. + /// + internal ReadOnlyMemory WrittenMemory => _buffer.AsMemory(0, _position); + + /// + /// Returns the rented buffer to the pool. Must be called exactly once when encoding is complete. + /// + internal void ReturnBuffer() => ArrayPool.Shared.Return(_buffer); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void EnsureCapacity(int required) { + if (required <= _buffer.Length) { + return; + } + + int newSize = Math.Max(_buffer.Length * 2, required); + char[] newBuffer = ArrayPool.Shared.Rent(newSize); + _buffer.AsSpan(0, _position).CopyTo(newBuffer); + ArrayPool.Shared.Return(_buffer); + _buffer = newBuffer; + } +} diff --git a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt index 7dc5c581..f4a0df28 100644 --- a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt +++ b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt @@ -1 +1,22 @@ #nullable enable +abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.GetReadOnlyMemory(in TPolyline polyline) -> System.ReadOnlyMemory +abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.Read(PolylineAlgorithm.Abstraction.IPolylineReader! reader) -> TCoordinate +abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.CreatePolyline(System.ReadOnlyMemory polyline) -> TPolyline +abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.Write(TCoordinate item, PolylineAlgorithm.Abstraction.IPolylineWriter! writer) -> void +PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.AbstractPolylineDecoder() -> void +PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.AbstractPolylineDecoder(PolylineAlgorithm.PolylineEncodingOptions! options) -> void +PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.Decode(TPolyline polyline, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Generic.IEnumerable! +PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.Options.get -> PolylineAlgorithm.PolylineEncodingOptions! +PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.Encode(System.ReadOnlySpan coordinates, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> TPolyline +PolylineAlgorithm.Abstraction.IPolylineReader +PolylineAlgorithm.Abstraction.IPolylineReader.Read() -> double +PolylineAlgorithm.Abstraction.IPolylineWriter +PolylineAlgorithm.Abstraction.IPolylineWriter.Write(double value) -> void +PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException() -> void +PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException(string! message, System.Exception! innerException) -> void +static PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(int delta) -> int +static PolylineAlgorithm.PolylineEncoding.TryWriteValue(int delta, System.Span buffer, ref int position) -> bool +static PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan polyline) -> void +static PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan polyline) -> void +static PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan polyline) -> void +virtual PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValidateFormat(System.ReadOnlyMemory sequence, Microsoft.Extensions.Logging.ILogger? logger) -> void diff --git a/src/PolylineAlgorithm/README.md b/src/PolylineAlgorithm/README.md index 099caa52..b049bb26 100644 --- a/src/PolylineAlgorithm/README.md +++ b/src/PolylineAlgorithm/README.md @@ -40,10 +40,9 @@ using PolylineAlgorithm; using PolylineAlgorithm.Abstraction; public sealed class MyPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - protected override int ValuesPerItem => 2; - protected override void GetValues((double Latitude, double Longitude) item, Span values) { - values[0] = item.Latitude; - values[1] = item.Longitude; + protected override void Write((double Latitude, double Longitude) item, IPolylineWriter writer) { + writer.Write(item.Latitude); // field 0 + writer.Write(item.Longitude); // field 1 } protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); } @@ -74,11 +73,8 @@ using PolylineAlgorithm; using PolylineAlgorithm.Abstraction; public sealed class MyPolylineDecoder : AbstractPolylineDecoder { - protected override int ValuesPerItem => 2; - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); - } + protected override (double Latitude, double Longitude) Read(IPolylineReader reader) => + (reader.Read(), reader.Read()); // field 0, field 1 protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); } ``` @@ -101,7 +97,6 @@ using Microsoft.Extensions.Logging; PolylineEncodingOptions options = PolylineEncodingOptionsBuilder.Create() .WithPrecision(6) // 6 decimal places instead of the default 5 - .WithStackAllocLimit(1024) // increase stack-alloc buffer .WithLoggerFactory(loggerFactory) // plug in your ILoggerFactory .Build(); diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs index b0017ee5..d7370587 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs @@ -17,11 +17,8 @@ namespace PolylineAlgorithm.Tests.Abstraction; public sealed class AbstractPolylineDecoderTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override int ValuesPerItem => 2; - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); - } + protected override (double Latitude, double Longitude) Read(IPolylineReader reader) => + (reader.Read(), reader.Read()); } private sealed class TestStringDecoderWithOptions : AbstractPolylineDecoder { @@ -29,11 +26,8 @@ public TestStringDecoderWithOptions(PolylineEncodingOptions options) : base(options) { } protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override int ValuesPerItem => 2; - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); - } + protected override (double Latitude, double Longitude) Read(IPolylineReader reader) => + (reader.Read(), reader.Read()); } /// diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs index 9988012f..43b184ce 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs @@ -22,10 +22,9 @@ public TestStringEncoder(PolylineEncodingOptions options) : base(options) { } protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override int ValuesPerItem => 2; - protected override void GetValues((double Latitude, double Longitude) item, Span values) { - values[0] = item.Latitude; - values[1] = item.Longitude; + protected override void Write((double Latitude, double Longitude) item, IPolylineWriter writer) { + writer.Write(item.Latitude); + writer.Write(item.Longitude); } } diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs index f651e65c..8af53e0a 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs @@ -18,20 +18,14 @@ namespace PolylineAlgorithm.Tests.Extensions; public sealed class PolylineDecoderExtensionsTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override int ValuesPerItem => 2; - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); - } + protected override (double Latitude, double Longitude) Read(IPolylineReader reader) => + (reader.Read(), reader.Read()); } private sealed class TestMemoryDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) => polyline; - protected override int ValuesPerItem => 2; - protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) { - ReadOnlySpan span = values.Span; - return (span[0], span[1]); - } + protected override (double Latitude, double Longitude) Read(IPolylineReader reader) => + (reader.Read(), reader.Read()); } // ----- Decode(char[]) for IPolylineDecoder ----- diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs index 3f322efe..6a3431bf 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs @@ -18,10 +18,9 @@ namespace PolylineAlgorithm.Tests.Extensions; public sealed class PolylineEncoderExtensionsTests { private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override int ValuesPerItem => 2; - protected override void GetValues((double Latitude, double Longitude) item, Span values) { - values[0] = item.Latitude; - values[1] = item.Longitude; + protected override void Write((double Latitude, double Longitude) item, IPolylineWriter writer) { + writer.Write(item.Latitude); + writer.Write(item.Longitude); } } diff --git a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs deleted file mode 100644 index 2109ffa8..00000000 --- a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs +++ /dev/null @@ -1,173 +0,0 @@ -// -// Copyright © Pete Sramek. All rights reserved. -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace PolylineAlgorithm.Tests.Internal; - -using PolylineAlgorithm.Internal; -using System.Globalization; - -/// -/// Tests for . -/// -[TestClass] -public sealed class CoordinateDeltaTests { - /// - /// Tests that the constructor with count 2 initializes delta values to zero. - /// - [TestMethod] - public void Constructor_With_Count_Two_Initializes_Deltas_To_Zero() { - // Act - CoordinateDelta delta = new(2); - - // Assert - ReadOnlySpan deltas = delta.Deltas; - Assert.AreEqual(2, deltas.Length); - Assert.AreEqual(0, deltas[0]); - Assert.AreEqual(0, deltas[1]); - } - - /// - /// Tests that the constructor with count 3 initializes delta values to zero. - /// - [TestMethod] - public void Constructor_With_Count_Three_Initializes_Deltas_To_Zero() { - // Act - CoordinateDelta delta = new(3); - - // Assert - ReadOnlySpan deltas = delta.Deltas; - Assert.AreEqual(3, deltas.Length); - for (int i = 0; i < deltas.Length; i++) { - Assert.AreEqual(0, deltas[i]); - } - } - - /// - /// Tests that a single call to Next computes the correct delta from the initial zero state. - /// - [TestMethod] - [DataRow(10, 20, 10, 20)] - [DataRow(-50, -100, -50, -100)] - [DataRow(0, 0, 0, 0)] - [DataRow(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue)] - [DataRow(int.MinValue, int.MinValue, int.MinValue, int.MinValue)] - public void Next_Single_Call_From_Zero_Computes_Expected_Delta(int first, int second, int expectedFirst, int expectedSecond) { - // Arrange - CoordinateDelta delta = new(2); - - // Act - delta.Next([first, second]); - - // Assert - ReadOnlySpan deltas = delta.Deltas; - Assert.AreEqual(expectedFirst, deltas[0]); - Assert.AreEqual(expectedSecond, deltas[1]); - } - - /// - /// Tests that two consecutive calls to Next compute the delta relative to the previous value. - /// - [TestMethod] - [DataRow(10, 20, 15, 30, 5, 10)] - [DataRow(100, 200, 50, 150, -50, -50)] - [DataRow(42, 84, 42, 84, 0, 0)] - [DataRow(-50, 100, 25, -75, 75, -175)] - public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value( - int firstA, int firstB, - int secondA, int secondB, - int expectedA, int expectedB) { - // Arrange - CoordinateDelta delta = new(2); - delta.Next([firstA, firstB]); - - // Act - delta.Next([secondA, secondB]); - - // Assert - ReadOnlySpan deltas = delta.Deltas; - Assert.AreEqual(expectedA, deltas[0]); - Assert.AreEqual(expectedB, deltas[1]); - } - - /// - /// Tests that Next works correctly for N-value items (N > 2). - /// - [TestMethod] - public void Next_With_Three_Values_Computes_Expected_Deltas() { - // Arrange - CoordinateDelta delta = new(3); - - // Act - delta.Next([10, 20, 30]); - delta.Next([15, 25, 35]); - - // Assert - ReadOnlySpan deltas = delta.Deltas; - Assert.AreEqual(5, deltas[0]); - Assert.AreEqual(5, deltas[1]); - Assert.AreEqual(5, deltas[2]); - } - - /// - /// Tests that ToString on a new instance returns a string containing expected structural keywords and zero values. - /// - [TestMethod] - public void ToString_With_New_Instance_Returns_Formatted_String_With_Zeros() { - // Arrange - CoordinateDelta delta = new(2); - - // Act - string result = delta.ToString(); - - // Assert - Assert.IsNotNull(result); - Assert.IsTrue(result.Contains("Coordinate", StringComparison.Ordinal)); - Assert.IsTrue(result.Contains("Delta", StringComparison.Ordinal)); - Assert.Contains('0', result); - } - - /// - /// Tests that ToString reflects the delta values computed by Next. - /// - [TestMethod] - [DataRow(42, 84)] - [DataRow(-100, -200)] - [DataRow(int.MaxValue, int.MaxValue)] - [DataRow(int.MinValue, int.MinValue)] - public void ToString_After_Next_Contains_Expected_Values(int first, int second) { - // Arrange - CoordinateDelta delta = new(2); - delta.Next([first, second]); - - // Act - string result = delta.ToString(); - - // Assert - Assert.IsNotNull(result); - Assert.IsTrue(result.Contains(first.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal)); - Assert.IsTrue(result.Contains(second.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal)); - } - - /// - /// Tests that ToString after multiple Next calls reflects the most recent delta values. - /// - [TestMethod] - public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Latest_Values() { - // Arrange - CoordinateDelta delta = new(2); - delta.Next([10, 20]); - delta.Next([30, 50]); - - // Act - string result = delta.ToString(); - - // Assert - Assert.IsNotNull(result); - Assert.IsTrue(result.Contains("30", StringComparison.Ordinal)); - Assert.IsTrue(result.Contains("50", StringComparison.Ordinal)); - Assert.IsTrue(result.Contains("20", StringComparison.Ordinal)); - } - -} diff --git a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs index 8992c560..e42f42b3 100644 --- a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs +++ b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs @@ -109,11 +109,9 @@ protected override string CreatePolyline(ReadOnlyMemory polyline) { return polyline.ToString(); } - protected override int ValuesPerItem => 2; - - protected override void GetValues((double Latitude, double Longitude) item, Span values) { - values[0] = item.Latitude; - values[1] = item.Longitude; + protected override void Write((double Latitude, double Longitude) item, IPolylineWriter writer) { + writer.Write(item.Latitude); + writer.Write(item.Longitude); } } } \ No newline at end of file From 9604ff72f61e3eb0fa5774b611447443c8abf1c2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 01:49:04 +0000 Subject: [PATCH 14/24] refactor: remove StackAllocLimit from public API, update SensorData sample Agent-Logs-Url: https://github.com/petesramek/polyline-algorithm-csharp/sessions/6048b0f0-ed27-438f-bf26-2525f7c4ff64 Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com> --- .../SensorDataEncoder.cs | 5 +- .../Internal/Diagnostics/ExceptionGuard.cs | 23 ---- .../PolylineEncodingOptions.cs | 16 +-- .../PolylineEncodingOptionsBuilder.cs | 30 ----- .../ExceptionMessageResource.Designer.cs | 8 -- .../Properties/ExceptionMessageResource.resx | 3 - .../AbstractPolylineEncoderTests.cs | 7 +- .../Diagnostics/ExceptionGuardTests.cs | 31 ----- .../PolylineEncodingOptionsBuilderTests.cs | 120 ------------------ 9 files changed, 7 insertions(+), 236 deletions(-) diff --git a/samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs b/samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs index be199e4d..20da8342 100644 --- a/samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs +++ b/samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs @@ -98,7 +98,10 @@ public string Encode(ReadOnlySpan coordinates, CancellationToken int position = 0; int length = coordinates.Length * 2 * MaxEncodedCharsPerValue; - char[]? temp = length <= Options.StackAllocLimit + // Use stackalloc for small buffers to avoid a heap allocation; fall back to ArrayPool for larger ones. + const int StackAllocLimit = 512; + + char[]? temp = length <= StackAllocLimit ? null : ArrayPool.Shared.Rent(length); diff --git a/src/PolylineAlgorithm/Internal/Diagnostics/ExceptionGuard.cs b/src/PolylineAlgorithm/Internal/Diagnostics/ExceptionGuard.cs index 208584ee..919a5367 100644 --- a/src/PolylineAlgorithm/Internal/Diagnostics/ExceptionGuard.cs +++ b/src/PolylineAlgorithm/Internal/Diagnostics/ExceptionGuard.cs @@ -86,21 +86,6 @@ internal static void ThrowCoordinateValueOutOfRange(double value, double min, do throw new ArgumentOutOfRangeException(paramName, ExceptionMessage.FormatCoordinateValueMustBeBetween(paramName, min, max)); } - /// - /// Throws an when a stack allocation limit is below the required minimum. - /// - /// Minimum required stack allocation limit. - /// Name of the parameter representing the limit. -#if NET6_0_OR_GREATER - [StackTraceHidden] -#else - [MethodImpl(MethodImplOptions.NoInlining)] -#endif - [DoesNotReturn] - internal static void StackAllocLimitMustBeEqualOrGreaterThan(int minValue, string paramName) { - throw new ArgumentOutOfRangeException(paramName, ExceptionMessage.FormatStackAllocLimitMustBeEqualOrGreaterThan(minValue)); - } - /// /// Throws an when an enumeration argument is empty but must contain at least one element. /// @@ -226,7 +211,6 @@ internal static void ThrowInvalidPolylineBlockTerminator() { [SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Internal use only.")] internal static class ExceptionMessage { #if NET8_0_OR_GREATER - private static readonly CompositeFormat StackAllocLimitMustBeEqualOrGreaterThanFormat = CompositeFormat.Parse(ExceptionMessageResource.StackAllocLimitMustBeEqualOrGreaterThanFormat); private static readonly CompositeFormat PolylineCannotBeShorterThanFormat = CompositeFormat.Parse(ExceptionMessageResource.PolylineCannotBeShorterThanFormat); private static readonly CompositeFormat PolylineIsMalformedAtFormat = CompositeFormat.Parse(ExceptionMessageResource.PolylineIsMalformedAtFormat); private static readonly CompositeFormat CoordinateValueMustBeBetweenFormat = CompositeFormat.Parse(ExceptionMessageResource.CoordinateValueMustBeBetweenValuesFormat); @@ -235,7 +219,6 @@ internal static class ExceptionMessage { private static readonly CompositeFormat DestinationArrayLengthMustBeEqualOrGreaterThanPolylineLengthFormat = CompositeFormat.Parse(ExceptionMessageResource.DestinationArrayLengthMustBeEqualOrGreaterThanPolylineLengthFormat); private static readonly CompositeFormat InvalidPolylineLengthFormat = CompositeFormat.Parse(ExceptionMessageResource.InvalidPolylineLengthFormat); #else - private static readonly string StackAllocLimitMustBeEqualOrGreaterThanFormat = ExceptionMessageResource.StackAllocLimitMustBeEqualOrGreaterThanFormat; private static readonly string PolylineCannotBeShorterThanFormat = ExceptionMessageResource.PolylineCannotBeShorterThanFormat; private static readonly string PolylineIsMalformedAtFormat = ExceptionMessageResource.PolylineIsMalformedAtFormat; private static readonly string CoordinateValueMustBeBetweenFormat = ExceptionMessageResource.CoordinateValueMustBeBetweenValuesFormat; @@ -250,12 +233,6 @@ internal static class ExceptionMessage { private static readonly string CouldNotWriteEncodedValueToTheBufferMessage = ExceptionMessageResource.CouldNotWriteEncodedValueToTheBufferMessage; private static readonly string InvalidPolylineBlockTerminatorMessage = ExceptionMessageResource.InvalidPolylineBlockTerminatorMessage; - /// - /// Formats the message for stack allocation limit violations. - /// - internal static string FormatStackAllocLimitMustBeEqualOrGreaterThan(int minValue) => - string.Format(CultureInfo.InvariantCulture, StackAllocLimitMustBeEqualOrGreaterThanFormat, minValue); - /// /// Formats the message when a polyline is shorter than the required minimum. /// diff --git a/src/PolylineAlgorithm/PolylineEncodingOptions.cs b/src/PolylineAlgorithm/PolylineEncodingOptions.cs index e99843de..63ffadbe 100644 --- a/src/PolylineAlgorithm/PolylineEncodingOptions.cs +++ b/src/PolylineAlgorithm/PolylineEncodingOptions.cs @@ -19,14 +19,13 @@ namespace PolylineAlgorithm; /// /// /// The level for coordinate encoding -/// The for memory allocation strategy /// The for diagnostic logging /// /// /// All properties have internal setters and should be configured through a builder or factory pattern. /// /// -[DebuggerDisplay("StackAllocLimit: {StackAllocLimit}, Precision: {Precision}, LoggerFactoryType: {GetLoggerFactoryType()}")] +[DebuggerDisplay("Precision: {Precision}, LoggerFactoryType: {GetLoggerFactoryType()}")] public sealed class PolylineEncodingOptions { /// /// Gets the logger factory used for diagnostic logging during encoding operations. @@ -59,19 +58,6 @@ public sealed class PolylineEncodingOptions { /// public uint Precision { get; internal set; } = 5; - /// - /// Gets the maximum buffer size (in characters) that can be allocated on the stack for encoding operations. - /// - /// - /// The maximum number of characters for stack allocation using stackalloc char[]. Defaults to 512. - /// - /// - /// When the required buffer size for encoding exceeds this limit, memory will be allocated on the heap instead of the stack. - /// This setting specifically applies to stack allocation of character arrays (stackalloc char[]) used during polyline encoding, - /// balancing performance and stack safety. - /// - public int StackAllocLimit { get; internal set; } = 512; - /// /// Returns the type name of the logger factory for debugging purposes. /// diff --git a/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs b/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs index 4258beca..21e41c1e 100644 --- a/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs +++ b/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs @@ -7,14 +7,12 @@ namespace PolylineAlgorithm; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -using PolylineAlgorithm.Internal.Diagnostics; /// /// Provides a builder for configuring options for polyline encoding operations. /// public sealed class PolylineEncodingOptionsBuilder { private uint _precision = 5; - private int _stackAllocLimit = 512; private ILoggerFactory _loggerFactory = NullLoggerFactory.Instance; private PolylineEncodingOptionsBuilder() { } @@ -38,38 +36,10 @@ public static PolylineEncodingOptionsBuilder Create() { public PolylineEncodingOptions Build() { return new PolylineEncodingOptions { Precision = _precision, - StackAllocLimit = _stackAllocLimit, LoggerFactory = _loggerFactory, }; } - /// - /// Configures the buffer size used for stack allocation during polyline encoding operations. - /// - /// - /// The maximum buffer size to use for stack allocation. Must be greater than or equal to 1. - /// - /// - /// The current instance for method chaining. - /// - /// - /// Thrown if is less than 1. - /// - /// - /// This method allows customization of the internal buffer size for encoding, which can impact performance and memory usage. - /// - public PolylineEncodingOptionsBuilder WithStackAllocLimit(int stackAllocLimit) { - const int minStackAllocLimit = 1; - - if (minStackAllocLimit > stackAllocLimit) { - ExceptionGuard.StackAllocLimitMustBeEqualOrGreaterThan(minStackAllocLimit, nameof(stackAllocLimit)); - } - - _stackAllocLimit = stackAllocLimit; - - return this; - } - /// /// Sets the coordinate encoding precision. /// diff --git a/src/PolylineAlgorithm/Properties/ExceptionMessageResource.Designer.cs b/src/PolylineAlgorithm/Properties/ExceptionMessageResource.Designer.cs index 0c73cce3..773fa473 100644 --- a/src/PolylineAlgorithm/Properties/ExceptionMessageResource.Designer.cs +++ b/src/PolylineAlgorithm/Properties/ExceptionMessageResource.Designer.cs @@ -159,13 +159,5 @@ internal static string PolylineIsMalformedAtFormat { } } - /// - /// Looks up a localized string similar to Stack alloc limit must be equal or greater than {0}.. - /// - internal static string StackAllocLimitMustBeEqualOrGreaterThanFormat { - get { - return ResourceManager.GetString("StackAllocLimitMustBeEqualOrGreaterThanFormat", resourceCulture); - } - } } } diff --git a/src/PolylineAlgorithm/Properties/ExceptionMessageResource.resx b/src/PolylineAlgorithm/Properties/ExceptionMessageResource.resx index 9ec92bf4..4e0f71d3 100644 --- a/src/PolylineAlgorithm/Properties/ExceptionMessageResource.resx +++ b/src/PolylineAlgorithm/Properties/ExceptionMessageResource.resx @@ -129,9 +129,6 @@ Value must be a finite number. - - Stack alloc limit must be equal or greater than {0}. - Destination array length {0} must be greater than the polyline length {1}. diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs index 43b184ce..6d2bcabc 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs @@ -40,7 +40,6 @@ public void Constructor_With_Default_Options_Creates_Instance() { Assert.IsNotNull(encoder); Assert.IsNotNull(encoder.Options); Assert.AreEqual(5u, encoder.Options.Precision); - Assert.AreEqual(512, encoder.Options.StackAllocLimit); } /// @@ -132,14 +131,12 @@ public void Encode_With_Pre_Cancelled_Token_Throws_OperationCanceledException() } /// - /// Tests that Encode still produces the correct result when the buffer exceeds the stack allocation - /// limit, forcing heap allocation via . + /// Tests that Encode produces the correct result for a standard set of coordinates. /// [TestMethod] public void Encode_With_Small_Stack_Alloc_Limit_Uses_Heap_Allocation_And_Produces_Correct_Result() { - // Arrange — force heap path by making stackAllocLimit smaller than any real encoding needs + // Arrange PolylineEncodingOptions options = PolylineEncodingOptionsBuilder.Create() - .WithStackAllocLimit(1) .Build(); TestStringEncoder encoder = new(options); (double Latitude, double Longitude)[] coordinates = [.. StaticValueProvider.Valid.GetCoordinates()]; diff --git a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/ExceptionGuardTests.cs b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/ExceptionGuardTests.cs index b49e719a..1b0701b9 100644 --- a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/ExceptionGuardTests.cs +++ b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/ExceptionGuardTests.cs @@ -70,21 +70,6 @@ public void ThrowCoordinateValueOutOfRange_With_Parameters_Throws_ArgumentOutOfR Assert.IsNotNull(ex.Message); } - /// - /// Tests that StackAllocLimitMustBeEqualOrGreaterThan throws ArgumentOutOfRangeException with correct parameter name. - /// - [TestMethod] - public void StackAllocLimitMustBeEqualOrGreaterThan_With_Parameters_Throws_ArgumentOutOfRangeException() { - // Arrange - const int minValue = 10; - const string paramName = "stackAllocLimit"; - - // Act & Assert - var ex = Assert.ThrowsExactly(() => ExceptionGuard.StackAllocLimitMustBeEqualOrGreaterThan(minValue, paramName)); - Assert.AreEqual(paramName, ex.ParamName); - Assert.IsNotNull(ex.Message); - } - /// /// Tests that ThrowArgumentCannotBeEmptyEnumerationMessage throws ArgumentException with correct parameter name. /// @@ -189,22 +174,6 @@ public void ThrowInvalidPolylineBlockTerminator_Throws_InvalidPolylineException( Assert.IsNotNull(ex.Message); } - /// - /// Tests that FormatStackAllocLimitMustBeEqualOrGreaterThan returns formatted message with specified value. - /// - [TestMethod] - public void FormatStackAllocLimitMustBeEqualOrGreaterThan_With_Min_Value_Returns_Formatted_Message() { - // Arrange - const int minValue = 10; - - // Act - string result = ExceptionGuard.ExceptionMessage.FormatStackAllocLimitMustBeEqualOrGreaterThan(minValue); - - // Assert - Assert.IsNotNull(result); - Assert.IsTrue(result.Contains("10", StringComparison.Ordinal)); - } - /// /// Tests that FormatPolylineCannotBeShorterThan returns formatted message with specified values. /// diff --git a/tests/PolylineAlgorithm.Tests/PolylineEncodingOptionsBuilderTests.cs b/tests/PolylineAlgorithm.Tests/PolylineEncodingOptionsBuilderTests.cs index 26dafc74..9e9ff272 100644 --- a/tests/PolylineAlgorithm.Tests/PolylineEncodingOptionsBuilderTests.cs +++ b/tests/PolylineAlgorithm.Tests/PolylineEncodingOptionsBuilderTests.cs @@ -54,7 +54,6 @@ public void Build_With_Defaults_Returns_Options_With_Default_Values() { // Assert Assert.IsNotNull(result); Assert.AreEqual(5u, result.Precision); - Assert.AreEqual(512, result.StackAllocLimit); Assert.IsNotNull(result.LoggerFactory); Assert.IsInstanceOfType(result.LoggerFactory); } @@ -75,22 +74,6 @@ public void Build_With_Custom_Precision_Returns_Options_With_Custom_Precision() Assert.AreEqual(7u, result.Precision); } - /// - /// Tests that Build returns options with configured stack alloc limit. - /// - [TestMethod] - public void Build_With_Custom_Stack_Alloc_Limit_Returns_Options_With_Custom_Stack_Alloc_Limit() { - // Arrange - PolylineEncodingOptionsBuilder builder = PolylineEncodingOptionsBuilder.Create() - .WithStackAllocLimit(1024); - - // Act - PolylineEncodingOptions result = builder.Build(); - - // Assert - Assert.AreEqual(1024, result.StackAllocLimit); - } - /// /// Tests that Build returns options with configured logger factory. /// @@ -120,7 +103,6 @@ public void Build_With_All_Custom_Values_Returns_Options_With_All_Custom_Values( ILoggerFactory loggerFactory = LoggerFactory.Create(_ => { }); PolylineEncodingOptionsBuilder builder = PolylineEncodingOptionsBuilder.Create() .WithPrecision(10) - .WithStackAllocLimit(2048) .WithLoggerFactory(loggerFactory); // Act @@ -128,7 +110,6 @@ public void Build_With_All_Custom_Values_Returns_Options_With_All_Custom_Values( // Assert Assert.AreEqual(10u, result.Precision); - Assert.AreEqual(2048, result.StackAllocLimit); Assert.AreSame(loggerFactory, result.LoggerFactory); // Cleanup @@ -151,105 +132,6 @@ public void Build_With_Multiple_Invocations_Returns_Different_Instances_With_Sam // Assert Assert.AreNotSame(first, second); Assert.AreEqual(first.Precision, second.Precision); - Assert.AreEqual(first.StackAllocLimit, second.StackAllocLimit); - } - - /// - /// Tests that WithStackAllocLimit sets the value and returns the builder. - /// - [TestMethod] - public void WithStackAllocLimit_With_Valid_Value_Sets_Value_And_Returns_Self() { - // Arrange - PolylineEncodingOptionsBuilder builder = PolylineEncodingOptionsBuilder.Create(); - - // Act - PolylineEncodingOptionsBuilder result = builder.WithStackAllocLimit(256); - - // Assert - Assert.AreSame(builder, result); - PolylineEncodingOptions options = builder.Build(); - Assert.AreEqual(256, options.StackAllocLimit); - } - - /// - /// Tests that WithStackAllocLimit accepts minimum value of 1. - /// - [TestMethod] - public void WithStackAllocLimit_With_Minimum_Value_Sets_Value() { - // Arrange - PolylineEncodingOptionsBuilder builder = PolylineEncodingOptionsBuilder.Create(); - - // Act - builder.WithStackAllocLimit(1); - PolylineEncodingOptions result = builder.Build(); - - // Assert - Assert.AreEqual(1, result.StackAllocLimit); - } - - /// - /// Tests that WithStackAllocLimit throws ArgumentOutOfRangeException for zero. - /// - [TestMethod] - public void WithStackAllocLimit_With_Zero_Throws_ArgumentOutOfRangeException() { - // Arrange - PolylineEncodingOptionsBuilder builder = PolylineEncodingOptionsBuilder.Create(); - - // Act - var exception = Assert.ThrowsExactly(() => builder.WithStackAllocLimit(0)); - - // Assert - Assert.AreEqual("stackAllocLimit", exception.ParamName); - } - - /// - /// Tests that WithStackAllocLimit throws ArgumentOutOfRangeException for negative value. - /// - [TestMethod] - public void WithStackAllocLimit_With_Negative_Value_Throws_ArgumentOutOfRangeException() { - // Arrange - PolylineEncodingOptionsBuilder builder = PolylineEncodingOptionsBuilder.Create(); - - // Act - var exception = Assert.ThrowsExactly(() => builder.WithStackAllocLimit(-10)); - - // Assert - Assert.AreEqual("stackAllocLimit", exception.ParamName); - } - - /// - /// Tests that WithStackAllocLimit accepts large value. - /// - [TestMethod] - public void WithStackAllocLimit_With_Large_Value_Sets_Value() { - // Arrange - PolylineEncodingOptionsBuilder builder = PolylineEncodingOptionsBuilder.Create(); - - // Act - PolylineEncodingOptions result = builder - .WithStackAllocLimit(100000) - .Build(); - - // Assert - Assert.AreEqual(100000, result.StackAllocLimit); - } - - /// - /// Tests that WithStackAllocLimit can be called multiple times. - /// - [TestMethod] - public void WithStackAllocLimit_With_Multiple_Calls_Last_Value_Wins() { - // Arrange - PolylineEncodingOptionsBuilder builder = PolylineEncodingOptionsBuilder.Create(); - - // Act - PolylineEncodingOptions result = builder.WithStackAllocLimit(100) - .WithStackAllocLimit(200) - .WithStackAllocLimit(300) - .Build(); - - // Assert - Assert.AreEqual(300, result.StackAllocLimit); } /// @@ -412,14 +294,12 @@ public void MethodChaining_With_All_Methods_Returns_Builder_For_Chaining() { // Act PolylineEncodingOptions result = PolylineEncodingOptionsBuilder.Create() .WithPrecision(6) - .WithStackAllocLimit(1024) .WithLoggerFactory(loggerFactory) .Build(); // Assert Assert.IsNotNull(result); Assert.AreEqual(6u, result.Precision); - Assert.AreEqual(1024, result.StackAllocLimit); Assert.AreSame(loggerFactory, result.LoggerFactory); } } \ No newline at end of file From e8634072c70318dad6c68319b85573b44a2d44ff Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 06:18:20 +0000 Subject: [PATCH 15/24] refactor: remove EnsureCapacity from PolylineWriter, pass max capacity upfront Agent-Logs-Url: https://github.com/petesramek/polyline-algorithm-csharp/sessions/e4cd1165-0005-4fad-a25f-a6f64f30e208 Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com> --- .../Abstraction/AbstractPolylineEncoder.cs | 6 ++-- .../Internal/PolylineWriter.cs | 29 +++++-------------- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs index 6dc035b0..ff21819c 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs @@ -86,9 +86,9 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken ValidateEmptyCoordinates(ref coordinates, _logger, OperationName); - // Initial capacity assumes 2 values per item (typical lat/lon); the writer grows if needed. - int initialCapacity = coordinates.Length * 2 * Defaults.Polyline.Block.Length.Max; - PolylineWriter writer = new(initialCapacity, Options.Precision); + // Worst-case maximum: every value uses the maximum number of encoded characters. + int maxCapacity = coordinates.Length * 2 * Defaults.Polyline.Block.Length.Max; + PolylineWriter writer = new(maxCapacity, Options.Precision); TPolyline result; diff --git a/src/PolylineAlgorithm/Internal/PolylineWriter.cs b/src/PolylineAlgorithm/Internal/PolylineWriter.cs index 3b1e1159..423d6066 100644 --- a/src/PolylineAlgorithm/Internal/PolylineWriter.cs +++ b/src/PolylineAlgorithm/Internal/PolylineWriter.cs @@ -15,19 +15,20 @@ namespace PolylineAlgorithm.Internal; /// Engine-owned stateful cursor that feeds values written by a formatter into the polyline encoding pipeline. /// /// -/// Each instance wraps a growable -backed output buffer and a per-slot delta accumulator. -/// The engine calls before invoking the formatter for each item so that the slot index -/// resets correctly while delta state is preserved across item boundaries. +/// Each instance wraps an -backed output buffer sized to the worst-case maximum +/// capacity so that the buffer never needs to grow. The engine calls before +/// invoking the formatter for each item so that the slot index resets correctly while delta state is +/// preserved across item boundaries. /// internal sealed class PolylineWriter : IPolylineWriter { - private char[] _buffer; + private readonly char[] _buffer; private int _position; private readonly uint _precision; private int[] _previous; private int _slotIndex; - internal PolylineWriter(int initialCapacity, uint precision) { - _buffer = ArrayPool.Shared.Rent(initialCapacity); + internal PolylineWriter(int capacity, uint precision) { + _buffer = ArrayPool.Shared.Rent(capacity); _precision = precision; _previous = []; _slotIndex = 0; @@ -48,9 +49,6 @@ public void Write(double value) { _previous[_slotIndex] = normalized; _slotIndex++; - // Ensure the output buffer has room for the worst-case encoded chunk. - EnsureCapacity(_position + Defaults.Polyline.Block.Length.Max); - if (!PolylineEncoding.TryWriteValue(delta, _buffer.AsSpan(), ref _position)) { ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer(); } @@ -78,17 +76,4 @@ public void Write(double value) { /// Returns the rented buffer to the pool. Must be called exactly once when encoding is complete. /// internal void ReturnBuffer() => ArrayPool.Shared.Return(_buffer); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void EnsureCapacity(int required) { - if (required <= _buffer.Length) { - return; - } - - int newSize = Math.Max(_buffer.Length * 2, required); - char[] newBuffer = ArrayPool.Shared.Rent(newSize); - _buffer.AsSpan(0, _position).CopyTo(newBuffer); - ArrayPool.Shared.Return(_buffer); - _buffer = newBuffer; - } } From 9af79d95b44f5c108ec5682825d1abb818098b5c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 06:43:24 +0000 Subject: [PATCH 16/24] refactor: move buffer allocation to encoder with ArrayPool threshold, PolylineWriter accepts external char[] Agent-Logs-Url: https://github.com/petesramek/polyline-algorithm-csharp/sessions/08c12b26-d5d8-4708-a74b-78e4cf6e2cbb Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com> --- .../Abstraction/AbstractPolylineEncoder.cs | 17 ++++++++++++++--- .../Internal/PolylineWriter.cs | 14 ++++---------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs index ff21819c..f60d31c1 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs @@ -10,6 +10,7 @@ namespace PolylineAlgorithm.Abstraction; using PolylineAlgorithm.Internal; using PolylineAlgorithm.Internal.Diagnostics; using System; +using System.Buffers; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Threading; @@ -88,7 +89,16 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken // Worst-case maximum: every value uses the maximum number of encoded characters. int maxCapacity = coordinates.Length * 2 * Defaults.Polyline.Block.Length.Max; - PolylineWriter writer = new(maxCapacity, Options.Precision); + + // Use ArrayPool for large buffers to avoid large heap allocations; for small buffers a fresh + // allocation is cheaper than pool overhead. + const int StackAllocThreshold = 512; + char[]? rentedBuffer = maxCapacity > StackAllocThreshold + ? ArrayPool.Shared.Rent(maxCapacity) + : null; + char[] buffer = rentedBuffer ?? new char[maxCapacity]; + + PolylineWriter writer = new(buffer, Options.Precision); TPolyline result; @@ -102,7 +112,9 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken result = CreatePolyline(writer.WrittenMemory); } finally { - writer.ReturnBuffer(); + if (rentedBuffer is not null) { + ArrayPool.Shared.Return(rentedBuffer); + } } _logger @@ -150,4 +162,3 @@ static void ValidateEmptyCoordinates(ref ReadOnlySpan coordinates, [MethodImpl(MethodImplOptions.AggressiveInlining)] protected abstract void Write(TCoordinate item, IPolylineWriter writer); } - diff --git a/src/PolylineAlgorithm/Internal/PolylineWriter.cs b/src/PolylineAlgorithm/Internal/PolylineWriter.cs index 423d6066..3fed109c 100644 --- a/src/PolylineAlgorithm/Internal/PolylineWriter.cs +++ b/src/PolylineAlgorithm/Internal/PolylineWriter.cs @@ -8,14 +8,13 @@ namespace PolylineAlgorithm.Internal; using PolylineAlgorithm.Abstraction; using PolylineAlgorithm.Internal.Diagnostics; using System; -using System.Buffers; using System.Runtime.CompilerServices; /// /// Engine-owned stateful cursor that feeds values written by a formatter into the polyline encoding pipeline. /// /// -/// Each instance wraps an -backed output buffer sized to the worst-case maximum +/// Each instance wraps a caller-provided buffer sized to the worst-case maximum /// capacity so that the buffer never needs to grow. The engine calls before /// invoking the formatter for each item so that the slot index resets correctly while delta state is /// preserved across item boundaries. @@ -27,8 +26,8 @@ internal sealed class PolylineWriter : IPolylineWriter { private int[] _previous; private int _slotIndex; - internal PolylineWriter(int capacity, uint precision) { - _buffer = ArrayPool.Shared.Rent(capacity); + internal PolylineWriter(char[] buffer, uint precision) { + _buffer = buffer; _precision = precision; _previous = []; _slotIndex = 0; @@ -68,12 +67,7 @@ public void Write(double value) { /// /// Returns the encoded polyline characters written so far. - /// The caller must not use this memory after is called. + /// The caller must not use this memory after the buffer is returned to . /// internal ReadOnlyMemory WrittenMemory => _buffer.AsMemory(0, _position); - - /// - /// Returns the rented buffer to the pool. Must be called exactly once when encoding is complete. - /// - internal void ReturnBuffer() => ArrayPool.Shared.Return(_buffer); } From fc751aec5bf07e968ab2d05ef5541e5f821dfa82 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 08:25:07 +0000 Subject: [PATCH 17/24] feat: remove IPolylineWriter/IPolylineReader; restore stackalloc in encoder via ref struct PolylineWriter Agent-Logs-Url: https://github.com/petesramek/polyline-algorithm-csharp/sessions/8085d58f-4c97-4a7a-a577-f078ff234b2a Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com> --- .../PolylineDecoderBenchmark.cs | 7 ++-- .../PolylineEncoderBenchmark.cs | 5 ++- .../NetTopologyPolylineDecoder.cs | 3 +- .../NetTopologyPolylineEncoder.cs | 9 +++-- .../Abstraction/AbstractPolylineDecoder.cs | 6 +-- .../Abstraction/AbstractPolylineEncoder.cs | 29 +++++++------- .../Abstraction/IPolylineReader.cs | 39 ------------------- .../Abstraction/IPolylineWriter.cs | 37 ------------------ .../Internal/PolylineReader.cs | 3 +- .../Internal/PolylineWriter.cs | 15 ++++--- src/PolylineAlgorithm/PublicAPI.Unshipped.txt | 14 +++---- .../AbstractPolylineDecoderTests.cs | 5 ++- .../AbstractPolylineEncoderTests.cs | 5 ++- .../PolylineDecoderExtensionsTests.cs | 5 ++- .../PolylineEncoderExtensionsTests.cs | 5 ++- .../RandomValueProvider.cs | 5 ++- 16 files changed, 61 insertions(+), 131 deletions(-) delete mode 100644 src/PolylineAlgorithm/Abstraction/IPolylineReader.cs delete mode 100644 src/PolylineAlgorithm/Abstraction/IPolylineWriter.cs diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs index 9425eba8..6ef207b7 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs @@ -8,6 +8,7 @@ namespace PolylineAlgorithm.Benchmarks; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Engines; using PolylineAlgorithm.Abstraction; +using PolylineAlgorithm.Internal; using PolylineAlgorithm.Utility; /// @@ -93,7 +94,7 @@ public void PolylineDecoder_Decode_Memory() { } private sealed class StringPolylineDecoder : AbstractPolylineDecoder { - protected override (double Latitude, double Longitude) Read(IPolylineReader reader) => + protected override (double Latitude, double Longitude) Read(PolylineReader reader) => (reader.Read(), reader.Read()); protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { @@ -102,7 +103,7 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { } private sealed class CharArrayPolylineDecoder : AbstractPolylineDecoder { - protected override (double Latitude, double Longitude) Read(IPolylineReader reader) => + protected override (double Latitude, double Longitude) Read(PolylineReader reader) => (reader.Read(), reader.Read()); protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) { @@ -111,7 +112,7 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) { } private sealed class MemoryCharPolylineDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { - protected override (double Latitude, double Longitude) Read(IPolylineReader reader) => + protected override (double Latitude, double Longitude) Read(PolylineReader reader) => (reader.Read(), reader.Read()); protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) { diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs index a662d887..fee56005 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs @@ -9,6 +9,7 @@ namespace PolylineAlgorithm.Benchmarks; using BenchmarkDotNet.Engines; using PolylineAlgorithm.Abstraction; using PolylineAlgorithm.Extensions; +using PolylineAlgorithm.Internal; using PolylineAlgorithm.Utility; using System.Collections.Generic; @@ -85,8 +86,8 @@ public void PolylineEncoder_Encode_List() { } private sealed class StringPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override void Write((double Latitude, double Longitude) item, IPolylineWriter writer) { + protected override string CreatePolyline(ReadOnlySpan polyline) => polyline.ToString(); + protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer) { writer.Write(item.Latitude); writer.Write(item.Longitude); } diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs index d37ccc0f..e6e8ae42 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs @@ -7,6 +7,7 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; using global::NetTopologySuite.Geometries; using PolylineAlgorithm.Abstraction; +using PolylineAlgorithm.Internal; using System; /// @@ -27,7 +28,7 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { /// /// The reader provided by the engine. Field 0 = latitude, field 1 = longitude. /// Point instance. - protected override Point Read(IPolylineReader reader) { + protected override Point Read(PolylineReader reader) { double latitude = reader.Read(); double longitude = reader.Read(); diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs index ff97f7e3..0310ebad 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs @@ -7,6 +7,7 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; using global::NetTopologySuite.Geometries; using PolylineAlgorithm.Abstraction; +using PolylineAlgorithm.Internal; using System; /// @@ -14,11 +15,11 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; /// internal sealed class NetTopologyPolylineEncoder : AbstractPolylineEncoder { /// - /// Creates encoded polyline string from memory. + /// Creates encoded polyline string from span. /// - /// Polyline memory. + /// Polyline span. /// Encoded polyline string. - protected override string CreatePolyline(ReadOnlyMemory polyline) { + protected override string CreatePolyline(ReadOnlySpan polyline) { if (polyline.IsEmpty) { return string.Empty; } @@ -31,7 +32,7 @@ protected override string CreatePolyline(ReadOnlyMemory polyline) { /// /// The point to write. Field 0 = latitude (Y), field 1 = longitude (X). /// The writer provided by the engine. - protected override void Write(Point item, IPolylineWriter writer) { + protected override void Write(Point item, ref PolylineWriter writer) { ArgumentNullException.ThrowIfNull(item); // NetTopologySuite Point: Y = latitude, X = longitude diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs index bd302d2d..61b5c77f 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs @@ -181,7 +181,7 @@ protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? lo /// Reads field values from the polyline decoding pipeline and constructs one item. /// /// - /// The cursor provided by the engine. Call + /// The cursor provided by the engine. Call /// once for each expected field value, in the same order used by the corresponding encoder's /// override. /// @@ -189,10 +189,10 @@ protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? lo /// A instance constructed from the decoded field values. /// /// - /// Implementations must always call the same number of times, + /// Implementations must always call the same number of times, /// in the same field order, for every item. The number of reads must match the number of writes /// performed by the corresponding encoder's override. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract TCoordinate Read(IPolylineReader reader); + protected abstract TCoordinate Read(PolylineReader reader); } diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs index f60d31c1..33cfaa7b 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs @@ -90,13 +90,12 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken // Worst-case maximum: every value uses the maximum number of encoded characters. int maxCapacity = coordinates.Length * 2 * Defaults.Polyline.Block.Length.Max; - // Use ArrayPool for large buffers to avoid large heap allocations; for small buffers a fresh - // allocation is cheaper than pool overhead. + // Use stackalloc for small buffers (zero heap allocation); fall back to ArrayPool for large ones. const int StackAllocThreshold = 512; - char[]? rentedBuffer = maxCapacity > StackAllocThreshold - ? ArrayPool.Shared.Rent(maxCapacity) - : null; - char[] buffer = rentedBuffer ?? new char[maxCapacity]; + char[]? rentedBuffer = null; + Span buffer = maxCapacity > StackAllocThreshold + ? (rentedBuffer = ArrayPool.Shared.Rent(maxCapacity)).AsSpan(0, maxCapacity) + : stackalloc char[maxCapacity]; PolylineWriter writer = new(buffer, Options.Precision); @@ -107,10 +106,10 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken.ThrowIfCancellationRequested(); writer.BeginItem(); - Write(coordinates[i], writer); + Write(coordinates[i], ref writer); } - result = CreatePolyline(writer.WrittenMemory); + result = CreatePolyline(writer.WrittenSpan); } finally { if (rentedBuffer is not null) { ArrayPool.Shared.Return(rentedBuffer); @@ -136,29 +135,29 @@ static void ValidateEmptyCoordinates(ref ReadOnlySpan coordinates, } /// - /// Creates a polyline instance from the provided read-only sequence of characters. + /// Creates a polyline instance from the provided read-only span of characters. /// - /// A containing the encoded polyline characters. + /// A containing the encoded polyline characters. /// /// An instance of representing the encoded polyline. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline); + protected abstract TPolyline CreatePolyline(ReadOnlySpan polyline); /// /// Writes the field values of the specified item into the polyline encoding pipeline. /// /// The item whose field values are to be encoded. /// - /// The cursor provided by the engine. Call + /// The cursor provided by the engine. Call /// once for each field value, in a fixed, consistent order. The engine handles delta computation, /// zigzag encoding, and output buffering. /// /// - /// Implementations must always call the same number of times, + /// Implementations must always call the same number of times, /// in the same field order, for every item. The corresponding override must - /// call the same number of times in the same order. + /// call the same number of times in the same order. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract void Write(TCoordinate item, IPolylineWriter writer); + protected abstract void Write(TCoordinate item, ref PolylineWriter writer); } diff --git a/src/PolylineAlgorithm/Abstraction/IPolylineReader.cs b/src/PolylineAlgorithm/Abstraction/IPolylineReader.cs deleted file mode 100644 index 8cde0f30..00000000 --- a/src/PolylineAlgorithm/Abstraction/IPolylineReader.cs +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright © Pete Sramek. All rights reserved. -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace PolylineAlgorithm.Abstraction; - -/// -/// Defines a read-only cursor for consuming individual field values from the polyline decoding pipeline. -/// -/// -/// -/// Instances of are created and owned by the decoding engine. Formatter implementations -/// must not create readers directly. -/// -/// -/// During decoding, the engine reverses the ASCII shift, un-zigzags, and accumulates deltas for each -/// encoded chunk. The reader exposes the resulting absolute floating-point values one at a time. -/// Each call to returns the next value and advances the cursor. -/// -/// -/// The reader is shared across all items in the sequence, so the formatter's implementation of -/// must consume exactly as many values per item as the corresponding -/// encoder's formatter writes. -/// -/// -public interface IPolylineReader { - /// - /// Reads and returns the next field value from the polyline decoding pipeline. - /// - /// - /// The next decoded floating-point field value. - /// - /// - /// Thrown when the polyline data is exhausted or malformed before the expected number of fields - /// for the current item has been read. - /// - double Read(); -} diff --git a/src/PolylineAlgorithm/Abstraction/IPolylineWriter.cs b/src/PolylineAlgorithm/Abstraction/IPolylineWriter.cs deleted file mode 100644 index a6eaaa5c..00000000 --- a/src/PolylineAlgorithm/Abstraction/IPolylineWriter.cs +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright © Pete Sramek. All rights reserved. -// Licensed under the MIT License. See LICENSE file in the project root for full license information. -// - -namespace PolylineAlgorithm.Abstraction; - -/// -/// Defines a write-only cursor for emitting individual field values into the polyline encoding pipeline. -/// -/// -/// -/// Instances of are created and owned by the encoding engine. Formatter implementations -/// must not create writers directly. -/// -/// -/// During encoding, the engine creates one writer per encoding session and calls -/// once for every field of every item, in the order determined by the formatter. -/// Delta accumulation, zigzag encoding, and ASCII shifting are performed internally; the formatter -/// only sees raw floating-point field values. -/// -/// -/// The writer is shared across all items in the sequence so that delta state carries correctly -/// across item boundaries. -/// -/// -public interface IPolylineWriter { - /// - /// Emits one field value into the polyline encoding pipeline. - /// - /// - /// The field value to emit. The engine normalises the value, computes the delta against the - /// same-position field of the previous item, applies zigzag encoding, and writes the result - /// to the output buffer. - /// - void Write(double value); -} diff --git a/src/PolylineAlgorithm/Internal/PolylineReader.cs b/src/PolylineAlgorithm/Internal/PolylineReader.cs index b85f5c8c..0447feda 100644 --- a/src/PolylineAlgorithm/Internal/PolylineReader.cs +++ b/src/PolylineAlgorithm/Internal/PolylineReader.cs @@ -5,7 +5,6 @@ namespace PolylineAlgorithm.Internal; -using PolylineAlgorithm.Abstraction; using PolylineAlgorithm.Internal.Diagnostics; using System.Runtime.CompilerServices; @@ -18,7 +17,7 @@ namespace PolylineAlgorithm.Internal; /// The engine calls before invoking the formatter for each item so that the /// slot index resets correctly while delta state is preserved across item boundaries. /// -internal sealed class PolylineReader : IPolylineReader { +public sealed class PolylineReader { private readonly ReadOnlyMemory _sequence; private int _position; private int[] _accumulated; diff --git a/src/PolylineAlgorithm/Internal/PolylineWriter.cs b/src/PolylineAlgorithm/Internal/PolylineWriter.cs index 3fed109c..f64fe21d 100644 --- a/src/PolylineAlgorithm/Internal/PolylineWriter.cs +++ b/src/PolylineAlgorithm/Internal/PolylineWriter.cs @@ -5,7 +5,6 @@ namespace PolylineAlgorithm.Internal; -using PolylineAlgorithm.Abstraction; using PolylineAlgorithm.Internal.Diagnostics; using System; using System.Runtime.CompilerServices; @@ -15,18 +14,19 @@ namespace PolylineAlgorithm.Internal; /// /// /// Each instance wraps a caller-provided buffer sized to the worst-case maximum -/// capacity so that the buffer never needs to grow. The engine calls before +/// capacity so that the buffer never needs to grow. The buffer may be stack-allocated or rented from +/// ; the engine calls before /// invoking the formatter for each item so that the slot index resets correctly while delta state is /// preserved across item boundaries. /// -internal sealed class PolylineWriter : IPolylineWriter { - private readonly char[] _buffer; +public ref struct PolylineWriter { + private Span _buffer; private int _position; private readonly uint _precision; private int[] _previous; private int _slotIndex; - internal PolylineWriter(char[] buffer, uint precision) { + internal PolylineWriter(Span buffer, uint precision) { _buffer = buffer; _precision = precision; _previous = []; @@ -48,7 +48,7 @@ public void Write(double value) { _previous[_slotIndex] = normalized; _slotIndex++; - if (!PolylineEncoding.TryWriteValue(delta, _buffer.AsSpan(), ref _position)) { + if (!PolylineEncoding.TryWriteValue(delta, _buffer, ref _position)) { ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer(); } } @@ -67,7 +67,6 @@ public void Write(double value) { /// /// Returns the encoded polyline characters written so far. - /// The caller must not use this memory after the buffer is returned to . /// - internal ReadOnlyMemory WrittenMemory => _buffer.AsMemory(0, _position); + internal ReadOnlySpan WrittenSpan => _buffer[.._position]; } diff --git a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt index f4a0df28..02d5732d 100644 --- a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt +++ b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt @@ -1,17 +1,17 @@ #nullable enable abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.GetReadOnlyMemory(in TPolyline polyline) -> System.ReadOnlyMemory -abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.Read(PolylineAlgorithm.Abstraction.IPolylineReader! reader) -> TCoordinate -abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.CreatePolyline(System.ReadOnlyMemory polyline) -> TPolyline -abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.Write(TCoordinate item, PolylineAlgorithm.Abstraction.IPolylineWriter! writer) -> void +abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.Read(PolylineAlgorithm.Internal.PolylineReader! reader) -> TCoordinate +abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.CreatePolyline(System.ReadOnlySpan polyline) -> TPolyline +abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.Write(TCoordinate item, ref PolylineAlgorithm.Internal.PolylineWriter writer) -> void PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.AbstractPolylineDecoder() -> void PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.AbstractPolylineDecoder(PolylineAlgorithm.PolylineEncodingOptions! options) -> void PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.Decode(TPolyline polyline, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Generic.IEnumerable! PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.Options.get -> PolylineAlgorithm.PolylineEncodingOptions! PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.Encode(System.ReadOnlySpan coordinates, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> TPolyline -PolylineAlgorithm.Abstraction.IPolylineReader -PolylineAlgorithm.Abstraction.IPolylineReader.Read() -> double -PolylineAlgorithm.Abstraction.IPolylineWriter -PolylineAlgorithm.Abstraction.IPolylineWriter.Write(double value) -> void +PolylineAlgorithm.Internal.PolylineReader +PolylineAlgorithm.Internal.PolylineReader.Read() -> double +PolylineAlgorithm.Internal.PolylineWriter +PolylineAlgorithm.Internal.PolylineWriter.Write(double value) -> void PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException() -> void PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException(string! message, System.Exception! innerException) -> void static PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(int delta) -> int diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs index d7370587..9b4da18f 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs @@ -6,6 +6,7 @@ namespace PolylineAlgorithm.Tests.Abstraction; using PolylineAlgorithm.Abstraction; +using PolylineAlgorithm.Internal; using PolylineAlgorithm.Utility; using System; using System.Collections.Generic; @@ -17,7 +18,7 @@ namespace PolylineAlgorithm.Tests.Abstraction; public sealed class AbstractPolylineDecoderTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) Read(IPolylineReader reader) => + protected override (double Latitude, double Longitude) Read(PolylineReader reader) => (reader.Read(), reader.Read()); } @@ -26,7 +27,7 @@ public TestStringDecoderWithOptions(PolylineEncodingOptions options) : base(options) { } protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) Read(IPolylineReader reader) => + protected override (double Latitude, double Longitude) Read(PolylineReader reader) => (reader.Read(), reader.Read()); } diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs index 6d2bcabc..c4e71168 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs @@ -6,6 +6,7 @@ namespace PolylineAlgorithm.Tests.Abstraction; using PolylineAlgorithm.Abstraction; +using PolylineAlgorithm.Internal; using PolylineAlgorithm.Utility; using System; @@ -21,8 +22,8 @@ public TestStringEncoder() public TestStringEncoder(PolylineEncodingOptions options) : base(options) { } - protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override void Write((double Latitude, double Longitude) item, IPolylineWriter writer) { + protected override string CreatePolyline(ReadOnlySpan polyline) => polyline.ToString(); + protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer) { writer.Write(item.Latitude); writer.Write(item.Longitude); } diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs index 8af53e0a..f23b52f4 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs @@ -7,6 +7,7 @@ namespace PolylineAlgorithm.Tests.Extensions; using PolylineAlgorithm.Abstraction; using PolylineAlgorithm.Extensions; +using PolylineAlgorithm.Internal; using PolylineAlgorithm.Utility; using System; using System.Collections.Generic; @@ -18,13 +19,13 @@ namespace PolylineAlgorithm.Tests.Extensions; public sealed class PolylineDecoderExtensionsTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) Read(IPolylineReader reader) => + protected override (double Latitude, double Longitude) Read(PolylineReader reader) => (reader.Read(), reader.Read()); } private sealed class TestMemoryDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) => polyline; - protected override (double Latitude, double Longitude) Read(IPolylineReader reader) => + protected override (double Latitude, double Longitude) Read(PolylineReader reader) => (reader.Read(), reader.Read()); } diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs index 6a3431bf..c790facb 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs @@ -7,6 +7,7 @@ namespace PolylineAlgorithm.Tests.Extensions; using PolylineAlgorithm.Abstraction; using PolylineAlgorithm.Extensions; +using PolylineAlgorithm.Internal; using PolylineAlgorithm.Utility; using System; using System.Collections.Generic; @@ -17,8 +18,8 @@ namespace PolylineAlgorithm.Tests.Extensions; [TestClass] public sealed class PolylineEncoderExtensionsTests { private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); - protected override void Write((double Latitude, double Longitude) item, IPolylineWriter writer) { + protected override string CreatePolyline(ReadOnlySpan polyline) => polyline.ToString(); + protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer) { writer.Write(item.Latitude); writer.Write(item.Longitude); } diff --git a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs index e42f42b3..a4fd09e8 100644 --- a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs +++ b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs @@ -6,6 +6,7 @@ namespace PolylineAlgorithm.Utility; using PolylineAlgorithm.Abstraction; +using PolylineAlgorithm.Internal; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -105,11 +106,11 @@ private readonly struct PolylineCoordinateCollectionPair(IEnumerable<(double Lat private sealed class PolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - protected override string CreatePolyline(ReadOnlyMemory polyline) { + protected override string CreatePolyline(ReadOnlySpan polyline) { return polyline.ToString(); } - protected override void Write((double Latitude, double Longitude) item, IPolylineWriter writer) { + protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer) { writer.Write(item.Latitude); writer.Write(item.Longitude); } From 9f4b27869d95b4a8209657a463f45e088ceda8af Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 08:27:22 +0000 Subject: [PATCH 18/24] docs: update README code examples after IPolylineWriter/IPolylineReader removal Agent-Logs-Url: https://github.com/petesramek/polyline-algorithm-csharp/sessions/8085d58f-4c97-4a7a-a577-f078ff234b2a Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com> --- src/PolylineAlgorithm/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/PolylineAlgorithm/README.md b/src/PolylineAlgorithm/README.md index b049bb26..25e070ff 100644 --- a/src/PolylineAlgorithm/README.md +++ b/src/PolylineAlgorithm/README.md @@ -38,13 +38,14 @@ The library provides abstract base classes to build your own encoder and decoder ```csharp using PolylineAlgorithm; using PolylineAlgorithm.Abstraction; +using PolylineAlgorithm.Internal; public sealed class MyPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - protected override void Write((double Latitude, double Longitude) item, IPolylineWriter writer) { + protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer) { writer.Write(item.Latitude); // field 0 writer.Write(item.Longitude); // field 1 } - protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString(); + protected override string CreatePolyline(ReadOnlySpan polyline) => polyline.ToString(); } ``` @@ -71,9 +72,10 @@ Console.WriteLine(encoded); ```csharp using PolylineAlgorithm; using PolylineAlgorithm.Abstraction; +using PolylineAlgorithm.Internal; public sealed class MyPolylineDecoder : AbstractPolylineDecoder { - protected override (double Latitude, double Longitude) Read(IPolylineReader reader) => + protected override (double Latitude, double Longitude) Read(PolylineReader reader) => (reader.Read(), reader.Read()); // field 0, field 1 protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); } From 6ccf62472149307e47c239decee2f0504ac4aa4f Mon Sep 17 00:00:00 2001 From: Pete Sramek <2333452+petesramek@users.noreply.github.com> Date: Mon, 6 Apr 2026 15:17:19 +0200 Subject: [PATCH 19/24] refactored --- .../PolylineDecoderBenchmark.cs | 15 +++- .../PolylineEncoderBenchmark.cs | 7 +- .../NetTopologyPolylineDecoder.cs | 7 +- .../NetTopologyPolylineEncoder.cs | 7 +- .../Abstraction/AbstractPolylineDecoder.cs | 5 +- .../Abstraction/AbstractPolylineEncoder.cs | 3 +- .../Internal/PolylineReader.cs | 31 ++----- .../Internal/PolylineWriter.cs | 32 ++------ .../PolylineAlgorithm.csproj | 1 + src/PolylineAlgorithm/PolylineEncoding.cs | 81 +++++++++++-------- src/PolylineAlgorithm/PublicAPI.Unshipped.txt | 21 ----- .../AbstractPolylineDecoderTests.cs | 9 ++- .../AbstractPolylineEncoderTests.cs | 7 +- .../PolylineDecoderExtensionsTests.cs | 10 ++- .../PolylineEncoderExtensionsTests.cs | 7 +- .../RandomValueProvider.cs | 6 +- 16 files changed, 120 insertions(+), 129 deletions(-) diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs index 6ef207b7..0ccddb52 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs @@ -94,8 +94,11 @@ public void PolylineDecoder_Decode_Memory() { } private sealed class StringPolylineDecoder : AbstractPolylineDecoder { + private int _latitudeState; + private int _longitudeState; + protected override (double Latitude, double Longitude) Read(PolylineReader reader) => - (reader.Read(), reader.Read()); + (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { return polyline?.AsMemory() ?? Memory.Empty; @@ -103,8 +106,11 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { } private sealed class CharArrayPolylineDecoder : AbstractPolylineDecoder { + private int _latitudeState; + private int _longitudeState; + protected override (double Latitude, double Longitude) Read(PolylineReader reader) => - (reader.Read(), reader.Read()); + (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) { return polyline?.AsMemory() ?? Memory.Empty; @@ -112,8 +118,11 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) { } private sealed class MemoryCharPolylineDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { + private int _latitudeState; + private int _longitudeState; + protected override (double Latitude, double Longitude) Read(PolylineReader reader) => - (reader.Read(), reader.Read()); + (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) { return polyline; diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs index fee56005..9a6ef87c 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs @@ -86,10 +86,13 @@ public void PolylineEncoder_Encode_List() { } private sealed class StringPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { + private int _latitudeState; + private int _longitudeState; + protected override string CreatePolyline(ReadOnlySpan polyline) => polyline.ToString(); protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer) { - writer.Write(item.Latitude); - writer.Write(item.Longitude); + writer.Write(item.Latitude, ref _latitudeState); + writer.Write(item.Longitude, ref _longitudeState); } } } diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs index e6e8ae42..956b846b 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs @@ -14,6 +14,9 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; /// Polyline decoder using NetTopologySuite. ///
internal sealed class NetTopologyPolylineDecoder : AbstractPolylineDecoder { + private int _latitudeState; + private int _longitudeState; + /// /// Converts polyline string to read-only memory. /// @@ -29,8 +32,8 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { /// The reader provided by the engine. Field 0 = latitude, field 1 = longitude. /// Point instance. protected override Point Read(PolylineReader reader) { - double latitude = reader.Read(); - double longitude = reader.Read(); + double latitude = reader.Read(ref _latitudeState); + double longitude = reader.Read(ref _longitudeState); // NetTopologySuite Point: x = longitude, y = latitude return new Point(longitude, latitude); diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs index 0310ebad..c98d706c 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs @@ -14,6 +14,9 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; /// Polyline encoder using NetTopologySuite's Point type. ///
internal sealed class NetTopologyPolylineEncoder : AbstractPolylineEncoder { + private int _latitudeState; + private int _longitudeState; + /// /// Creates encoded polyline string from span. /// @@ -36,7 +39,7 @@ protected override void Write(Point item, ref PolylineWriter writer) { ArgumentNullException.ThrowIfNull(item); // NetTopologySuite Point: Y = latitude, X = longitude - writer.Write(item.Y); - writer.Write(item.X); + writer.Write(item.Y, ref _latitudeState); + writer.Write(item.X, ref _longitudeState); } } \ No newline at end of file diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs index 61b5c77f..debacb4d 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs @@ -1,4 +1,4 @@ -// +// // Copyright © Pete Sramek. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for full license information. // @@ -96,10 +96,9 @@ public IEnumerable Decode(TPolyline polyline, CancellationToken can while (!reader.IsEmpty) { cancellationToken.ThrowIfCancellationRequested(); - reader.BeginItem(); TCoordinate item = Read(reader); - _logger?.LogDecodedItemDebug(reader.SlotIndex, reader.Position); + //_logger?.LogDecodedItemDebug(reader.SlotIndex, reader.Position); yield return item; } diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs index 33cfaa7b..8d45408c 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs @@ -1,4 +1,4 @@ -// +// // Copyright © Pete Sramek. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for full license information. // @@ -105,7 +105,6 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken for (var i = 0; i < coordinates.Length; i++) { cancellationToken.ThrowIfCancellationRequested(); - writer.BeginItem(); Write(coordinates[i], ref writer); } diff --git a/src/PolylineAlgorithm/Internal/PolylineReader.cs b/src/PolylineAlgorithm/Internal/PolylineReader.cs index 0447feda..8002f67c 100644 --- a/src/PolylineAlgorithm/Internal/PolylineReader.cs +++ b/src/PolylineAlgorithm/Internal/PolylineReader.cs @@ -1,4 +1,4 @@ -// +// // Copyright © Pete Sramek. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for full license information. // @@ -20,15 +20,11 @@ namespace PolylineAlgorithm.Internal; public sealed class PolylineReader { private readonly ReadOnlyMemory _sequence; private int _position; - private int[] _accumulated; - private int _slotIndex; private readonly uint _precision; internal PolylineReader(ReadOnlyMemory sequence, uint precision) { _sequence = sequence; _precision = precision; - _accumulated = []; - _slotIndex = 0; _position = 0; } @@ -38,33 +34,16 @@ internal PolylineReader(ReadOnlyMemory sequence, uint precision) { /// /// Thrown when the data runs out before the formatter has finished reading an item's fields. /// - public double Read() { - // Grow the per-slot accumulator array on the first item (field discovery). - if (_slotIndex >= _accumulated.Length) { - Array.Resize(ref _accumulated, _slotIndex + 1); - } - - if (!PolylineEncoding.TryReadValue(ref _accumulated[_slotIndex], _sequence, ref _position)) { + public double Read(ref int state) { + if (!PolylineEncoding.TryReadValue(ref state, _sequence, ref _position)) { ExceptionGuard.ThrowInvalidPolylineFormat(_position); } - double result = PolylineEncoding.Denormalize(_accumulated[_slotIndex], _precision); - _slotIndex++; + double result = PolylineEncoding.Denormalize(state, _precision); + return result; } - /// - /// Resets the intra-item slot index so that delta accumulation is applied to the correct field slot - /// on the next item. Must be called by the engine before each call to the formatter's Read method. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void BeginItem() => _slotIndex = 0; - - /// - /// Gets the number of fields read in the current (or most recently completed) item. - /// - internal int SlotIndex => _slotIndex; - /// /// Gets the current character position in the encoded sequence. /// diff --git a/src/PolylineAlgorithm/Internal/PolylineWriter.cs b/src/PolylineAlgorithm/Internal/PolylineWriter.cs index f64fe21d..523d4d47 100644 --- a/src/PolylineAlgorithm/Internal/PolylineWriter.cs +++ b/src/PolylineAlgorithm/Internal/PolylineWriter.cs @@ -1,4 +1,4 @@ -// +// // Copyright © Pete Sramek. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for full license information. // @@ -23,48 +23,28 @@ public ref struct PolylineWriter { private Span _buffer; private int _position; private readonly uint _precision; - private int[] _previous; - private int _slotIndex; internal PolylineWriter(Span buffer, uint precision) { _buffer = buffer; _precision = precision; - _previous = []; - _slotIndex = 0; _position = 0; } /// /// Emits one field value into the encoding pipeline. /// - public void Write(double value) { - // Grow the per-slot delta array on the first item (field discovery). - if (_slotIndex >= _previous.Length) { - Array.Resize(ref _previous, _slotIndex + 1); - } - + public void Write(double value, ref int state) { int normalized = PolylineEncoding.Normalize(value, _precision); - int delta = normalized - _previous[_slotIndex]; - _previous[_slotIndex] = normalized; - _slotIndex++; + + int delta = normalized - state; + + state = normalized; if (!PolylineEncoding.TryWriteValue(delta, _buffer, ref _position)) { ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer(); } } - /// - /// Resets the intra-item slot index so delta state is applied to the correct field on the next item. - /// Must be called by the engine before each call to the formatter's Write method. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void BeginItem() => _slotIndex = 0; - - /// - /// Gets the number of fields written in the current (or most recently completed) item. - /// - internal int SlotIndex => _slotIndex; - /// /// Returns the encoded polyline characters written so far. /// diff --git a/src/PolylineAlgorithm/PolylineAlgorithm.csproj b/src/PolylineAlgorithm/PolylineAlgorithm.csproj index 907a2a15..5d6777d8 100644 --- a/src/PolylineAlgorithm/PolylineAlgorithm.csproj +++ b/src/PolylineAlgorithm/PolylineAlgorithm.csproj @@ -2,6 +2,7 @@ netstandard2.1 + true diff --git a/src/PolylineAlgorithm/PolylineEncoding.cs b/src/PolylineAlgorithm/PolylineEncoding.cs index 3d6de5e7..afc55b08 100644 --- a/src/PolylineAlgorithm/PolylineEncoding.cs +++ b/src/PolylineAlgorithm/PolylineEncoding.cs @@ -10,6 +10,7 @@ namespace PolylineAlgorithm; using System; using System.Numerics; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; /// @@ -389,35 +390,43 @@ public static void ValidateFormat(ReadOnlySpan polyline) { /// /// Thrown when an invalid character is found in the polyline segment. /// - public static void ValidateCharRange(ReadOnlySpan polyline) { + public static unsafe void ValidateCharRange(ReadOnlySpan polyline) { int length = polyline.Length; - int vectorSize = Vector.Count; - - int i = 0; - for (; i <= length - vectorSize; i += vectorSize) { - var span = MemoryMarshal.Cast(polyline.Slice(i, vectorSize)); -#if NET5_0_OR_GREATER - var chars = new Vector(span); -#else - var chars = new Vector(span.ToArray()); -#endif - var belowMin = Vector.LessThan(chars, MinVector); - var aboveMax = Vector.GreaterThan(chars, MaxVector); - if (Vector.BitwiseOr(belowMin, aboveMax) != Vector.Zero) { - // Fallback to scalar check for this block - for (int j = 0; j < vectorSize; j++) { - char character = polyline[i + j]; - if (character < Min || character > Max) { - ExceptionGuard.ThrowInvalidPolylineCharacter(character, i + j); + int vecSize = Vector.Count; + + fixed (char* p = polyline) { + ushort* up = (ushort*)p; + + int i = 0; + + // SIMD loop + for (; i <= length - vecSize; i += vecSize) { + // Load vector directly without allocations + var vec = Unsafe.Read>(up + i); + + var belowMin = Vector.LessThan(vec, MinVector); + var aboveMax = Vector.GreaterThan(vec, MaxVector); + + var invalid = Vector.BitwiseOr(belowMin, aboveMax); + + if (!Vector.EqualsAll(invalid, Vector.Zero)) { + // Fallback to scalar for this block + for (int j = 0; j < vecSize; j++) { + ushort ch = up[i + j]; + if (ch < Min || ch > Max) { + ExceptionGuard.ThrowInvalidPolylineCharacter((char)ch, i + j); + } } } } - } - for (; i < length; i++) { - char character = polyline[i]; - if (character < Min || character > Max) { - ExceptionGuard.ThrowInvalidPolylineCharacter(character, i); + // Tail + for (; i < length; i++) { + ushort ch = up[i]; + + if (ch < Min || ch > Max) { + ExceptionGuard.ThrowInvalidPolylineCharacter((char)ch, i); + } } } } @@ -436,24 +445,32 @@ public static void ValidateCharRange(ReadOnlySpan polyline) { /// Thrown when a block exceeds 7 characters or the polyline does not end with a valid block terminator. /// public static void ValidateBlockLength(ReadOnlySpan polyline) { + const int MaxBlockLen = Defaults.Polyline.Block.Length.Max; + int blockLen = 0; - bool foundBlockEnd = false; + bool foundEnd = false; for (int i = 0; i < polyline.Length; i++) { blockLen++; - if (polyline[i] < End) { - foundBlockEnd = true; - if (blockLen > Defaults.Polyline.Block.Length.Max) { + if (polyline[i] >= End) { + if (blockLen > MaxBlockLen) { ExceptionGuard.ThrowPolylineBlockTooLong(i - blockLen + 1); } - blockLen = 0; - } else { - foundBlockEnd = false; + + foundEnd = false; + continue; } + + if (blockLen > MaxBlockLen) { + ExceptionGuard.ThrowPolylineBlockTooLong(i - blockLen + 1); + } + + blockLen = 0; + foundEnd = true; } - if (!foundBlockEnd) { + if (!foundEnd) { ExceptionGuard.ThrowInvalidPolylineBlockTerminator(); } } diff --git a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt index 02d5732d..7dc5c581 100644 --- a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt +++ b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt @@ -1,22 +1 @@ #nullable enable -abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.GetReadOnlyMemory(in TPolyline polyline) -> System.ReadOnlyMemory -abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.Read(PolylineAlgorithm.Internal.PolylineReader! reader) -> TCoordinate -abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.CreatePolyline(System.ReadOnlySpan polyline) -> TPolyline -abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.Write(TCoordinate item, ref PolylineAlgorithm.Internal.PolylineWriter writer) -> void -PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.AbstractPolylineDecoder() -> void -PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.AbstractPolylineDecoder(PolylineAlgorithm.PolylineEncodingOptions! options) -> void -PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.Decode(TPolyline polyline, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Generic.IEnumerable! -PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.Options.get -> PolylineAlgorithm.PolylineEncodingOptions! -PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.Encode(System.ReadOnlySpan coordinates, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> TPolyline -PolylineAlgorithm.Internal.PolylineReader -PolylineAlgorithm.Internal.PolylineReader.Read() -> double -PolylineAlgorithm.Internal.PolylineWriter -PolylineAlgorithm.Internal.PolylineWriter.Write(double value) -> void -PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException() -> void -PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException(string! message, System.Exception! innerException) -> void -static PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(int delta) -> int -static PolylineAlgorithm.PolylineEncoding.TryWriteValue(int delta, System.Span buffer, ref int position) -> bool -static PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan polyline) -> void -static PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan polyline) -> void -static PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan polyline) -> void -virtual PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValidateFormat(System.ReadOnlyMemory sequence, Microsoft.Extensions.Logging.ILogger? logger) -> void diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs index 9b4da18f..9197551b 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs @@ -17,18 +17,23 @@ namespace PolylineAlgorithm.Tests.Abstraction; [TestClass] public sealed class AbstractPolylineDecoderTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { + private int _latitudeState; + private int _longitudeState; protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); protected override (double Latitude, double Longitude) Read(PolylineReader reader) => - (reader.Read(), reader.Read()); + (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); } private sealed class TestStringDecoderWithOptions : AbstractPolylineDecoder { + private int _latitudeState; + private int _longitudeState; + public TestStringDecoderWithOptions(PolylineEncodingOptions options) : base(options) { } protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); protected override (double Latitude, double Longitude) Read(PolylineReader reader) => - (reader.Read(), reader.Read()); + (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); } /// diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs index c4e71168..0edb1206 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs @@ -16,6 +16,9 @@ namespace PolylineAlgorithm.Tests.Abstraction; [TestClass] public sealed class AbstractPolylineEncoderTests { private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { + private int _latitudeState; + private int _longitudeState; + public TestStringEncoder() : base() { } @@ -24,8 +27,8 @@ public TestStringEncoder(PolylineEncodingOptions options) protected override string CreatePolyline(ReadOnlySpan polyline) => polyline.ToString(); protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer) { - writer.Write(item.Latitude); - writer.Write(item.Longitude); + writer.Write(item.Latitude, ref _latitudeState); + writer.Write(item.Longitude, ref _longitudeState); } } diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs index f23b52f4..2e501fe3 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs @@ -18,15 +18,21 @@ namespace PolylineAlgorithm.Tests.Extensions; [TestClass] public sealed class PolylineDecoderExtensionsTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { + private int _latitudeState; + private int _longitudeState; + protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); protected override (double Latitude, double Longitude) Read(PolylineReader reader) => - (reader.Read(), reader.Read()); + (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); } private sealed class TestMemoryDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { + private int _latitudeState; + private int _longitudeState; + protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) => polyline; protected override (double Latitude, double Longitude) Read(PolylineReader reader) => - (reader.Read(), reader.Read()); + (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); } // ----- Decode(char[]) for IPolylineDecoder ----- diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs index c790facb..04ec3d2b 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs @@ -18,10 +18,13 @@ namespace PolylineAlgorithm.Tests.Extensions; [TestClass] public sealed class PolylineEncoderExtensionsTests { private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { + private int _latitudeState; + private int _longitudeState; + protected override string CreatePolyline(ReadOnlySpan polyline) => polyline.ToString(); protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer) { - writer.Write(item.Latitude); - writer.Write(item.Longitude); + writer.Write(item.Latitude, ref _latitudeState); + writer.Write(item.Longitude, ref _longitudeState); } } diff --git a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs index a4fd09e8..492329bf 100644 --- a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs +++ b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs @@ -105,14 +105,16 @@ private readonly struct PolylineCoordinateCollectionPair(IEnumerable<(double Lat } private sealed class PolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { + private int _latitudeState; + private int _longitudeState; protected override string CreatePolyline(ReadOnlySpan polyline) { return polyline.ToString(); } protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer) { - writer.Write(item.Latitude); - writer.Write(item.Longitude); + writer.Write(item.Latitude, ref _latitudeState); + writer.Write(item.Longitude, ref _longitudeState); } } } \ No newline at end of file From 6e40c94b3262e9c21ca54d7613b3b3fbd91a0f99 Mon Sep 17 00:00:00 2001 From: Pete Sramek <2333452+petesramek@users.noreply.github.com> Date: Mon, 6 Apr 2026 13:19:28 +0000 Subject: [PATCH 20/24] Updated docs for version 0.0 --- ....Abstraction.AbstractPolylineDecoder-2.yml | 85 ++++++++----------- ....Abstraction.AbstractPolylineEncoder-2.yml | 85 ++++++++----------- ...ylineAlgorithm.Internal.PolylineReader.yml | 76 +++++++++++++++++ ...ylineAlgorithm.Internal.PolylineWriter.yml | 65 ++++++++++++++ .../0.0/PolylineAlgorithm.Internal.yml | 21 +++++ .../PolylineAlgorithm.PolylineEncoding.yml | 18 ++-- ...ylineAlgorithm.PolylineEncodingOptions.yml | 28 +----- ...gorithm.PolylineEncodingOptionsBuilder.yml | 39 ++------- api-reference/0.0/PolylineAlgorithm.yml | 3 + api-reference/0.0/toc.yml | 9 ++ 10 files changed, 264 insertions(+), 165 deletions(-) create mode 100644 api-reference/0.0/PolylineAlgorithm.Internal.PolylineReader.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.Internal.PolylineWriter.yml create mode 100644 api-reference/0.0/PolylineAlgorithm.Internal.yml diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml index f868e1f9..a4d7ae94 100644 --- a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml +++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml @@ -50,9 +50,9 @@ body: url: https://learn.microsoft.com/dotnet/api/system.object.tostring - h2: Remarks - markdown: >- - Derive from this class to implement a decoder for a specific polyline type. Override , + Derive from this class to implement a decoder for a specific polyline type. Override - , and to provide type-specific behavior. + and to provide type-specific behavior. - h2: Constructors - api3: AbstractPolylineDecoder() id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor @@ -97,52 +97,7 @@ body: - type: - text: PolylineEncodingOptions url: PolylineAlgorithm.PolylineEncodingOptions.html -- api3: ValuesPerItem - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_ValuesPerItem - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L206 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValuesPerItem - commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValuesPerItem -- markdown: Gets the number of values decoded per item from the polyline. -- code: protected abstract int ValuesPerItem { get; } -- h4: Property Value -- parameters: - - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 -- h4: Remarks -- markdown: >- - Must be greater than zero. Each item in the decoded output is constructed from this many consecutive - - delta-decoded values. For a standard geographic coordinate pair (latitude + longitude), return 2. - h2: Methods -- api3: CreateItem(ReadOnlyMemory) - id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_CreateItem_System_ReadOnlyMemory_System_Double__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L218 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateItem(System.ReadOnlyMemory{System.Double}) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateItem(System.ReadOnlyMemory{System.Double}) -- markdown: Creates a TCoordinate instance from the specified decoded values. -- code: protected abstract TCoordinate CreateItem(ReadOnlyMemory values) -- h4: Parameters -- parameters: - - name: values - type: - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 - - < - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - - '>' - description: >- - A of containing the decoded values for this item. - - The length equals . Implementations should copy values out rather than store the memory. -- h4: Returns -- parameters: - - type: - - TCoordinate - description: A TCoordinate instance representing the decoded item. - api3: Decode(TPolyline, CancellationToken) id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L81 @@ -195,7 +150,7 @@ body: description: Thrown when cancellationToken is canceled during decoding. - api3: GetReadOnlyMemory(in TPolyline) id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_GetReadOnlyMemory__0__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L196 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L176 metadata: uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@) commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@) @@ -217,9 +172,41 @@ body: url: https://learn.microsoft.com/dotnet/api/system.char - '>' description: A of representing the encoded polyline characters. +- api3: Read(PolylineReader) + id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Read_PolylineAlgorithm_Internal_PolylineReader_ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L195 + metadata: + uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Read(PolylineAlgorithm.Internal.PolylineReader) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Read(PolylineAlgorithm.Internal.PolylineReader) +- markdown: Reads field values from the polyline decoding pipeline and constructs one TCoordinate item. +- code: protected abstract TCoordinate Read(PolylineReader reader) +- h4: Parameters +- parameters: + - name: reader + type: + - text: PolylineReader + url: PolylineAlgorithm.Internal.PolylineReader.html + description: >- + The cursor provided by the engine. Call + + once for each expected field value, in the same order used by the corresponding encoder's + + Write override. +- h4: Returns +- parameters: + - type: + - TCoordinate + description: A TCoordinate instance constructed from the decoded field values. +- h4: Remarks +- markdown: >- + Implementations must always call the same number of times, + + in the same field order, for every item. The number of reads must match the number of writes + + performed by the corresponding encoder's Write override. - api3: ValidateFormat(ReadOnlyMemory, ILogger?) id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_ValidateFormat_System_ReadOnlyMemory_System_Char__Microsoft_Extensions_Logging_ILogger_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L176 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L156 metadata: uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger) commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger) diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml index 39cf4dd4..a421abcd 100644 --- a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml +++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml @@ -58,7 +58,7 @@ body: - markdown: >- Derive from this class to implement an encoder for a specific item and polyline type. Override - , , and to provide type-specific behavior. + , and to provide type-specific behavior. - h2: Constructors - api3: AbstractPolylineEncoder() id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor @@ -103,44 +103,26 @@ body: - type: - text: PolylineEncodingOptions url: PolylineAlgorithm.PolylineEncodingOptions.html -- api3: ValuesPerItem - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_ValuesPerItem - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L196 - metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.ValuesPerItem - commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.ValuesPerItem -- markdown: Gets the number of values extracted from each TCoordinate item during encoding. -- code: protected abstract int ValuesPerItem { get; } -- h4: Property Value -- parameters: - - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 -- h4: Remarks -- markdown: >- - Must be greater than zero. Each value is written as a separate delta-encoded block in the output polyline. - - For a standard geographic coordinate pair (latitude + longitude), return 2. - h2: Methods -- api3: CreatePolyline(ReadOnlyMemory) - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_CreatePolyline_System_ReadOnlyMemory_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L186 +- api3: CreatePolyline(ReadOnlySpan) + id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_CreatePolyline_System_ReadOnlySpan_System_Char__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L143 metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char}) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char}) -- markdown: Creates a polyline instance from the provided read-only sequence of characters. -- code: protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline) + uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlySpan{System.Char}) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlySpan{System.Char}) +- markdown: Creates a polyline instance from the provided read-only span of characters. +- code: protected abstract TPolyline CreatePolyline(ReadOnlySpan polyline) - h4: Parameters - parameters: - name: polyline type: - - text: ReadOnlyMemory - url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1 + - text: ReadOnlySpan + url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1 - < - text: char url: https://learn.microsoft.com/dotnet/api/system.char - '>' - description: A containing the encoded polyline characters. + description: A containing the encoded polyline characters. - h4: Returns - parameters: - type: @@ -153,10 +135,7 @@ body: uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken) - markdown: Encodes a collection of TCoordinate instances into an encoded TPolyline string. -- code: >- - [SuppressMessage("Design", "MA0051:Method is too long", Justification = "Method contains local methods. Actual method only 55 lines.")] - - public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default) +- code: public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default) - h4: Parameters - parameters: - name: coordinates @@ -192,29 +171,37 @@ body: - text: InvalidOperationException url: https://learn.microsoft.com/dotnet/api/system.invalidoperationexception description: Thrown when the internal encoding buffer cannot accommodate the encoded value. -- api3: GetValues(TCoordinate, Span) - id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetValues__0_System_Span_System_Double__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L205 +- api3: Write(TCoordinate, ref PolylineWriter) + id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Write__0_PolylineAlgorithm_Internal_PolylineWriter__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L160 metadata: - uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetValues(`0,System.Span{System.Double}) - commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetValues(`0,System.Span{System.Double}) -- markdown: Extracts the encoded values from the specified item into the provided span. -- code: protected abstract void GetValues(TCoordinate item, Span values) + uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Write(`0,PolylineAlgorithm.Internal.PolylineWriter@) + commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Write(`0,PolylineAlgorithm.Internal.PolylineWriter@) +- markdown: Writes the field values of the specified item into the polyline encoding pipeline. +- code: protected abstract void Write(TCoordinate item, ref PolylineWriter writer) - h4: Parameters - parameters: - name: item type: - TCoordinate - description: The item from which to extract values. - - name: values + description: The item whose field values are to be encoded. + - name: writer type: - - text: Span - url: https://learn.microsoft.com/dotnet/api/system.span-1 - - < - - text: double - url: https://learn.microsoft.com/dotnet/api/system.double - - '>' - description: A span that receives the extracted values. Its length equals . + - text: PolylineWriter + url: PolylineAlgorithm.Internal.PolylineWriter.html + description: >- + The cursor provided by the engine. Call + + once for each field value, in a fixed, consistent order. The engine handles delta computation, + + zigzag encoding, and output buffering. +- h4: Remarks +- markdown: >- + Implementations must always call the same number of times, + + in the same field order, for every item. The corresponding Read override must + + call the same number of times in the same order. languageId: csharp metadata: description: Provides a base implementation for encoding sequences of items into encoded polyline strings. diff --git a/api-reference/0.0/PolylineAlgorithm.Internal.PolylineReader.yml b/api-reference/0.0/PolylineAlgorithm.Internal.PolylineReader.yml new file mode 100644 index 00000000..a9b1b374 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Internal.PolylineReader.yml @@ -0,0 +1,76 @@ +### YamlMime:ApiPage +title: Class PolylineReader +body: +- api1: Class PolylineReader + id: PolylineAlgorithm_Internal_PolylineReader + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Internal/PolylineReader.cs#L20 + metadata: + uid: PolylineAlgorithm.Internal.PolylineReader + commentId: T:PolylineAlgorithm.Internal.PolylineReader +- facts: + - name: Namespace + value: + text: PolylineAlgorithm.Internal + url: PolylineAlgorithm.Internal.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: Engine-owned stateful cursor that delivers decoded field values to a formatter during polyline decoding. +- code: public sealed class PolylineReader +- h4: Inheritance +- inheritance: + - text: object + url: https://learn.microsoft.com/dotnet/api/system.object + - text: PolylineReader + url: PolylineAlgorithm.Internal.PolylineReader.html +- h4: Inherited Members +- list: + - text: object.Equals(object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - text: object.Equals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - text: object.GetHashCode() + url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - text: object.GetType() + url: https://learn.microsoft.com/dotnet/api/system.object.gettype + - text: object.ReferenceEquals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - text: object.ToString() + url: https://learn.microsoft.com/dotnet/api/system.object.tostring +- h2: Remarks +- markdown: >- + The reader wraps the raw encoded character sequence and applies the full decoding pipeline + + (ASCII shift reversal, un-zigzag, per-slot delta accumulation) on each call. + + The engine calls BeginItem before invoking the formatter for each item so that the + + slot index resets correctly while delta state is preserved across item boundaries. +- h2: Methods +- api3: Read(ref int) + id: PolylineAlgorithm_Internal_PolylineReader_Read_System_Int32__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Internal/PolylineReader.cs#L37 + metadata: + uid: PolylineAlgorithm.Internal.PolylineReader.Read(System.Int32@) + commentId: M:PolylineAlgorithm.Internal.PolylineReader.Read(System.Int32@) +- markdown: Reads and returns the next decoded field value from the polyline sequence. +- code: public double Read(ref int state) +- h4: Parameters +- parameters: + - name: state + type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 +- h4: Returns +- parameters: + - type: + - text: double + url: https://learn.microsoft.com/dotnet/api/system.double +- h4: Exceptions +- parameters: + - type: + - text: InvalidPolylineException + url: PolylineAlgorithm.InvalidPolylineException.html + description: Thrown when the data runs out before the formatter has finished reading an item's fields. +languageId: csharp +metadata: + description: Engine-owned stateful cursor that delivers decoded field values to a formatter during polyline decoding. diff --git a/api-reference/0.0/PolylineAlgorithm.Internal.PolylineWriter.yml b/api-reference/0.0/PolylineAlgorithm.Internal.PolylineWriter.yml new file mode 100644 index 00000000..4e887b40 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Internal.PolylineWriter.yml @@ -0,0 +1,65 @@ +### YamlMime:ApiPage +title: Struct PolylineWriter +body: +- api1: Struct PolylineWriter + id: PolylineAlgorithm_Internal_PolylineWriter + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Internal/PolylineWriter.cs#L22 + metadata: + uid: PolylineAlgorithm.Internal.PolylineWriter + commentId: T:PolylineAlgorithm.Internal.PolylineWriter +- facts: + - name: Namespace + value: + text: PolylineAlgorithm.Internal + url: PolylineAlgorithm.Internal.html + - name: Assembly + value: PolylineAlgorithm.dll +- markdown: Engine-owned stateful cursor that feeds values written by a formatter into the polyline encoding pipeline. +- code: public ref struct PolylineWriter +- h4: Inherited Members +- list: + - text: object.Equals(object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object) + - text: object.Equals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object) + - text: object.GetHashCode() + url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode + - text: object.GetType() + url: https://learn.microsoft.com/dotnet/api/system.object.gettype + - text: object.ReferenceEquals(object, object) + url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals + - text: object.ToString() + url: https://learn.microsoft.com/dotnet/api/system.object.tostring +- h2: Remarks +- markdown: >- + Each instance wraps a caller-provided buffer sized to the worst-case maximum + + capacity so that the buffer never needs to grow. The buffer may be stack-allocated or rented from + + ; the engine calls BeginItem before + + invoking the formatter for each item so that the slot index resets correctly while delta state is + + preserved across item boundaries. +- h2: Methods +- api3: Write(double, ref int) + id: PolylineAlgorithm_Internal_PolylineWriter_Write_System_Double_System_Int32__ + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Internal/PolylineWriter.cs#L36 + metadata: + uid: PolylineAlgorithm.Internal.PolylineWriter.Write(System.Double,System.Int32@) + commentId: M:PolylineAlgorithm.Internal.PolylineWriter.Write(System.Double,System.Int32@) +- markdown: Emits one field value into the encoding pipeline. +- code: public void Write(double value, ref int state) +- h4: Parameters +- parameters: + - name: value + type: + - text: double + url: https://learn.microsoft.com/dotnet/api/system.double + - name: state + type: + - text: int + url: https://learn.microsoft.com/dotnet/api/system.int32 +languageId: csharp +metadata: + description: Engine-owned stateful cursor that feeds values written by a formatter into the polyline encoding pipeline. diff --git a/api-reference/0.0/PolylineAlgorithm.Internal.yml b/api-reference/0.0/PolylineAlgorithm.Internal.yml new file mode 100644 index 00000000..375a8e20 --- /dev/null +++ b/api-reference/0.0/PolylineAlgorithm.Internal.yml @@ -0,0 +1,21 @@ +### YamlMime:ApiPage +title: Namespace PolylineAlgorithm.Internal +body: +- api1: Namespace PolylineAlgorithm.Internal + id: PolylineAlgorithm_Internal + metadata: + uid: PolylineAlgorithm.Internal + commentId: N:PolylineAlgorithm.Internal +- h3: Classes +- parameters: + - type: + text: PolylineReader + url: PolylineAlgorithm.Internal.PolylineReader.html + description: Engine-owned stateful cursor that delivers decoded field values to a formatter during polyline decoding. +- h3: Structs +- parameters: + - type: + text: PolylineWriter + url: PolylineAlgorithm.Internal.PolylineWriter.html + description: Engine-owned stateful cursor that feeds values written by a formatter into the polyline encoding pipeline. +languageId: csharp diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml index 56818e4c..edd67e7b 100644 --- a/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml +++ b/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml @@ -3,7 +3,7 @@ title: Class PolylineEncoding body: - api1: Class PolylineEncoding id: PolylineAlgorithm_PolylineEncoding - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L23 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L24 metadata: uid: PolylineAlgorithm.PolylineEncoding commentId: T:PolylineAlgorithm.PolylineEncoding @@ -50,7 +50,7 @@ body: - h2: Methods - api3: Denormalize(int, uint) id: PolylineAlgorithm_PolylineEncoding_Denormalize_System_Int32_System_UInt32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L122 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L123 metadata: uid: PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32) commentId: M:PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32) @@ -117,7 +117,7 @@ body: description: Thrown if the arithmetic operation overflows during conversion. - api3: GetRequiredBufferSize(int) id: PolylineAlgorithm_PolylineEncoding_GetRequiredBufferSize_System_Int32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L298 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L299 metadata: uid: PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32) commentId: M:PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32) @@ -200,7 +200,7 @@ body: - ) - api3: Normalize(double, uint) id: PolylineAlgorithm_PolylineEncoding_Normalize_System_Double_System_UInt32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L61 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L62 metadata: uid: PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32) commentId: M:PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32) @@ -268,7 +268,7 @@ body: description: Thrown when the normalized result exceeds the range of a 32-bit signed integer during the conversion from double to int. - api3: TryReadValue(ref int, ReadOnlyMemory, ref int) id: PolylineAlgorithm_PolylineEncoding_TryReadValue_System_Int32__System_ReadOnlyMemory_System_Char__System_Int32__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L169 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L170 metadata: uid: PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@) commentId: M:PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@) @@ -328,7 +328,7 @@ body:

- api3: TryWriteValue(int, Span, ref int) id: PolylineAlgorithm_PolylineEncoding_TryWriteValue_System_Int32_System_Span_System_Char__System_Int32__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L237 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L238 metadata: uid: PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@) commentId: M:PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@) @@ -407,7 +407,7 @@ body:

- api3: ValidateBlockLength(ReadOnlySpan) id: PolylineAlgorithm_PolylineEncoding_ValidateBlockLength_System_ReadOnlySpan_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L438 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L447 metadata: uid: PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char}) commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char}) @@ -441,7 +441,7 @@ body: description: Thrown when a block exceeds 7 characters or the polyline does not end with a valid block terminator. - api3: ValidateCharRange(ReadOnlySpan) id: PolylineAlgorithm_PolylineEncoding_ValidateCharRange_System_ReadOnlySpan_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L392 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L393 metadata: uid: PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char}) commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char}) @@ -479,7 +479,7 @@ body: description: Thrown when an invalid character is found in the polyline segment. - api3: ValidateFormat(ReadOnlySpan) id: PolylineAlgorithm_PolylineEncoding_ValidateFormat_System_ReadOnlySpan_System_Char__ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L370 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L371 metadata: uid: PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char}) commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char}) diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml index 90dc279b..16977870 100644 --- a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml +++ b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml @@ -3,7 +3,7 @@ title: Class PolylineEncodingOptions body: - api1: Class PolylineEncodingOptions id: PolylineAlgorithm_PolylineEncodingOptions - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L29 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L28 metadata: uid: PolylineAlgorithm.PolylineEncodingOptions commentId: T:PolylineAlgorithm.PolylineEncodingOptions @@ -44,7 +44,7 @@ body:

-
  • The level for coordinate encoding
  • The for memory allocation strategy
  • The for diagnostic logging
+
  • The level for coordinate encoding
  • The for diagnostic logging

@@ -54,7 +54,7 @@ body: - h2: Properties - api3: LoggerFactory id: PolylineAlgorithm_PolylineEncodingOptions_LoggerFactory - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L41 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L40 metadata: uid: PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory commentId: P:PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory @@ -72,7 +72,7 @@ body: To enable logging, provide a custom implementation. - api3: Precision id: PolylineAlgorithm_PolylineEncodingOptions_Precision - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L60 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L59 metadata: uid: PolylineAlgorithm.PolylineEncodingOptions.Precision commentId: P:PolylineAlgorithm.PolylineEncodingOptions.Precision @@ -102,26 +102,6 @@ body: the granularity of the encoded values.

-- api3: StackAllocLimit - id: PolylineAlgorithm_PolylineEncodingOptions_StackAllocLimit - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L73 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit - commentId: P:PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit -- markdown: Gets the maximum buffer size (in characters) that can be allocated on the stack for encoding operations. -- code: public int StackAllocLimit { get; } -- h4: Property Value -- parameters: - - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 -- h4: Remarks -- markdown: >- - When the required buffer size for encoding exceeds this limit, memory will be allocated on the heap instead of the stack. - - This setting specifically applies to stack allocation of character arrays (stackalloc char[]) used during polyline encoding, - - balancing performance and stack safety. languageId: csharp metadata: description: Provides configuration options for polyline encoding operations. diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml index 2c959bdb..c6c9ead4 100644 --- a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml +++ b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml @@ -3,7 +3,7 @@ title: Class PolylineEncodingOptionsBuilder body: - api1: Class PolylineEncodingOptionsBuilder id: PolylineAlgorithm_PolylineEncodingOptionsBuilder - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L15 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L14 metadata: uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder commentId: T:PolylineAlgorithm.PolylineEncodingOptionsBuilder @@ -39,7 +39,7 @@ body: - h2: Methods - api3: Build() id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Build - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L38 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L36 metadata: uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build @@ -53,7 +53,7 @@ body: description: A configured instance. - api3: Create() id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Create - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L28 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L26 metadata: uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create @@ -67,7 +67,7 @@ body: description: An instance for configuring polyline encoding options. - api3: WithLoggerFactory(ILoggerFactory) id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithLoggerFactory_Microsoft_Extensions_Logging_ILoggerFactory_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L97 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L67 metadata: uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory) commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory) @@ -88,7 +88,7 @@ body: description: The current instance for method chaining. - api3: WithPrecision(uint) id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithPrecision_System_UInt32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L82 + src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L52 metadata: uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32) commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32) @@ -107,35 +107,6 @@ body: - text: PolylineEncodingOptionsBuilder url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html description: The current instance for method chaining. -- api3: WithStackAllocLimit(int) - id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithStackAllocLimit_System_Int32_ - src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L61 - metadata: - uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32) - commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32) -- markdown: Configures the buffer size used for stack allocation during polyline encoding operations. -- code: public PolylineEncodingOptionsBuilder WithStackAllocLimit(int stackAllocLimit) -- h4: Parameters -- parameters: - - name: stackAllocLimit - type: - - text: int - url: https://learn.microsoft.com/dotnet/api/system.int32 - description: The maximum buffer size to use for stack allocation. Must be greater than or equal to 1. -- h4: Returns -- parameters: - - type: - - text: PolylineEncodingOptionsBuilder - url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html - description: The current instance for method chaining. -- h4: Remarks -- markdown: This method allows customization of the internal buffer size for encoding, which can impact performance and memory usage. -- h4: Exceptions -- parameters: - - type: - - text: ArgumentOutOfRangeException - url: https://learn.microsoft.com/dotnet/api/system.argumentoutofrangeexception - description: Thrown if stackAllocLimit is less than 1. languageId: csharp metadata: description: Provides a builder for configuring options for polyline encoding operations. diff --git a/api-reference/0.0/PolylineAlgorithm.yml b/api-reference/0.0/PolylineAlgorithm.yml index b60dc3c0..d6c5bba7 100644 --- a/api-reference/0.0/PolylineAlgorithm.yml +++ b/api-reference/0.0/PolylineAlgorithm.yml @@ -14,6 +14,9 @@ body: - type: text: PolylineAlgorithm.Extensions url: PolylineAlgorithm.Extensions.html + - type: + text: PolylineAlgorithm.Internal + url: PolylineAlgorithm.Internal.html - h3: Classes - parameters: - type: diff --git a/api-reference/0.0/toc.yml b/api-reference/0.0/toc.yml index d1ffc58a..051163d6 100644 --- a/api-reference/0.0/toc.yml +++ b/api-reference/0.0/toc.yml @@ -32,3 +32,12 @@ href: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml - name: PolylineEncoderExtensions href: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml +- name: PolylineAlgorithm.Internal + href: PolylineAlgorithm.Internal.yml + items: + - name: Classes + - name: PolylineReader + href: PolylineAlgorithm.Internal.PolylineReader.yml + - name: Structs + - name: PolylineWriter + href: PolylineAlgorithm.Internal.PolylineWriter.yml From 9988339099fba8162ab7d6d2b6e106ae42bff03f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 14:10:57 +0000 Subject: [PATCH 21/24] feat: introduce PolylineValueState struct to replace ref int state in Write/Read Agent-Logs-Url: https://github.com/petesramek/polyline-algorithm-csharp/sessions/7920fca6-3575-456d-9604-4e1400a5a5eb Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com> --- .../PolylineDecoderBenchmark.cs | 12 ++++----- .../PolylineEncoderBenchmark.cs | 4 +-- .../NetTopologyPolylineDecoder.cs | 4 +-- .../NetTopologyPolylineEncoder.cs | 4 +-- .../Internal/PolylineReader.cs | 6 ++--- .../Internal/PolylineValueState.cs | 25 +++++++++++++++++++ .../Internal/PolylineWriter.cs | 6 ++--- src/PolylineAlgorithm/PublicAPI.Unshipped.txt | 5 ++++ .../AbstractPolylineDecoderTests.cs | 8 +++--- .../AbstractPolylineEncoderTests.cs | 4 +-- .../PolylineDecoderExtensionsTests.cs | 8 +++--- .../PolylineEncoderExtensionsTests.cs | 4 +-- .../RandomValueProvider.cs | 4 +-- 13 files changed, 62 insertions(+), 32 deletions(-) create mode 100644 src/PolylineAlgorithm/Internal/PolylineValueState.cs diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs index 0ccddb52..0f09bbf4 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs @@ -94,8 +94,8 @@ public void PolylineDecoder_Decode_Memory() { } private sealed class StringPolylineDecoder : AbstractPolylineDecoder { - private int _latitudeState; - private int _longitudeState; + private PolylineValueState _latitudeState; + private PolylineValueState _longitudeState; protected override (double Latitude, double Longitude) Read(PolylineReader reader) => (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); @@ -106,8 +106,8 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { } private sealed class CharArrayPolylineDecoder : AbstractPolylineDecoder { - private int _latitudeState; - private int _longitudeState; + private PolylineValueState _latitudeState; + private PolylineValueState _longitudeState; protected override (double Latitude, double Longitude) Read(PolylineReader reader) => (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); @@ -118,8 +118,8 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) { } private sealed class MemoryCharPolylineDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { - private int _latitudeState; - private int _longitudeState; + private PolylineValueState _latitudeState; + private PolylineValueState _longitudeState; protected override (double Latitude, double Longitude) Read(PolylineReader reader) => (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs index 9a6ef87c..b4233f3a 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs @@ -86,8 +86,8 @@ public void PolylineEncoder_Encode_List() { } private sealed class StringPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - private int _latitudeState; - private int _longitudeState; + private PolylineValueState _latitudeState; + private PolylineValueState _longitudeState; protected override string CreatePolyline(ReadOnlySpan polyline) => polyline.ToString(); protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer) { diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs index 956b846b..5d2fbcd2 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs @@ -14,8 +14,8 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; /// Polyline decoder using NetTopologySuite. ///
internal sealed class NetTopologyPolylineDecoder : AbstractPolylineDecoder { - private int _latitudeState; - private int _longitudeState; + private PolylineValueState _latitudeState; + private PolylineValueState _longitudeState; /// /// Converts polyline string to read-only memory. diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs index c98d706c..ce9bb26a 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs @@ -14,8 +14,8 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; /// Polyline encoder using NetTopologySuite's Point type. /// internal sealed class NetTopologyPolylineEncoder : AbstractPolylineEncoder { - private int _latitudeState; - private int _longitudeState; + private PolylineValueState _latitudeState; + private PolylineValueState _longitudeState; /// /// Creates encoded polyline string from span. diff --git a/src/PolylineAlgorithm/Internal/PolylineReader.cs b/src/PolylineAlgorithm/Internal/PolylineReader.cs index 8002f67c..bc37195a 100644 --- a/src/PolylineAlgorithm/Internal/PolylineReader.cs +++ b/src/PolylineAlgorithm/Internal/PolylineReader.cs @@ -34,12 +34,12 @@ internal PolylineReader(ReadOnlyMemory sequence, uint precision) { /// /// Thrown when the data runs out before the formatter has finished reading an item's fields. /// - public double Read(ref int state) { - if (!PolylineEncoding.TryReadValue(ref state, _sequence, ref _position)) { + public double Read(ref PolylineValueState state) { + if (!PolylineEncoding.TryReadValue(ref state._value, _sequence, ref _position)) { ExceptionGuard.ThrowInvalidPolylineFormat(_position); } - double result = PolylineEncoding.Denormalize(state, _precision); + double result = PolylineEncoding.Denormalize(state._value, _precision); return result; } diff --git a/src/PolylineAlgorithm/Internal/PolylineValueState.cs b/src/PolylineAlgorithm/Internal/PolylineValueState.cs new file mode 100644 index 00000000..c4467056 --- /dev/null +++ b/src/PolylineAlgorithm/Internal/PolylineValueState.cs @@ -0,0 +1,25 @@ +// +// Copyright © Pete Sramek. All rights reserved. +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace PolylineAlgorithm.Internal; + +/// +/// Holds the per-field delta accumulation state for polyline encoding and decoding. +/// +/// +/// Instances are owned by caller-provided encoder/decoder subclasses as private fields — one per +/// encoded field (e.g. latitude, longitude). The engine mutates the state on every +/// or call via an +/// reference, while the public property lets callers +/// read the current accumulated value (e.g. for diagnostics or logging) without being able to write it. +/// +public struct PolylineValueState { + internal int _value; + + /// + /// Gets the current accumulated normalized integer value. + /// + public readonly int Value => _value; +} diff --git a/src/PolylineAlgorithm/Internal/PolylineWriter.cs b/src/PolylineAlgorithm/Internal/PolylineWriter.cs index 523d4d47..f7334cd7 100644 --- a/src/PolylineAlgorithm/Internal/PolylineWriter.cs +++ b/src/PolylineAlgorithm/Internal/PolylineWriter.cs @@ -33,12 +33,12 @@ internal PolylineWriter(Span buffer, uint precision) { /// /// Emits one field value into the encoding pipeline. /// - public void Write(double value, ref int state) { + public void Write(double value, ref PolylineValueState state) { int normalized = PolylineEncoding.Normalize(value, _precision); - int delta = normalized - state; + int delta = normalized - state._value; - state = normalized; + state._value = normalized; if (!PolylineEncoding.TryWriteValue(delta, _buffer, ref _position)) { ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer(); diff --git a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt index 7dc5c581..eca939ea 100644 --- a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt +++ b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt @@ -1 +1,6 @@ #nullable enable +PolylineAlgorithm.Internal.PolylineValueState +PolylineAlgorithm.Internal.PolylineValueState.PolylineValueState() -> void +PolylineAlgorithm.Internal.PolylineValueState.Value.get -> int +PolylineAlgorithm.Internal.PolylineReader.Read(ref PolylineAlgorithm.Internal.PolylineValueState state) -> double +PolylineAlgorithm.Internal.PolylineWriter.Write(double value, ref PolylineAlgorithm.Internal.PolylineValueState state) -> void diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs index 9197551b..e52972d4 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs @@ -17,16 +17,16 @@ namespace PolylineAlgorithm.Tests.Abstraction; [TestClass] public sealed class AbstractPolylineDecoderTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { - private int _latitudeState; - private int _longitudeState; + private PolylineValueState _latitudeState; + private PolylineValueState _longitudeState; protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); protected override (double Latitude, double Longitude) Read(PolylineReader reader) => (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); } private sealed class TestStringDecoderWithOptions : AbstractPolylineDecoder { - private int _latitudeState; - private int _longitudeState; + private PolylineValueState _latitudeState; + private PolylineValueState _longitudeState; public TestStringDecoderWithOptions(PolylineEncodingOptions options) : base(options) { } diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs index 0edb1206..1c55df0b 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs @@ -16,8 +16,8 @@ namespace PolylineAlgorithm.Tests.Abstraction; [TestClass] public sealed class AbstractPolylineEncoderTests { private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - private int _latitudeState; - private int _longitudeState; + private PolylineValueState _latitudeState; + private PolylineValueState _longitudeState; public TestStringEncoder() : base() { } diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs index 2e501fe3..8072db12 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs @@ -18,8 +18,8 @@ namespace PolylineAlgorithm.Tests.Extensions; [TestClass] public sealed class PolylineDecoderExtensionsTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { - private int _latitudeState; - private int _longitudeState; + private PolylineValueState _latitudeState; + private PolylineValueState _longitudeState; protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); protected override (double Latitude, double Longitude) Read(PolylineReader reader) => @@ -27,8 +27,8 @@ protected override (double Latitude, double Longitude) Read(PolylineReader reade } private sealed class TestMemoryDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { - private int _latitudeState; - private int _longitudeState; + private PolylineValueState _latitudeState; + private PolylineValueState _longitudeState; protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) => polyline; protected override (double Latitude, double Longitude) Read(PolylineReader reader) => diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs index 04ec3d2b..e469db18 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs @@ -18,8 +18,8 @@ namespace PolylineAlgorithm.Tests.Extensions; [TestClass] public sealed class PolylineEncoderExtensionsTests { private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - private int _latitudeState; - private int _longitudeState; + private PolylineValueState _latitudeState; + private PolylineValueState _longitudeState; protected override string CreatePolyline(ReadOnlySpan polyline) => polyline.ToString(); protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer) { diff --git a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs index 492329bf..0bd305f6 100644 --- a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs +++ b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs @@ -105,8 +105,8 @@ private readonly struct PolylineCoordinateCollectionPair(IEnumerable<(double Lat } private sealed class PolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - private int _latitudeState; - private int _longitudeState; + private PolylineValueState _latitudeState; + private PolylineValueState _longitudeState; protected override string CreatePolyline(ReadOnlySpan polyline) { return polyline.ToString(); From f21d3ec39d466d77a857e3cbdbc10c0b4236db3a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 14:13:16 +0000 Subject: [PATCH 22/24] docs: update README examples to use PolylineValueState state fields Agent-Logs-Url: https://github.com/petesramek/polyline-algorithm-csharp/sessions/7920fca6-3575-456d-9604-4e1400a5a5eb Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com> --- src/PolylineAlgorithm/README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/PolylineAlgorithm/README.md b/src/PolylineAlgorithm/README.md index 25e070ff..b5c0352b 100644 --- a/src/PolylineAlgorithm/README.md +++ b/src/PolylineAlgorithm/README.md @@ -41,9 +41,12 @@ using PolylineAlgorithm.Abstraction; using PolylineAlgorithm.Internal; public sealed class MyPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { + private PolylineValueState _latitudeState; + private PolylineValueState _longitudeState; + protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer) { - writer.Write(item.Latitude); // field 0 - writer.Write(item.Longitude); // field 1 + writer.Write(item.Latitude, ref _latitudeState); // field 0 + writer.Write(item.Longitude, ref _longitudeState); // field 1 } protected override string CreatePolyline(ReadOnlySpan polyline) => polyline.ToString(); } @@ -75,8 +78,11 @@ using PolylineAlgorithm.Abstraction; using PolylineAlgorithm.Internal; public sealed class MyPolylineDecoder : AbstractPolylineDecoder { + private PolylineValueState _latitudeState; + private PolylineValueState _longitudeState; + protected override (double Latitude, double Longitude) Read(PolylineReader reader) => - (reader.Read(), reader.Read()); // field 0, field 1 + (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); // field 0, field 1 protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); } ``` From 621d6e5f7fa2244e56a50e08845d0406c7932eae Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 17:47:22 +0000 Subject: [PATCH 23/24] refactor: move PolylineValueState to local variables in Encode/Decode via ValuesPerItem pattern Agent-Logs-Url: https://github.com/petesramek/polyline-algorithm-csharp/sessions/8a3b65fb-20f2-40d5-a3cc-0ea2638e1e94 Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com> --- .../PolylineDecoderBenchmark.cs | 21 +++++++-------- .../PolylineEncoderBenchmark.cs | 9 +++---- .../NetTopologyPolylineDecoder.cs | 13 ++++----- .../NetTopologyPolylineEncoder.cs | 13 ++++----- .../Abstraction/AbstractPolylineDecoder.cs | 24 ++++++++++++++--- .../Abstraction/AbstractPolylineEncoder.cs | 27 +++++++++++++++---- src/PolylineAlgorithm/PublicAPI.Unshipped.txt | 4 +++ .../AbstractPolylineDecoderTests.cs | 15 +++++------ .../AbstractPolylineEncoderTests.cs | 10 +++---- .../PolylineDecoderExtensionsTests.cs | 16 +++++------ .../PolylineEncoderExtensionsTests.cs | 10 +++---- .../RandomValueProvider.cs | 9 +++---- 12 files changed, 97 insertions(+), 74 deletions(-) diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs index 0f09bbf4..72134710 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs @@ -94,11 +94,10 @@ public void PolylineDecoder_Decode_Memory() { } private sealed class StringPolylineDecoder : AbstractPolylineDecoder { - private PolylineValueState _latitudeState; - private PolylineValueState _longitudeState; + protected override int ValuesPerItem => 2; - protected override (double Latitude, double Longitude) Read(PolylineReader reader) => - (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); + protected override (double Latitude, double Longitude) Read(PolylineReader reader, PolylineValueState[] states) => + (reader.Read(ref states[0]), reader.Read(ref states[1])); protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { return polyline?.AsMemory() ?? Memory.Empty; @@ -106,11 +105,10 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { } private sealed class CharArrayPolylineDecoder : AbstractPolylineDecoder { - private PolylineValueState _latitudeState; - private PolylineValueState _longitudeState; + protected override int ValuesPerItem => 2; - protected override (double Latitude, double Longitude) Read(PolylineReader reader) => - (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); + protected override (double Latitude, double Longitude) Read(PolylineReader reader, PolylineValueState[] states) => + (reader.Read(ref states[0]), reader.Read(ref states[1])); protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) { return polyline?.AsMemory() ?? Memory.Empty; @@ -118,11 +116,10 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) { } private sealed class MemoryCharPolylineDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { - private PolylineValueState _latitudeState; - private PolylineValueState _longitudeState; + protected override int ValuesPerItem => 2; - protected override (double Latitude, double Longitude) Read(PolylineReader reader) => - (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); + protected override (double Latitude, double Longitude) Read(PolylineReader reader, PolylineValueState[] states) => + (reader.Read(ref states[0]), reader.Read(ref states[1])); protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) { return polyline; diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs index b4233f3a..24b8bc66 100644 --- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs +++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs @@ -86,13 +86,12 @@ public void PolylineEncoder_Encode_List() { } private sealed class StringPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - private PolylineValueState _latitudeState; - private PolylineValueState _longitudeState; + protected override int ValuesPerItem => 2; protected override string CreatePolyline(ReadOnlySpan polyline) => polyline.ToString(); - protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer) { - writer.Write(item.Latitude, ref _latitudeState); - writer.Write(item.Longitude, ref _longitudeState); + protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer, PolylineValueState[] states) { + writer.Write(item.Latitude, ref states[0]); + writer.Write(item.Longitude, ref states[1]); } } } diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs index 5d2fbcd2..f4469e87 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs @@ -14,9 +14,6 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; /// Polyline decoder using NetTopologySuite. /// internal sealed class NetTopologyPolylineDecoder : AbstractPolylineDecoder { - private PolylineValueState _latitudeState; - private PolylineValueState _longitudeState; - /// /// Converts polyline string to read-only memory. /// @@ -26,14 +23,18 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) { return polyline.AsMemory(); } + /// + protected override int ValuesPerItem => 2; + /// /// Creates a NetTopologySuite Point from decoded field values. /// /// The reader provided by the engine. Field 0 = latitude, field 1 = longitude. + /// Per-field delta accumulation states. /// Point instance. - protected override Point Read(PolylineReader reader) { - double latitude = reader.Read(ref _latitudeState); - double longitude = reader.Read(ref _longitudeState); + protected override Point Read(PolylineReader reader, PolylineValueState[] states) { + double latitude = reader.Read(ref states[0]); + double longitude = reader.Read(ref states[1]); // NetTopologySuite Point: x = longitude, y = latitude return new Point(longitude, latitude); diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs index ce9bb26a..15d283c2 100644 --- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs +++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs @@ -14,9 +14,6 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample; /// Polyline encoder using NetTopologySuite's Point type. ///
internal sealed class NetTopologyPolylineEncoder : AbstractPolylineEncoder { - private PolylineValueState _latitudeState; - private PolylineValueState _longitudeState; - /// /// Creates encoded polyline string from span. /// @@ -30,16 +27,20 @@ protected override string CreatePolyline(ReadOnlySpan polyline) { return polyline.ToString(); } + /// + protected override int ValuesPerItem => 2; + /// /// Writes latitude and longitude from a NetTopologySuite Point into the polyline encoding pipeline. /// /// The point to write. Field 0 = latitude (Y), field 1 = longitude (X). /// The writer provided by the engine. - protected override void Write(Point item, ref PolylineWriter writer) { + /// Per-field delta accumulation states. + protected override void Write(Point item, ref PolylineWriter writer, PolylineValueState[] states) { ArgumentNullException.ThrowIfNull(item); // NetTopologySuite Point: Y = latitude, X = longitude - writer.Write(item.Y, ref _latitudeState); - writer.Write(item.X, ref _longitudeState); + writer.Write(item.Y, ref states[0]); + writer.Write(item.X, ref states[1]); } } \ No newline at end of file diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs index debacb4d..d58496b3 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs @@ -91,12 +91,13 @@ public IEnumerable Decode(TPolyline polyline, CancellationToken can ValidateFormat(sequence, _logger); PolylineReader reader = new(sequence, Options.Precision); + PolylineValueState[] states = new PolylineValueState[ValuesPerItem]; try { while (!reader.IsEmpty) { cancellationToken.ThrowIfCancellationRequested(); - TCoordinate item = Read(reader); + TCoordinate item = Read(reader, states); //_logger?.LogDecodedItemDebug(reader.SlotIndex, reader.Position); @@ -107,6 +108,16 @@ public IEnumerable Decode(TPolyline polyline, CancellationToken can } } + /// + /// Gets the number of field values encoded or decoded per item. + /// + /// + /// The base class uses this value to allocate the per-call state array that is passed to + /// . Implementations must return a constant value that matches the + /// number of calls made inside . + /// + protected abstract int ValuesPerItem { get; } + /// /// Validates that the provided polyline is not . /// @@ -184,14 +195,19 @@ protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? lo /// once for each expected field value, in the same order used by the corresponding encoder's /// override. /// + /// + /// The per-field delta accumulation state array, allocated by the base class for the duration of + /// the call. Index into this array in the same fixed order used for each field + /// (e.g. states[0] for latitude, states[1] for longitude). + /// /// /// A instance constructed from the decoded field values. /// /// /// Implementations must always call the same number of times, - /// in the same field order, for every item. The number of reads must match the number of writes - /// performed by the corresponding encoder's override. + /// in the same field order, for every item. The number of reads must match + /// and the number of writes performed by the corresponding encoder's override. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract TCoordinate Read(PolylineReader reader); + protected abstract TCoordinate Read(PolylineReader reader, PolylineValueState[] states); } diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs index 8d45408c..1d75e54c 100644 --- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs +++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs @@ -88,7 +88,7 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken ValidateEmptyCoordinates(ref coordinates, _logger, OperationName); // Worst-case maximum: every value uses the maximum number of encoded characters. - int maxCapacity = coordinates.Length * 2 * Defaults.Polyline.Block.Length.Max; + int maxCapacity = coordinates.Length * ValuesPerItem * Defaults.Polyline.Block.Length.Max; // Use stackalloc for small buffers (zero heap allocation); fall back to ArrayPool for large ones. const int StackAllocThreshold = 512; @@ -98,6 +98,7 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken : stackalloc char[maxCapacity]; PolylineWriter writer = new(buffer, Options.Precision); + PolylineValueState[] states = new PolylineValueState[ValuesPerItem]; TPolyline result; @@ -105,7 +106,7 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken for (var i = 0; i < coordinates.Length; i++) { cancellationToken.ThrowIfCancellationRequested(); - Write(coordinates[i], ref writer); + Write(coordinates[i], ref writer, states); } result = CreatePolyline(writer.WrittenSpan); @@ -133,6 +134,16 @@ static void ValidateEmptyCoordinates(ref ReadOnlySpan coordinates, } } + /// + /// Gets the number of field values encoded or decoded per item. + /// + /// + /// The base class uses this value to allocate the per-call state array that is passed to + /// . Implementations must return a constant value that matches the + /// number of calls made inside . + /// + protected abstract int ValuesPerItem { get; } + /// /// Creates a polyline instance from the provided read-only span of characters. /// @@ -152,11 +163,17 @@ static void ValidateEmptyCoordinates(ref ReadOnlySpan coordinates, /// once for each field value, in a fixed, consistent order. The engine handles delta computation, /// zigzag encoding, and output buffering. /// + /// + /// The per-field delta accumulation state array, allocated by the base class for the duration of + /// the call. Index into this array in the same fixed order used for each field + /// (e.g. states[0] for latitude, states[1] for longitude). + /// /// /// Implementations must always call the same number of times, - /// in the same field order, for every item. The corresponding override must - /// call the same number of times in the same order. + /// in the same field order, for every item. The number of calls must match . + /// The corresponding override must call the + /// same number of times in the same order. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected abstract void Write(TCoordinate item, ref PolylineWriter writer); + protected abstract void Write(TCoordinate item, ref PolylineWriter writer, PolylineValueState[] states); } diff --git a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt index eca939ea..98a5e689 100644 --- a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt +++ b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt @@ -4,3 +4,7 @@ PolylineAlgorithm.Internal.PolylineValueState.PolylineValueState() -> void PolylineAlgorithm.Internal.PolylineValueState.Value.get -> int PolylineAlgorithm.Internal.PolylineReader.Read(ref PolylineAlgorithm.Internal.PolylineValueState state) -> double PolylineAlgorithm.Internal.PolylineWriter.Write(double value, ref PolylineAlgorithm.Internal.PolylineValueState state) -> void +abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValuesPerItem.get -> int +abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.Read(PolylineAlgorithm.Internal.PolylineReader! reader, PolylineAlgorithm.Internal.PolylineValueState[]! states) -> TCoordinate +abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.ValuesPerItem.get -> int +abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.Write(TCoordinate item, ref PolylineAlgorithm.Internal.PolylineWriter writer, PolylineAlgorithm.Internal.PolylineValueState[]! states) -> void diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs index e52972d4..338f1643 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs @@ -17,23 +17,20 @@ namespace PolylineAlgorithm.Tests.Abstraction; [TestClass] public sealed class AbstractPolylineDecoderTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { - private PolylineValueState _latitudeState; - private PolylineValueState _longitudeState; + protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) Read(PolylineReader reader) => - (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); + protected override (double Latitude, double Longitude) Read(PolylineReader reader, PolylineValueState[] states) => + (reader.Read(ref states[0]), reader.Read(ref states[1])); } private sealed class TestStringDecoderWithOptions : AbstractPolylineDecoder { - private PolylineValueState _latitudeState; - private PolylineValueState _longitudeState; - public TestStringDecoderWithOptions(PolylineEncodingOptions options) : base(options) { } + protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) Read(PolylineReader reader) => - (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); + protected override (double Latitude, double Longitude) Read(PolylineReader reader, PolylineValueState[] states) => + (reader.Read(ref states[0]), reader.Read(ref states[1])); } /// diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs index 1c55df0b..839166bc 100644 --- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs +++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs @@ -16,19 +16,17 @@ namespace PolylineAlgorithm.Tests.Abstraction; [TestClass] public sealed class AbstractPolylineEncoderTests { private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - private PolylineValueState _latitudeState; - private PolylineValueState _longitudeState; - public TestStringEncoder() : base() { } public TestStringEncoder(PolylineEncodingOptions options) : base(options) { } + protected override int ValuesPerItem => 2; protected override string CreatePolyline(ReadOnlySpan polyline) => polyline.ToString(); - protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer) { - writer.Write(item.Latitude, ref _latitudeState); - writer.Write(item.Longitude, ref _longitudeState); + protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer, PolylineValueState[] states) { + writer.Write(item.Latitude, ref states[0]); + writer.Write(item.Longitude, ref states[1]); } } diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs index 8072db12..a444cc56 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs @@ -18,21 +18,17 @@ namespace PolylineAlgorithm.Tests.Extensions; [TestClass] public sealed class PolylineDecoderExtensionsTests { private sealed class TestStringDecoder : AbstractPolylineDecoder { - private PolylineValueState _latitudeState; - private PolylineValueState _longitudeState; - + protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); - protected override (double Latitude, double Longitude) Read(PolylineReader reader) => - (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); + protected override (double Latitude, double Longitude) Read(PolylineReader reader, PolylineValueState[] states) => + (reader.Read(ref states[0]), reader.Read(ref states[1])); } private sealed class TestMemoryDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> { - private PolylineValueState _latitudeState; - private PolylineValueState _longitudeState; - + protected override int ValuesPerItem => 2; protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) => polyline; - protected override (double Latitude, double Longitude) Read(PolylineReader reader) => - (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); + protected override (double Latitude, double Longitude) Read(PolylineReader reader, PolylineValueState[] states) => + (reader.Read(ref states[0]), reader.Read(ref states[1])); } // ----- Decode(char[]) for IPolylineDecoder ----- diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs index e469db18..e006b254 100644 --- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs +++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs @@ -18,13 +18,11 @@ namespace PolylineAlgorithm.Tests.Extensions; [TestClass] public sealed class PolylineEncoderExtensionsTests { private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - private PolylineValueState _latitudeState; - private PolylineValueState _longitudeState; - + protected override int ValuesPerItem => 2; protected override string CreatePolyline(ReadOnlySpan polyline) => polyline.ToString(); - protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer) { - writer.Write(item.Latitude, ref _latitudeState); - writer.Write(item.Longitude, ref _longitudeState); + protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer, PolylineValueState[] states) { + writer.Write(item.Latitude, ref states[0]); + writer.Write(item.Longitude, ref states[1]); } } diff --git a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs index 0bd305f6..2bb44718 100644 --- a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs +++ b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs @@ -105,16 +105,15 @@ private readonly struct PolylineCoordinateCollectionPair(IEnumerable<(double Lat } private sealed class PolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - private PolylineValueState _latitudeState; - private PolylineValueState _longitudeState; + protected override int ValuesPerItem => 2; protected override string CreatePolyline(ReadOnlySpan polyline) { return polyline.ToString(); } - protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer) { - writer.Write(item.Latitude, ref _latitudeState); - writer.Write(item.Longitude, ref _longitudeState); + protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer, PolylineValueState[] states) { + writer.Write(item.Latitude, ref states[0]); + writer.Write(item.Longitude, ref states[1]); } } } \ No newline at end of file From 8511b505c2304e201fead9e1779eae0a34da6961 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 17:49:44 +0000 Subject: [PATCH 24/24] docs: update README examples to use new ValuesPerItem and states[] pattern Agent-Logs-Url: https://github.com/petesramek/polyline-algorithm-csharp/sessions/8a3b65fb-20f2-40d5-a3cc-0ea2638e1e94 Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com> --- src/PolylineAlgorithm/README.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/PolylineAlgorithm/README.md b/src/PolylineAlgorithm/README.md index b5c0352b..7abf9766 100644 --- a/src/PolylineAlgorithm/README.md +++ b/src/PolylineAlgorithm/README.md @@ -41,12 +41,11 @@ using PolylineAlgorithm.Abstraction; using PolylineAlgorithm.Internal; public sealed class MyPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> { - private PolylineValueState _latitudeState; - private PolylineValueState _longitudeState; + protected override int ValuesPerItem => 2; - protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer) { - writer.Write(item.Latitude, ref _latitudeState); // field 0 - writer.Write(item.Longitude, ref _longitudeState); // field 1 + protected override void Write((double Latitude, double Longitude) item, ref PolylineWriter writer, PolylineValueState[] states) { + writer.Write(item.Latitude, ref states[0]); // field 0 + writer.Write(item.Longitude, ref states[1]); // field 1 } protected override string CreatePolyline(ReadOnlySpan polyline) => polyline.ToString(); } @@ -78,11 +77,10 @@ using PolylineAlgorithm.Abstraction; using PolylineAlgorithm.Internal; public sealed class MyPolylineDecoder : AbstractPolylineDecoder { - private PolylineValueState _latitudeState; - private PolylineValueState _longitudeState; + protected override int ValuesPerItem => 2; - protected override (double Latitude, double Longitude) Read(PolylineReader reader) => - (reader.Read(ref _latitudeState), reader.Read(ref _longitudeState)); // field 0, field 1 + protected override (double Latitude, double Longitude) Read(PolylineReader reader, PolylineValueState[] states) => + (reader.Read(ref states[0]), reader.Read(ref states[1])); // field 0, field 1 protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory(); } ```