BufferWriterSlim<T>
Represents stack-allocated buffer builder.
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DotNext.Buffers
{
[StructLayout(LayoutKind.Auto)]
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
[DebuggerDisplay("WrittenCount = {WrittenCount}, FreeCapacity = {FreeCapacity}, Overflow = {Overflow}")]
public ref struct BufferWriterSlim<[System.Runtime.CompilerServices.Nullable(2)] T>
{
[System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
private readonly Span<T> initialBuffer;
[System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})]
private readonly MemoryAllocator<T> allocator;
[System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
private MemoryOwner<T> extraBuffer;
private int position;
private int Overflow {
[IsReadOnly]
get {
return Math.Max(0, position - initialBuffer.Length);
}
}
public int WrittenCount {
[IsReadOnly]
get {
return position;
}
}
public int Capacity {
[IsReadOnly]
get {
if (!extraBuffer.IsEmpty)
return extraBuffer.Length;
return initialBuffer.Length;
}
}
public int FreeCapacity {
[IsReadOnly]
get {
return Capacity - WrittenCount;
}
}
[System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
public ReadOnlySpan<T> WrittenSpan {
[IsReadOnly]
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
get {
return ((position <= initialBuffer.Length) ? initialBuffer : extraBuffer.Memory.Span).Slice(0, position);
}
}
public ref T this[int index] {
[IsReadOnly]
get {
if (index < 0 || index >= position)
throw new ArgumentOutOfRangeException("index");
return ref Unsafe.Add<T>(ref MemoryMarshal.GetReference<T>((position <= initialBuffer.Length) ? initialBuffer : extraBuffer.Memory.Span), index);
}
}
public BufferWriterSlim([System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] Span<T> buffer, [System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})] MemoryAllocator<T> allocator = null)
{
initialBuffer = buffer;
this.allocator = allocator;
extraBuffer = default(MemoryOwner<T>);
position = 0;
}
public BufferWriterSlim(int initialCapacity, [System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})] MemoryAllocator<T> allocator = null)
{
if (initialCapacity < 0)
throw new ArgumentOutOfRangeException("initialCapacity");
initialBuffer = default(Span<T>);
this.allocator = allocator;
extraBuffer = ((initialCapacity == 0) ? default(MemoryOwner<T>) : MemoryAllocator.Invoke<T>(allocator, initialCapacity, false));
position = 0;
}
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
public Span<T> GetSpan(int sizeHint = 0)
{
if (sizeHint < 0)
throw new ArgumentOutOfRangeException("sizeHint");
Memory<T> memory;
Span<T> span;
if (extraBuffer.IsEmpty) {
int length = initialBuffer.Length;
int writtenCount = position;
int? bufferSize = ((IGrowableBuffer<T>)).GetBufferSize(sizeHint, length, writtenCount);
if (bufferSize.HasValue) {
extraBuffer = MemoryAllocator.Invoke<T>(allocator, bufferSize.GetValueOrDefault(), false);
ref Span<T> reference = ref initialBuffer;
memory = extraBuffer.Memory;
reference.CopyTo(memory.Span);
initialBuffer.Clear();
memory = extraBuffer.Memory;
span = memory.Span;
} else
span = initialBuffer;
} else {
int length2 = extraBuffer.Length;
int writtenCount2 = position;
int? bufferSize = ((IGrowableBuffer<T>)).GetBufferSize(sizeHint, length2, writtenCount2);
if (bufferSize.HasValue) {
MemoryOwner<T> memoryOwner = MemoryAllocator.Invoke<T>(allocator, bufferSize.GetValueOrDefault(), false);
memory = extraBuffer.Memory;
memory.CopyTo(memoryOwner.Memory);
extraBuffer.Dispose();
extraBuffer = memoryOwner;
}
memory = extraBuffer.Memory;
span = memory.Span;
}
return span.Slice(position);
}
public void Advance(int count)
{
if (count < 0)
throw new ArgumentOutOfRangeException("count");
if (position > Capacity - count)
throw new InvalidOperationException();
position += count;
}
public void Write([System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] ReadOnlySpan<T> input)
{
if (!input.IsEmpty) {
input.CopyTo(GetSpan(input.Length));
position += input.Length;
}
}
public void Add(T item)
{
Write(MemoryMarshal.CreateReadOnlySpan<T>(ref item, 1));
}
public void Clear(bool reuseBuffer)
{
initialBuffer.Clear();
if (!reuseBuffer) {
extraBuffer.Dispose();
extraBuffer = default(MemoryOwner<T>);
} else if (RuntimeHelpers.IsReferenceOrContainsReferences<T>()) {
extraBuffer.Memory.Span.Clear();
}
position = 0;
}
public void Dispose()
{
extraBuffer.Dispose();
this = default(BufferWriterSlim<T>);
}
public override string ToString()
{
return WrittenSpan.ToString();
}
}
}