Files
even-perfect-numbers-scanner/PerfectNumbers.Core/PooledValueStringBuilder.cs
T

122 lines
2.9 KiB
C#

using System;
using System.Globalization;
using System.Runtime.CompilerServices;
namespace PerfectNumbers.Core;
public ref struct PooledValueStringBuilder
{
private Span<char> _span;
private char[]? _arrayFromPool;
private int _pos;
public PooledValueStringBuilder(Span<char> initialBuffer)
{
_span = initialBuffer;
_arrayFromPool = null;
_pos = 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Append(char value)
{
int position = _pos;
if (position < _span.Length)
{
_span[position] = value;
_pos = position + 1;
return;
}
Grow(1);
_span[_pos++] = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Append(string? value)
{
if (!string.IsNullOrEmpty(value))
{
Append(value.AsSpan());
}
}
public void Append(ReadOnlySpan<char> value)
{
if (value.Length == 0)
{
return;
}
int remaining = _span.Length - _pos;
if (value.Length <= remaining)
{
value.CopyTo(_span[_pos..]);
_pos += value.Length;
return;
}
Grow(value.Length);
value.CopyTo(_span[_pos..]);
_pos += value.Length;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Append(int value)
{
AppendSpanFormattable(value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Append(ulong value)
{
AppendSpanFormattable(value);
}
public ReadOnlySpan<char> AsSpan() => _span[.._pos];
public override string ToString()
{
return new string(_span[.._pos]);
}
public void Dispose()
{
if (_arrayFromPool is { } array)
{
ThreadStaticPools.CharPool.Return(array);
_arrayFromPool = null;
}
_span = Span<char>.Empty;
_pos = 0;
}
private void AppendSpanFormattable<T>(T value) where T : ISpanFormattable
{
int charsWritten;
while (!value.TryFormat(_span[_pos..], out charsWritten, default, CultureInfo.InvariantCulture))
{
Grow(Math.Max(4, _span.Length));
}
_pos += charsWritten;
}
private void Grow(int additionalCapacity)
{
int required = _pos + additionalCapacity;
int currentLength = _span.Length;
int newCapacity = currentLength == 0 ? Math.Max(4, required) : Math.Max(currentLength * 2, required);
char[] newArray = ThreadStaticPools.CharPool.Rent(newCapacity);
_span[.._pos].CopyTo(newArray.AsSpan());
if (_arrayFromPool is { } toReturn)
{
ThreadStaticPools.CharPool.Return(toReturn);
}
_span = newArray;
_arrayFromPool = newArray;
}
}