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

290 lines
7.1 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 ReadOnlySpan<T>
{
public ref struct Enumerator
{
private readonly ReadOnlySpan<T> _span;
private int _index;
public ref readonly T Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return ref _span[_index];
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Enumerator(ReadOnlySpan<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 ReadOnlySpan<T> Empty => default(ReadOnlySpan<T>);
public unsafe ref readonly 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 !=(ReadOnlySpan<T> left, ReadOnlySpan<T> right)
{
return !(left == right);
}
[Obsolete("Equals() on ReadOnlySpan 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 ReadOnlySpan will always throw an exception.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode()
{
throw new NotSupportedException(System.SR.NotSupported_CannotCallGetHashCodeOnSpan);
}
public static implicit operator ReadOnlySpan<T>(T[] array)
{
return new ReadOnlySpan<T>(array);
}
public static implicit operator ReadOnlySpan<T>(ArraySegment<T> segment)
{
return new ReadOnlySpan<T>(segment.Array, segment.Offset, segment.Count);
}
public Enumerator GetEnumerator()
{
return new Enumerator(this);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan(T[] array)
{
if (array == null)
{
this = default(ReadOnlySpan<T>);
return;
}
_length = array.Length;
_pinnable = Unsafe.As<Pinnable<T>>(array);
_byteOffset = System.SpanHelpers.PerTypeValues<T>.ArrayAdjustment;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan(T[] array, int start, int length)
{
if (array == null)
{
if (start != 0 || length != 0)
{
System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.start);
}
this = default(ReadOnlySpan<T>);
return;
}
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 ReadOnlySpan(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 ReadOnlySpan(Pinnable<T> pinnable, IntPtr byteOffset, int length)
{
_length = length;
_pinnable = pinnable;
_byteOffset = byteOffset;
}
[EditorBrowsable(EditorBrowsableState.Never)]
public unsafe ref readonly 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 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 ==(ReadOnlySpan<T> left, ReadOnlySpan<T> right)
{
if (left._length == right._length)
{
return Unsafe.AreSame(in left.DangerousGetPinnableReference(), in right.DangerousGetPinnableReference());
}
return false;
}
public unsafe override string ToString()
{
if (typeof(T) == typeof(char))
{
if (_byteOffset == MemoryExtensions.StringAdjustment)
{
object obj = Unsafe.As<object>(_pinnable);
if (obj is string text && _length == text.Length)
{
return text;
}
}
fixed (char* value = &Unsafe.As<T, char>(ref DangerousGetPinnableReference()))
{
return new string(value, 0, _length);
}
}
return $"System.ReadOnlySpan<{typeof(T).Name}>[{_length}]";
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<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 ReadOnlySpan<T>(_pinnable, byteOffset, length);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<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 ReadOnlySpan<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);
}
}