SpanOwner<T>
Represents the memory obtained from the pool or allocated
on the stack or heap.
using DotNext.Runtime;
using System;
using System.Buffers;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DotNext.Buffers
{
[StructLayout(LayoutKind.Auto)]
[NullableContext(1)]
[Nullable(0)]
[CompilerFeatureRequired("RefStructs")]
public ref struct SpanOwner<[Nullable(2)] T>
{
private readonly object owner;
private readonly Span<T> memory;
[EditorBrowsable(EditorBrowsableState.Never)]
[CLSCompliant(false)]
public static int StackallocThreshold { get; } = 1 + LibrarySettings.StackallocThreshold / Unsafe.SizeOf<T>();
private static bool UseNativeAllocation {
get {
if (!LibrarySettings.DisableNativeAllocation && !RuntimeHelpers.IsReferenceOrContainsReferences<T>())
return Intrinsics.AlignOf<T>() <= UIntPtr.Size;
return false;
}
}
[Nullable(new byte[] {
0,
1
})]
public Span<T> Span {
[IsReadOnly]
[return: Nullable(new byte[] {
0,
1
})]
get {
return memory;
}
}
public bool IsEmpty {
[IsReadOnly]
get {
return memory.IsEmpty;
}
}
public int Length {
[IsReadOnly]
get {
return memory.Length;
}
}
public ref T this[int index] {
[IsReadOnly]
get {
return ref memory[index];
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public SpanOwner([Nullable(new byte[] {
0,
1
})] Span<T> span)
{
owner = null;
memory = span;
}
public SpanOwner([Nullable(new byte[] {
0,
1
})] Span<T> span, int length)
{
this = new SpanOwner<T>(span.Slice(0, length));
}
public SpanOwner(MemoryPool<T> pool, int minBufferSize, bool exactSize = true)
{
ArgumentNullException.ThrowIfNull((object)pool, "pool");
ArgumentOutOfRangeException.ThrowIfNegativeOrZero<int>(minBufferSize, "minBufferSize");
IMemoryOwner<T> memoryOwner = pool.Rent(minBufferSize);
memory = memoryOwner.Memory.Span;
if (exactSize)
memory = memory.Slice(0, minBufferSize);
owner = memoryOwner;
}
public SpanOwner(MemoryPool<T> pool)
{
ArgumentNullException.ThrowIfNull((object)pool, "pool");
IMemoryOwner<T> memoryOwner = pool.Rent(-1);
memory = memoryOwner.Memory.Span;
owner = memoryOwner;
}
public unsafe SpanOwner(int minBufferSize, bool exactSize = true)
{
if (UseNativeAllocation) {
ArgumentOutOfRangeException.ThrowIfNegativeOrZero<int>(minBufferSize, "minBufferSize");
void* pointer = NativeMemory.Alloc((UIntPtr)(uint)minBufferSize, (UIntPtr)(uint)Unsafe.SizeOf<T>());
memory = new Span<T>(pointer, minBufferSize);
owner = Sentinel.Instance;
} else {
T[] array = ArrayPool<T>.Shared.Rent(minBufferSize);
memory = (exactSize ? new Span<T>(array, 0, minBufferSize) : new Span<T>(array));
owner = array;
}
}
public static implicit operator SpanOwner<T>([Nullable(new byte[] {
0,
1
})] Span<T> span)
{
return new SpanOwner<T>(span);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[IsReadOnly]
[EditorBrowsable(EditorBrowsableState.Never)]
public ref T GetPinnableReference()
{
return ref memory.GetPinnableReference();
}
[IsReadOnly]
public override string ToString()
{
return memory.ToString();
}
public unsafe void Dispose()
{
T[] array = owner as T[];
if (array != null)
ArrayPool<T>.Shared.Return(array, RuntimeHelpers.IsReferenceOrContainsReferences<T>());
else if (owner == Sentinel.Instance) {
NativeMemory.Free(Unsafe.AsPointer<T>(ref MemoryMarshal.GetReference<T>(memory)));
} else {
Unsafe.As<IDisposable>(owner)?.Dispose();
}
this = default(SpanOwner<T>);
}
}
}