Files
2026-08-27 10:56:38 -06:00

399 lines
10 KiB
C#

using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace System;
[DebuggerTypeProxy(typeof(System.SpanDebugView<>))]
[DebuggerDisplay("{ToString(),raw}")]
[DebuggerTypeProxy(typeof(System.SpanDebugView<>))]
[DebuggerDisplay("{ToString(),raw}")]
public readonly ref struct Span<T>
{
public ref struct Enumerator
{
private readonly Span<T> _span;
private int _index;
public ref T Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return ref _span[_index];
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Enumerator(Span<T> span)
{
_span = span;
_index = -1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
int num = _index + 1;
if (num < _span.Length)
{
_index = num;
return true;
}
return false;
}
}
private readonly Pinnable<T> _pinnable;
private readonly IntPtr _byteOffset;
private readonly int _length;
public int Length => _length;
public bool IsEmpty => _length == 0;
public static Span<T> Empty => default(Span<T>);
public unsafe ref T this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
if ((uint)index >= (uint)_length)
{
System.ThrowHelper.ThrowIndexOutOfRangeException();
}
if (_pinnable == null)
{
IntPtr byteOffset = _byteOffset;
return ref Unsafe.Add(ref Unsafe.AsRef<T>(byteOffset.ToPointer()), index);
}
return ref Unsafe.Add(ref Unsafe.AddByteOffset(ref _pinnable.Data, _byteOffset), index);
}
}
internal Pinnable<T> Pinnable => _pinnable;
internal IntPtr ByteOffset => _byteOffset;
public static bool operator !=(Span<T> left, Span<T> right)
{
return !(left == right);
}
[Obsolete("Equals() on Span will always throw an exception. Use == instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals(object obj)
{
throw new NotSupportedException(System.SR.NotSupported_CannotCallEqualsOnSpan);
}
[Obsolete("GetHashCode() on Span will always throw an exception.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode()
{
throw new NotSupportedException(System.SR.NotSupported_CannotCallGetHashCodeOnSpan);
}
public static implicit operator Span<T>(T[] array)
{
return new Span<T>(array);
}
public static implicit operator Span<T>(ArraySegment<T> segment)
{
return new Span<T>(segment.Array, segment.Offset, segment.Count);
}
public Enumerator GetEnumerator()
{
return new Enumerator(this);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span(T[] array)
{
if (array == null)
{
this = default(Span<T>);
return;
}
if (default(T) == null && array.GetType() != typeof(T[]))
{
System.ThrowHelper.ThrowArrayTypeMismatchException();
}
_length = array.Length;
_pinnable = Unsafe.As<Pinnable<T>>(array);
_byteOffset = System.SpanHelpers.PerTypeValues<T>.ArrayAdjustment;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Span<T> Create(T[] array, int start)
{
if (array == null)
{
if (start != 0)
{
System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.start);
}
return default(Span<T>);
}
if (default(T) == null && array.GetType() != typeof(T[]))
{
System.ThrowHelper.ThrowArrayTypeMismatchException();
}
if ((uint)start > (uint)array.Length)
{
System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.start);
}
IntPtr byteOffset = System.SpanHelpers.PerTypeValues<T>.ArrayAdjustment.Add<T>(start);
int length = array.Length - start;
return new Span<T>(Unsafe.As<Pinnable<T>>(array), byteOffset, length);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span(T[] array, int start, int length)
{
if (array == null)
{
if (start != 0 || length != 0)
{
System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.start);
}
this = default(Span<T>);
return;
}
if (default(T) == null && array.GetType() != typeof(T[]))
{
System.ThrowHelper.ThrowArrayTypeMismatchException();
}
if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
{
System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.start);
}
_length = length;
_pinnable = Unsafe.As<Pinnable<T>>(array);
_byteOffset = System.SpanHelpers.PerTypeValues<T>.ArrayAdjustment.Add<T>(start);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[CLSCompliant(false)]
public unsafe Span(void* pointer, int length)
{
if (System.SpanHelpers.IsReferenceOrContainsReferences<T>())
{
System.ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
}
if (length < 0)
{
System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.start);
}
_length = length;
_pinnable = null;
_byteOffset = new IntPtr(pointer);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Span(Pinnable<T> pinnable, IntPtr byteOffset, int length)
{
_length = length;
_pinnable = pinnable;
_byteOffset = byteOffset;
}
[EditorBrowsable(EditorBrowsableState.Never)]
public unsafe ref T GetPinnableReference()
{
if (_length != 0)
{
if (_pinnable == null)
{
IntPtr byteOffset = _byteOffset;
return ref Unsafe.AsRef<T>(byteOffset.ToPointer());
}
return ref Unsafe.AddByteOffset(ref _pinnable.Data, _byteOffset);
}
return ref Unsafe.AsRef<T>(null);
}
public unsafe void Clear()
{
int length = _length;
if (length == 0)
{
return;
}
UIntPtr byteLength = (UIntPtr)(ulong)((uint)length * Unsafe.SizeOf<T>());
if ((Unsafe.SizeOf<T>() & (sizeof(IntPtr) - 1)) != 0)
{
if (_pinnable == null)
{
IntPtr byteOffset = _byteOffset;
byte* ptr = (byte*)byteOffset.ToPointer();
System.SpanHelpers.ClearLessThanPointerSized(ptr, byteLength);
}
else
{
System.SpanHelpers.ClearLessThanPointerSized(ref Unsafe.As<T, byte>(ref Unsafe.AddByteOffset(ref _pinnable.Data, _byteOffset)), byteLength);
}
}
else if (System.SpanHelpers.IsReferenceOrContainsReferences<T>())
{
UIntPtr pointerSizeLength = (UIntPtr)(ulong)(length * Unsafe.SizeOf<T>() / sizeof(IntPtr));
System.SpanHelpers.ClearPointerSizedWithReferences(ref Unsafe.As<T, IntPtr>(ref DangerousGetPinnableReference()), pointerSizeLength);
}
else
{
System.SpanHelpers.ClearPointerSizedWithoutReferences(ref Unsafe.As<T, byte>(ref DangerousGetPinnableReference()), byteLength);
}
}
public unsafe void Fill(T value)
{
int length = _length;
if (length == 0)
{
return;
}
if (Unsafe.SizeOf<T>() == 1)
{
byte value2 = Unsafe.As<T, byte>(ref value);
if (_pinnable == null)
{
IntPtr byteOffset = _byteOffset;
Unsafe.InitBlockUnaligned(byteOffset.ToPointer(), value2, (uint)length);
}
else
{
Unsafe.InitBlockUnaligned(ref Unsafe.As<T, byte>(ref Unsafe.AddByteOffset(ref _pinnable.Data, _byteOffset)), value2, (uint)length);
}
return;
}
ref T source = ref DangerousGetPinnableReference();
int i;
for (i = 0; i < (length & -8); i += 8)
{
Unsafe.Add(ref source, i) = value;
Unsafe.Add(ref source, i + 1) = value;
Unsafe.Add(ref source, i + 2) = value;
Unsafe.Add(ref source, i + 3) = value;
Unsafe.Add(ref source, i + 4) = value;
Unsafe.Add(ref source, i + 5) = value;
Unsafe.Add(ref source, i + 6) = value;
Unsafe.Add(ref source, i + 7) = value;
}
if (i < (length & -4))
{
Unsafe.Add(ref source, i) = value;
Unsafe.Add(ref source, i + 1) = value;
Unsafe.Add(ref source, i + 2) = value;
Unsafe.Add(ref source, i + 3) = value;
i += 4;
}
for (; i < length; i++)
{
Unsafe.Add(ref source, i) = value;
}
}
public void CopyTo(Span<T> destination)
{
if (!TryCopyTo(destination))
{
System.ThrowHelper.ThrowArgumentException_DestinationTooShort();
}
}
public bool TryCopyTo(Span<T> destination)
{
int length = _length;
int length2 = destination._length;
if (length == 0)
{
return true;
}
if ((uint)length > (uint)length2)
{
return false;
}
ref T src = ref DangerousGetPinnableReference();
System.SpanHelpers.CopyTo(ref destination.DangerousGetPinnableReference(), length2, ref src, length);
return true;
}
public static bool operator ==(Span<T> left, Span<T> right)
{
if (left._length == right._length)
{
return Unsafe.AreSame(in left.DangerousGetPinnableReference(), in right.DangerousGetPinnableReference());
}
return false;
}
public static implicit operator ReadOnlySpan<T>(Span<T> span)
{
return new ReadOnlySpan<T>(span._pinnable, span._byteOffset, span._length);
}
public unsafe override string ToString()
{
if (typeof(T) == typeof(char))
{
fixed (char* value = &Unsafe.As<T, char>(ref DangerousGetPinnableReference()))
{
return new string(value, 0, _length);
}
}
return $"System.Span<{typeof(T).Name}>[{_length}]";
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<T> Slice(int start)
{
if ((uint)start > (uint)_length)
{
System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.start);
}
IntPtr byteOffset = _byteOffset.Add<T>(start);
int length = _length - start;
return new Span<T>(_pinnable, byteOffset, length);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<T> Slice(int start, int length)
{
if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
{
System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.start);
}
IntPtr byteOffset = _byteOffset.Add<T>(start);
return new Span<T>(_pinnable, byteOffset, length);
}
public T[] ToArray()
{
if (_length == 0)
{
return System.SpanHelpers.PerTypeValues<T>.EmptyArray;
}
T[] array = new T[_length];
CopyTo(array);
return array;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[EditorBrowsable(EditorBrowsableState.Never)]
internal unsafe ref T DangerousGetPinnableReference()
{
if (_pinnable == null)
{
IntPtr byteOffset = _byteOffset;
return ref Unsafe.AsRef<T>(byteOffset.ToPointer());
}
return ref Unsafe.AddByteOffset(ref _pinnable.Data, _byteOffset);
}
}