BufferWriterSlim<T>
Represents stack-allocated buffer writer.
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
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>
{
[StructLayout(LayoutKind.Auto)]
internal readonly ref struct Ref
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly ReadOnlySpan<byte> reference;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
internal ref BufferWriterSlim<T> Value {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get {
return ref <get_Value>g__AsWriter|3_0(ref MemoryMarshal.GetReference<byte>(reference));
}
}
internal Ref(ref BufferWriterSlim<T> writer)
{
reference = MemoryMarshal.CreateSpan<byte>(ref <.ctor>g__AsRef|1_0(ref writer), BufferWriterSlim<T>.Size);
}
}
private readonly Span<T> initialBuffer;
private readonly MemoryAllocator<T> allocator;
private MemoryOwner<T> extraBuffer;
private int position;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private unsafe static int Size {
get {
return sizeof(BufferWriterSlim<T>);
}
}
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[ExcludeFromCodeCoverage]
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;
}
}
private bool NoOverflow {
[IsReadOnly]
get {
return position <= initialBuffer.Length;
}
}
[System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
public ReadOnlySpan<T> WrittenSpan {
[IsReadOnly]
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
get {
return (NoOverflow ? initialBuffer : extraBuffer.Span).Slice(0, position);
}
}
public ref T this[int index] {
[IsReadOnly]
get {
if ((uint)index >= (uint)position)
throw new ArgumentOutOfRangeException("index");
return ref Unsafe.Add<T>(ref NoOverflow ? ref MemoryMarshal.GetReference<T>(initialBuffer) : ref extraBuffer.First, 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");
int newSize;
Span<T> span;
if (extraBuffer.IsEmpty) {
int length = initialBuffer.Length;
int writtenCount = position;
if (((IGrowableBuffer<T>)).GetBufferSize(sizeHint, length, writtenCount, out newSize)) {
extraBuffer = MemoryAllocator.Invoke<T>(allocator, newSize, false);
initialBuffer.CopyTo(span = extraBuffer.Span);
} else
span = initialBuffer;
} else {
int length2 = extraBuffer.Length;
int writtenCount2 = position;
if (((IGrowableBuffer<T>)).GetBufferSize(sizeHint, length2, writtenCount2, out newSize))
BufferHelpers.Resize<T>(ref extraBuffer, newSize, false, allocator);
span = extraBuffer.Span;
}
return span.Slice(position);
}
public void Advance(int count)
{
if (count < 0)
<Advance>g__ThrowArgumentOutOfRangeException|22_0();
if (position > Capacity - count)
<Advance>g__ThrowInvalidOperationException|22_1();
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)
{
MemoryMarshal.GetReference<T>(GetSpan(1)) = item;
position++;
}
public bool TryDetachBuffer([System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] out MemoryOwner<T> owner)
{
if (NoOverflow) {
owner = default(MemoryOwner<T>);
return false;
}
owner = extraBuffer;
owner.Truncate(position);
position = 0;
extraBuffer = default(MemoryOwner<T>);
return true;
}
public void Clear(bool reuseBuffer = false)
{
initialBuffer.Clear();
if (!reuseBuffer)
extraBuffer.Dispose();
else if (RuntimeHelpers.IsReferenceOrContainsReferences<T>()) {
extraBuffer.Span.Clear();
}
position = 0;
}
public void Dispose()
{
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
initialBuffer.Clear();
extraBuffer.Dispose();
this = default(BufferWriterSlim<T>);
}
[IsReadOnly]
public override string ToString()
{
return WrittenSpan.ToString();
}
}
}