Skip to content

Commit 9af79d9

Browse files
Copilotpetesramek
andauthored
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>
1 parent e863407 commit 9af79d9

2 files changed

Lines changed: 18 additions & 13 deletions

File tree

src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace PolylineAlgorithm.Abstraction;
1010
using PolylineAlgorithm.Internal;
1111
using PolylineAlgorithm.Internal.Diagnostics;
1212
using System;
13+
using System.Buffers;
1314
using System.Diagnostics;
1415
using System.Runtime.CompilerServices;
1516
using System.Threading;
@@ -88,7 +89,16 @@ public TPolyline Encode(ReadOnlySpan<TCoordinate> coordinates, CancellationToken
8889

8990
// Worst-case maximum: every value uses the maximum number of encoded characters.
9091
int maxCapacity = coordinates.Length * 2 * Defaults.Polyline.Block.Length.Max;
91-
PolylineWriter writer = new(maxCapacity, Options.Precision);
92+
93+
// Use ArrayPool for large buffers to avoid large heap allocations; for small buffers a fresh
94+
// allocation is cheaper than pool overhead.
95+
const int StackAllocThreshold = 512;
96+
char[]? rentedBuffer = maxCapacity > StackAllocThreshold
97+
? ArrayPool<char>.Shared.Rent(maxCapacity)
98+
: null;
99+
char[] buffer = rentedBuffer ?? new char[maxCapacity];
100+
101+
PolylineWriter writer = new(buffer, Options.Precision);
92102

93103
TPolyline result;
94104

@@ -102,7 +112,9 @@ public TPolyline Encode(ReadOnlySpan<TCoordinate> coordinates, CancellationToken
102112

103113
result = CreatePolyline(writer.WrittenMemory);
104114
} finally {
105-
writer.ReturnBuffer();
115+
if (rentedBuffer is not null) {
116+
ArrayPool<char>.Shared.Return(rentedBuffer);
117+
}
106118
}
107119

108120
_logger
@@ -150,4 +162,3 @@ static void ValidateEmptyCoordinates(ref ReadOnlySpan<TCoordinate> coordinates,
150162
[MethodImpl(MethodImplOptions.AggressiveInlining)]
151163
protected abstract void Write(TCoordinate item, IPolylineWriter writer);
152164
}
153-

src/PolylineAlgorithm/Internal/PolylineWriter.cs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@ namespace PolylineAlgorithm.Internal;
88
using PolylineAlgorithm.Abstraction;
99
using PolylineAlgorithm.Internal.Diagnostics;
1010
using System;
11-
using System.Buffers;
1211
using System.Runtime.CompilerServices;
1312

1413
/// <summary>
1514
/// Engine-owned stateful cursor that feeds values written by a formatter into the polyline encoding pipeline.
1615
/// </summary>
1716
/// <remarks>
18-
/// Each instance wraps an <see cref="ArrayPool{T}"/>-backed output buffer sized to the worst-case maximum
17+
/// Each instance wraps a caller-provided <see cref="char"/> buffer sized to the worst-case maximum
1918
/// capacity so that the buffer never needs to grow. The engine calls <see cref="BeginItem"/> before
2019
/// invoking the formatter for each item so that the slot index resets correctly while delta state is
2120
/// preserved across item boundaries.
@@ -27,8 +26,8 @@ internal sealed class PolylineWriter : IPolylineWriter {
2726
private int[] _previous;
2827
private int _slotIndex;
2928

30-
internal PolylineWriter(int capacity, uint precision) {
31-
_buffer = ArrayPool<char>.Shared.Rent(capacity);
29+
internal PolylineWriter(char[] buffer, uint precision) {
30+
_buffer = buffer;
3231
_precision = precision;
3332
_previous = [];
3433
_slotIndex = 0;
@@ -68,12 +67,7 @@ public void Write(double value) {
6867

6968
/// <summary>
7069
/// Returns the encoded polyline characters written so far.
71-
/// The caller must not use this memory after <see cref="ReturnBuffer"/> is called.
70+
/// The caller must not use this memory after the buffer is returned to <see cref="System.Buffers.ArrayPool{T}"/>.
7271
/// </summary>
7372
internal ReadOnlyMemory<char> WrittenMemory => _buffer.AsMemory(0, _position);
74-
75-
/// <summary>
76-
/// Returns the rented buffer to the pool. Must be called exactly once when encoding is complete.
77-
/// </summary>
78-
internal void ReturnBuffer() => ArrayPool<char>.Shared.Return(_buffer);
7973
}

0 commit comments

Comments
 (0)