DotNext by .NET Foundation and Contributors

<PackageReference Include="DotNext" Version="4.12.3" />

 MemoryOwner<T>

Represents unified representation of the memory rented using various types of memory pools.
using DotNext.Runtime.CompilerServices; using System; using System.Buffers; using System.ComponentModel; 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)] public struct MemoryOwner<[System.Runtime.CompilerServices.Nullable(2)] T> : IMemoryOwner<T>, IDisposable, ISupplier<Memory<T>>, IFunctional<Func<Memory<T>>>, ISupplier<ReadOnlyMemory<T>>, IFunctional<Func<ReadOnlyMemory<T>>> { private readonly object owner; private readonly T[] array; private int length; public int Length { [IsReadOnly] get { return length; } } private int RawLength { [MethodImpl(MethodImplOptions.AggressiveInlining)] [IsReadOnly] get { T[] obj = array; if (obj == null) { IMemoryOwner<T> memoryOwner = Unsafe.As<IMemoryOwner<T>>(owner); if (memoryOwner == null) return 0; return memoryOwner.Memory.Length; } return obj.Length; } } public bool IsEmpty { [IsReadOnly] get { return length == 0; } } [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public Memory<T> Memory { [IsReadOnly] [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] get { T[] obj = array; if (obj == null) { IMemoryOwner<T> memoryOwner = Unsafe.As<IMemoryOwner<T>>(owner); if (memoryOwner == null) return Memory<T>.Empty; return memoryOwner.Memory.Slice(0, length); } return MemoryExtensions.AsMemory<T>(obj, 0, length); } } [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public Span<T> Span { [IsReadOnly] [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] get { return MemoryMarshal.CreateSpan<T>(ref First, length); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] internal ref T First { [MethodImpl(MethodImplOptions.AggressiveInlining)] [IsReadOnly] get { if (array == null) { if (owner == null) return ref Unsafe.NullRef<T>(); return ref MemoryMarshal.GetReference<T>(Unsafe.As<IMemoryOwner<T>>(owner).Memory.Span); } return ref MemoryMarshal.GetArrayDataReference<T>(array); } } public ref T this[[System.Runtime.CompilerServices.NativeInteger] IntPtr index] { [IsReadOnly] get { if ((ulong)(long)index >= (ulong)length) <get_Item>g__ThrowArgumentOutOfRangeException|32_0(); return ref Unsafe.Add<T>(ref First, index); } } public ref T this[int index] { [IsReadOnly] get { return ref this[(IntPtr)index]; } } private MemoryOwner(IMemoryOwner<T> owner, int? length) { this.owner = (((this.length = (length ?? owner.Memory.Length)) > 0) ? owner : null); array = null; } internal MemoryOwner(ArrayPool<T> pool, T[] array, int length) { this.array = array; owner = pool; this.length = length; } internal MemoryOwner(ArrayPool<T> pool, int length, bool exactSize) { if (length == 0) this = default(MemoryOwner<T>); else { array = pool.Rent(length); owner = pool; this.length = (exactSize ? length : array.Length); } } public MemoryOwner(ArrayPool<T> pool, int length) { this = new MemoryOwner<T>(pool, length, true); } public MemoryOwner(MemoryPool<T> pool, int length = -1) { if (length == 0) this = default(MemoryOwner<T>); else { array = null; IMemoryOwner<T> memoryOwner = pool.Rent(length); if ((this.length = ((length < 0) ? memoryOwner.Memory.Length : length)) > 0) owner = memoryOwner; else { memoryOwner.Dispose(); owner = null; } } } public MemoryOwner(Func<int, IMemoryOwner<T>> provider, int length) { if (length < 0) throw new ArgumentOutOfRangeException("length"); if (length == 0) this = default(MemoryOwner<T>); else { array = null; IMemoryOwner<T> memoryOwner = provider(length); if ((this.length = Math.Min(memoryOwner.Memory.Length, length)) > 0) owner = memoryOwner; else { memoryOwner.Dispose(); owner = null; } } } public MemoryOwner(Func<IMemoryOwner<T>> provider) { array = null; IMemoryOwner<T> memoryOwner = provider(); if ((length = memoryOwner.Memory.Length) > 0) owner = memoryOwner; else { memoryOwner.Dispose(); owner = null; } } public MemoryOwner(T[] array, int length) { if ((uint)length > (uint)array.Length) throw new ArgumentOutOfRangeException("length"); this.array = ((length > 0) ? array : null); this.length = length; owner = null; } public MemoryOwner(T[] array) { this = new MemoryOwner<T>(array, array.Length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [CLSCompliant(false)] [EditorBrowsable(EditorBrowsableState.Advanced)] [return: System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1 })] public unsafe static MemoryOwner<T> Create<[System.Runtime.CompilerServices.Nullable(2)] TArg>([System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1, 1, 1 })] IntPtr provider, int length, TArg arg, bool exactSize = true) { if (provider == (IntPtr)(void*)null) throw new ArgumentNullException("provider"); if (length != 0) return new MemoryOwner<T>((IMemoryOwner<T>), exactSize ? new int?(length) : null); return default(MemoryOwner<T>); } internal void Expand() { length = RawLength; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void Truncate(int newLength) { length = Math.Min(length, newLength); } public bool TryResize(int newLength) { if (newLength < 0) throw new ArgumentOutOfRangeException("newLength"); if (newLength == 0) Dispose(); else { if (newLength > RawLength) return false; length = newLength; } return true; } [IsReadOnly] [Conditional("DEBUG")] private void AssertValid() { } [IsReadOnly] Memory<T> ISupplier<Memory<T>>.Invoke() { return Memory; } [IsReadOnly] ReadOnlyMemory<T> ISupplier<ReadOnlyMemory<T>>.Invoke() { return Memory; } [IsReadOnly] internal void Clear(bool clearBuffer) { if (array == null) Unsafe.As<IDisposable>(owner)?.Dispose(); else if (owner != null) { Unsafe.As<ArrayPool<T>>(owner).Return(array, clearBuffer); } else if (clearBuffer) { Array.Clear((Array)array); } } public void Dispose() { Clear(RuntimeHelpers.IsReferenceOrContainsReferences<T>()); this = default(MemoryOwner<T>); } } }