SpanReader<T>
struct SpanReader<T> where T : ValueType modreq(System.Runtime.InteropServices.UnmanagedType), IEquatable<T>
Fast stack based ReadOnlySpan<T> reader.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace System
{
[CompilerFeatureRequired("RefStructs")]
internal ref struct SpanReader<[IsUnmanaged] T> where T : struct, IEquatable<T>
{
private ReadOnlySpan<T> _unread;
public ReadOnlySpan<T> Span {
[IsReadOnly]
get;
}
public int Position {
[IsReadOnly]
get {
return Span.Length - _unread.Length;
}
set {
ReadOnlySpan<T> span = Span;
_unread = span.Slice(value, span.Length - value);
}
}
public SpanReader(ReadOnlySpan<T> span)
{
_unread = span;
Span = span;
}
public bool TryReadTo(T delimiter, out ReadOnlySpan<T> span)
{
return TryReadTo(delimiter, true, out span);
}
public bool TryReadTo(T delimiter, bool advancePastDelimiter, out ReadOnlySpan<T> span)
{
bool result = false;
int num = MemoryExtensions.IndexOf<T>(_unread, delimiter);
span = default(ReadOnlySpan<T>);
if (num != -1) {
result = true;
if (num > 0) {
span = _unread;
UncheckedSliceTo(ref span, num);
if (advancePastDelimiter)
num++;
UnsafeAdvance(num);
}
}
return result;
}
public bool TryRead(out T value)
{
bool result;
if (_unread.IsEmpty) {
value = default(T);
result = false;
} else {
result = true;
value = _unread[0];
UnsafeAdvance(1);
}
return result;
}
public bool TryRead(int count, out ReadOnlySpan<T> span)
{
bool result;
if (count > _unread.Length) {
span = default(ReadOnlySpan<T>);
result = false;
} else {
result = true;
span = _unread.Slice(0, count);
UnsafeAdvance(count);
}
return result;
}
public unsafe bool TryRead<[IsUnmanaged] TValue>(out TValue value) where TValue : struct
{
if (sizeof(TValue) < sizeof(T) || sizeof(TValue) % sizeof(T) != 0)
throw new ArgumentException("The size of TValue must be evenly divisible by the size of T.");
bool result;
if (sizeof(TValue) > this._unread.Length * sizeof(T)) {
value = default(TValue);
result = false;
} else {
result = true;
value = Unsafe.ReadUnaligned<TValue>(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference<T>(this._unread)));
this.UnsafeAdvance(sizeof(TValue) / sizeof(T));
}
return result;
}
public unsafe bool TryRead<[IsUnmanaged] TValue>(int count, out ReadOnlySpan<TValue> value) where TValue : struct
{
if (sizeof(TValue) < sizeof(T) || sizeof(TValue) % sizeof(T) != 0)
throw new ArgumentException("The size of TValue must be evenly divisible by the size of T.");
bool result;
if (sizeof(TValue) * count > this._unread.Length * sizeof(T)) {
value = default(ReadOnlySpan<TValue>);
result = false;
} else {
result = true;
value = MemoryMarshal.CreateReadOnlySpan<TValue>(ref Unsafe.As<T, TValue>(ref MemoryMarshal.GetReference<T>(this._unread)), count);
this.UnsafeAdvance(sizeof(TValue) / sizeof(T) * count);
}
return result;
}
[IsReadOnly]
public bool IsNext([ParamCollection] [ScopedRef] ReadOnlySpan<T> next)
{
return MemoryExtensions.StartsWith<T>(_unread, next);
}
public bool TryAdvancePast([ParamCollection] [ScopedRef] ReadOnlySpan<T> next)
{
bool result = false;
if (MemoryExtensions.StartsWith<T>(_unread, next)) {
UnsafeAdvance(next.Length);
result = true;
}
return result;
}
public int AdvancePast(T value)
{
int result = 0;
int num = MemoryExtensions.IndexOfAnyExcept<T>(_unread, value);
switch (num) {
case -1:
result = _unread.Length;
_unread = default(ReadOnlySpan<T>);
break;
default:
result = num;
UnsafeAdvance(num);
break;
case 0:
break;
}
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Advance(int count)
{
ref ReadOnlySpan<T> unread = ref _unread;
_unread = unread.Slice(count, unread.Length - count);
}
public void Rewind(int count)
{
ReadOnlySpan<T> span = Span;
int num = Span.Length - _unread.Length - count;
_unread = span.Slice(num, span.Length - num);
}
public void Reset()
{
_unread = Span;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void UnsafeAdvance(int count)
{
UncheckedSlice(ref _unread, count, _unread.Length - count);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void UncheckedSliceTo(ref ReadOnlySpan<T> span, int length)
{
span = MemoryMarshal.CreateReadOnlySpan<T>(ref MemoryMarshal.GetReference<T>(span), length);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe static void UncheckedSlice(ref ReadOnlySpan<T> span, int start, int length)
{
span = MemoryMarshal.CreateReadOnlySpan<T>(ref Unsafe.Add<T>(ref MemoryMarshal.GetReference<T>(span), (IntPtr)(void*)(uint)start), length);
}
}
}