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)]
[NullableContext(1)]
[Nullable(0)]
[CompilerFeatureRequired("RefStructs")]
[DebuggerDisplay("WrittenCount = {WrittenCount}, FreeCapacity = {FreeCapacity}, Overflow = {Overflow}")]
public ref struct BufferWriterSlim<[Nullable(2)] T>
{
[StructLayout(LayoutKind.Auto)]
[CompilerFeatureRequired("RefStructs")]
internal readonly ref struct Ref
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly ref byte reference;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
internal unsafe ref BufferWriterSlim<T> Value {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get {
return ref Ref.<get_Value>g__AsWriter|3_0(*(ref byte*)(&reference));
}
}
internal unsafe Ref(ref BufferWriterSlim<T> writer)
{
*(ref byte*)(&reference) = ref <.ctor>g__AsRef|1_0(ref writer);
}
}
private readonly Span<T> initialBuffer;
private readonly MemoryAllocator<T> allocator;
private MemoryOwner<T> extraBuffer;
private int position;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[ExcludeFromCodeCoverage]
private int Overflow {
[IsReadOnly]
get {
return Math.Max(0, position - initialBuffer.Length);
}
}
public int WrittenCount {
[IsReadOnly]
get {
return position;
}
set {
ArgumentOutOfRangeException.ThrowIfGreaterThan<uint>((uint)value, (uint)Capacity, "value");
position = value;
}
}
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;
}
}
[Nullable(new byte[] {
0,
1
})]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private Span<T> Buffer {
[IsReadOnly]
get {
if (!NoOverflow)
return extraBuffer.Span;
return initialBuffer;
}
}
[Nullable(new byte[] {
0,
1
})]
public ReadOnlySpan<T> WrittenSpan {
[IsReadOnly]
[return: Nullable(new byte[] {
0,
1
})]
get {
return Buffer.Slice(0, position);
}
}
public ref T this[int index] {
[IsReadOnly]
get {
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual<uint>((uint)index, (uint)position, "index");
return ref Unsafe.Add<T>(ref MemoryMarshal.GetReference<T>(Buffer), index);
}
}
public BufferWriterSlim([Nullable(new byte[] {
0,
1
})] Span<T> buffer, [Nullable(new byte[] {
2,
1
})] MemoryAllocator<T> allocator = null)
{
extraBuffer = default(MemoryOwner<T>);
position = 0;
initialBuffer = buffer;
this.allocator = allocator;
}
public BufferWriterSlim(int initialCapacity, [Nullable(new byte[] {
2,
1
})] MemoryAllocator<T> allocator = null)
{
initialBuffer = default(Span<T>);
position = 0;
ArgumentOutOfRangeException.ThrowIfNegative<int>(initialCapacity, "initialCapacity");
this.allocator = allocator;
extraBuffer = ((initialCapacity == 0) ? default(MemoryOwner<T>) : Memory.AllocateAtLeast<T>(allocator, initialCapacity));
}
[return: Nullable(new byte[] {
0,
1
})]
public Span<T> GetSpan(int sizeHint = 0)
{
ArgumentOutOfRangeException.ThrowIfNegative<int>(sizeHint, "sizeHint");
return InternalGetSpan(sizeHint);
}
internal Span<T> InternalGetSpan(int 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 = Memory.AllocateAtLeast<T>(allocator, newSize);
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))
Memory.Resize<T>(ref extraBuffer, newSize, allocator);
span = extraBuffer.Span;
}
return span.Slice(position);
}
public void Advance(int count)
{
ArgumentOutOfRangeException.ThrowIfNegative<int>(count, "count");
int num = position + count;
if (num > Capacity)
<Advance>g__ThrowInvalidOperationException|24_0();
position = num;
}
public void Rewind(int count)
{
ArgumentOutOfRangeException.ThrowIfGreaterThan<uint>((uint)count, (uint)position, "count");
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>()) {
Span<T> span = Buffer;
span = span.Slice(count);
span.Clear();
}
position -= count;
}
public void Write([ScopedRef] [Nullable(new byte[] {
0,
1
})] ReadOnlySpan<T> input)
{
if (!input.IsEmpty) {
input.CopyTo(InternalGetSpan(input.Length));
position += input.Length;
}
}
public void Add(T item)
{
Add() = item;
}
public ref T Add()
{
ref T reference = ref MemoryMarshal.GetReference<T>(InternalGetSpan(1));
position++;
return ref reference;
}
[IsReadOnly]
[NullableContext(2)]
public bool TryPeek([MaybeNullWhen(false)] out T item)
{
if (position > 0) {
item = Unsafe.Add<T>(ref MemoryMarshal.GetReference<T>(Buffer), position - 1);
return true;
}
item = default(T);
return false;
}
[NullableContext(2)]
public bool TryPop([MaybeNullWhen(false)] out T item)
{
if (position > 0) {
item = Unsafe.Add<T>(ref MemoryMarshal.GetReference<T>(Buffer), --position);
return true;
}
item = default(T);
return false;
}
public bool TryPop([ScopedRef] [Nullable(new byte[] {
0,
1
})] Span<T> output)
{
if (position >= output.Length) {
Span<T> span = Buffer;
span = span.Slice(position - output.Length, output.Length);
if (span.TryCopyTo(output)) {
position -= output.Length;
return true;
}
}
return false;
}
public bool TryDetachBuffer([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.Clear(true);
} else
extraBuffer.Clear(false);
this = default(BufferWriterSlim<T>);
}
[IsReadOnly]
public override string ToString()
{
return WrittenSpan.ToString();
}
}
}