PoolingInterpolatedStringHandler
public struct PoolingInterpolatedStringHandler : IGrowableBuffer<char>, IReadOnlySpanConsumer<char>, ISupplier<ReadOnlyMemory<char>, CancellationToken, ValueTask>, IFunctional<Func<ReadOnlyMemory<char>, CancellationToken, ValueTask>>, IDisposable, IResettable
Represents interpolated string builder that utilizes reusable buffer rented from the pool.
using DotNext.Runtime.CompilerServices;
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace DotNext.Buffers
{
[StructLayout(LayoutKind.Auto)]
[InterpolatedStringHandler]
[EditorBrowsable(EditorBrowsableState.Never)]
public struct PoolingInterpolatedStringHandler : IGrowableBuffer<char>, IReadOnlySpanConsumer<char>, ISupplier<ReadOnlyMemory<char>, CancellationToken, ValueTask>, IFunctional<Func<ReadOnlyMemory<char>, CancellationToken, ValueTask>>, IDisposable, IResettable
{
private const int MaxBufferSize = 1073741823;
private const char Whitespace = ' ';
private readonly MemoryAllocator<char> allocator;
private readonly IFormatProvider provider;
private MemoryOwner<char> buffer;
private int count;
long IGrowableBuffer<char>.WrittenCount {
[IsReadOnly]
get {
return count;
}
}
private ReadOnlyMemory<char> WrittenMemory {
[IsReadOnly]
get {
if (count <= 0)
return ReadOnlyMemory<char>.Empty;
return buffer.Memory.Slice(0, count);
}
}
[System.Runtime.CompilerServices.NullableContext(2)]
public PoolingInterpolatedStringHandler(int literalLength, int formattedCount, MemoryAllocator<char> allocator, IFormatProvider provider = null)
{
int num = 10 * formattedCount + literalLength;
if ((uint)num > (uint)Array.get_MaxLength())
throw new InsufficientMemoryException();
buffer = allocator.Invoke(num, false);
this.allocator = allocator;
this.provider = provider;
count = 0;
}
void IGrowableBuffer<char>.Write(ReadOnlySpan<char> value)
{
AppendFormatted(value);
}
void IReadOnlySpanConsumer<char>.Invoke(ReadOnlySpan<char> value)
{
AppendFormatted(value);
}
void IGrowableBuffer<char>.Write(char value)
{
AppendFormatted(MemoryMarshal.CreateReadOnlySpan(ref value, 1));
}
[IsReadOnly]
void IGrowableBuffer<char>.CopyTo<TConsumer>(TConsumer consumer)
{
((IReadOnlySpanConsumer<char>)consumer).Invoke(WrittenMemory.Span);
}
[IsReadOnly]
ValueTask IGrowableBuffer<char>.CopyToAsync<TConsumer>(TConsumer consumer, CancellationToken token)
{
return ((ISupplier<ReadOnlyMemory<char>, CancellationToken, ValueTask>)consumer).Invoke(WrittenMemory, token);
}
[IsReadOnly]
int IGrowableBuffer<char>.CopyTo(Span<char> output)
{
WrittenMemory.Span.CopyTo(output, out int writtenCount);
return writtenCount;
}
void IGrowableBuffer<char>.Clear()
{
buffer.Dispose();
count = 0;
}
[IsReadOnly]
bool IGrowableBuffer<char>.TryGetWrittenContent(out ReadOnlyMemory<char> block)
{
block = WrittenMemory;
return true;
}
internal MemoryOwner<char> DetachBuffer()
{
MemoryOwner<char> result;
if (count == 0)
result = default(MemoryOwner<char>);
else {
result = buffer;
result.Truncate(count);
count = 0;
buffer = default(MemoryOwner<char>);
}
return result;
}
private Span<char> GetSpan(int sizeHint)
{
int sizeHint2 = sizeHint;
int length = buffer.Length;
int writtenCount = count;
if (((IGrowableBuffer<char>)).GetBufferSize(sizeHint2, length, writtenCount, out sizeHint))
ref buffer.Resize(sizeHint, false, allocator);
return buffer.Span.Slice(count);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public void AppendLiteral(string value)
{
AppendFormatted(value.AsSpan());
}
[System.Runtime.CompilerServices.NullableContext(2)]
public void AppendFormatted<T>([System.Runtime.CompilerServices.Nullable(1)] T value, string format = null)
{
if (!(((object)value) is ISpanFormattable)) {
if (!(((object)value) is IFormattable)) {
if (value != null)
AppendLiteral(value.ToString());
} else
AppendLiteral(((IFormattable)(object)value).ToString(format, provider));
} else {
int num = 0;
int num2 = default(int);
while (true) {
Span<char> span = GetSpan(num);
if (value.TryFormat(span, ref num2, (ReadOnlySpan<char>)format, provider))
break;
if (num > 1073741823)
throw new InsufficientMemoryException();
num <<= 1;
}
count += num2;
}
}
private void AppendFormatted(ReadOnlySpan<char> value, int alignment, bool leftAlign)
{
int num = alignment - value.Length;
if (num <= 0)
AppendFormatted(value);
else {
Span<char> span = GetSpan(alignment);
Span<char> span2;
if (leftAlign) {
span2 = span.Slice(value.Length, num);
span2.Fill(' ');
value.CopyTo(span);
} else {
span2 = span.Slice(0, num);
span2.Fill(' ');
value.CopyTo(span.Slice(num));
}
count += alignment;
}
}
public void AppendFormatted(ReadOnlySpan<char> value, int alignment)
{
bool leftAlign = false;
if (alignment < 0) {
leftAlign = true;
alignment = -alignment;
}
AppendFormatted(value, alignment, leftAlign);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public void AppendFormatted<T>([System.Runtime.CompilerServices.Nullable(1)] T value, int alignment, string format = null)
{
bool flag = false;
if (alignment < 0) {
flag = true;
alignment = -alignment;
}
if (((object)value) is ISpanFormattable) {
int num = alignment;
while (true) {
Span<char> span = GetSpan(num);
int num2 = default(int);
if (value.TryFormat(span, ref num2, (ReadOnlySpan<char>)format, provider)) {
int num3 = alignment - num2;
Span<char> span2;
if (num3 <= 0)
alignment = num2;
else if (flag) {
span2 = span.Slice(num2, num3);
span2.Fill(' ');
} else {
span2 = span.Slice(0, num2);
span2.CopyTo(span.Slice(num3));
span2 = span.Slice(0, num3);
span2.Fill(' ');
}
count += alignment;
return;
}
if (num > 1073741823)
break;
num <<= 1;
}
throw new InsufficientMemoryException();
}
if (!(((object)value) is IFormattable)) {
if (value != null)
AppendFormatted(value.ToString().AsSpan(), alignment, flag);
} else
AppendFormatted(((IFormattable)(object)value).ToString(format, provider).AsSpan(), alignment, flag);
}
public void AppendFormatted(ReadOnlySpan<char> value)
{
value.CopyTo(GetSpan(value.Length));
count += value.Length;
}
[IsReadOnly]
[System.Runtime.CompilerServices.NullableContext(1)]
public override string ToString()
{
return WrittenMemory.ToString();
}
public void Dispose()
{
buffer.Dispose();
this = default(PoolingInterpolatedStringHandler);
}
}
}