initial commit
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace System.Buffers;
|
||||
|
||||
internal sealed class ArrayMemoryPool<T> : MemoryPool<T>
|
||||
{
|
||||
private sealed class ArrayMemoryPoolBuffer : IMemoryOwner<T>, IDisposable
|
||||
{
|
||||
private T[] _array;
|
||||
|
||||
public Memory<T> Memory
|
||||
{
|
||||
get
|
||||
{
|
||||
T[] array = _array;
|
||||
if (array == null)
|
||||
{
|
||||
System.ThrowHelper.ThrowObjectDisposedException_ArrayMemoryPoolBuffer();
|
||||
}
|
||||
return new Memory<T>(array);
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayMemoryPoolBuffer(int size)
|
||||
{
|
||||
_array = ArrayPool<T>.Shared.Rent(size);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
T[] array = _array;
|
||||
if (array != null)
|
||||
{
|
||||
_array = null;
|
||||
ArrayPool<T>.Shared.Return(array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const int s_maxBufferSize = int.MaxValue;
|
||||
|
||||
public sealed override int MaxBufferSize => int.MaxValue;
|
||||
|
||||
public sealed override IMemoryOwner<T> Rent(int minimumBufferSize = -1)
|
||||
{
|
||||
if (minimumBufferSize == -1)
|
||||
{
|
||||
minimumBufferSize = 1 + 4095 / Unsafe.SizeOf<T>();
|
||||
}
|
||||
else if ((uint)minimumBufferSize > 2147483647u)
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.minimumBufferSize);
|
||||
}
|
||||
return new ArrayMemoryPoolBuffer(minimumBufferSize);
|
||||
}
|
||||
|
||||
protected sealed override void Dispose(bool disposing)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace System.Buffers;
|
||||
|
||||
public static class BuffersExtensions
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static SequencePosition? PositionOf<T>(this in ReadOnlySequence<T> source, T value) where T : IEquatable<T>
|
||||
{
|
||||
if (source.IsSingleSegment)
|
||||
{
|
||||
int num = source.First.Span.IndexOf(value);
|
||||
if (num != -1)
|
||||
{
|
||||
return source.GetPosition(num);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return PositionOfMultiSegment(in source, value);
|
||||
}
|
||||
|
||||
private static SequencePosition? PositionOfMultiSegment<T>(in ReadOnlySequence<T> source, T value) where T : IEquatable<T>
|
||||
{
|
||||
SequencePosition position = source.Start;
|
||||
SequencePosition origin = position;
|
||||
ReadOnlyMemory<T> memory;
|
||||
while (source.TryGet(ref position, out memory))
|
||||
{
|
||||
int num = memory.Span.IndexOf(value);
|
||||
if (num != -1)
|
||||
{
|
||||
return source.GetPosition(num, origin);
|
||||
}
|
||||
if (position.GetObject() == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
origin = position;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void CopyTo<T>(this in ReadOnlySequence<T> source, Span<T> destination)
|
||||
{
|
||||
if (source.Length > destination.Length)
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.destination);
|
||||
}
|
||||
if (source.IsSingleSegment)
|
||||
{
|
||||
source.First.Span.CopyTo(destination);
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyToMultiSegment(in source, destination);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CopyToMultiSegment<T>(in ReadOnlySequence<T> sequence, Span<T> destination)
|
||||
{
|
||||
SequencePosition position = sequence.Start;
|
||||
ReadOnlyMemory<T> memory;
|
||||
while (sequence.TryGet(ref position, out memory))
|
||||
{
|
||||
ReadOnlySpan<T> span = memory.Span;
|
||||
span.CopyTo(destination);
|
||||
if (position.GetObject() != null)
|
||||
{
|
||||
destination = destination.Slice(span.Length);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static T[] ToArray<T>(this in ReadOnlySequence<T> sequence)
|
||||
{
|
||||
T[] array = new T[sequence.Length];
|
||||
sequence.CopyTo(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Write<T>(this IBufferWriter<T> writer, ReadOnlySpan<T> value)
|
||||
{
|
||||
Span<T> span = writer.GetSpan();
|
||||
if (value.Length <= span.Length)
|
||||
{
|
||||
value.CopyTo(span);
|
||||
writer.Advance(value.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteMultiSegment(writer, in value, span);
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteMultiSegment<T>(IBufferWriter<T> writer, in ReadOnlySpan<T> source, Span<T> destination)
|
||||
{
|
||||
ReadOnlySpan<T> readOnlySpan = source;
|
||||
while (true)
|
||||
{
|
||||
int num = Math.Min(destination.Length, readOnlySpan.Length);
|
||||
readOnlySpan.Slice(0, num).CopyTo(destination);
|
||||
writer.Advance(num);
|
||||
readOnlySpan = readOnlySpan.Slice(num);
|
||||
if (readOnlySpan.Length > 0)
|
||||
{
|
||||
destination = writer.GetSpan(readOnlySpan.Length);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace System.Buffers;
|
||||
|
||||
public interface IBufferWriter<T>
|
||||
{
|
||||
void Advance(int count);
|
||||
|
||||
Memory<T> GetMemory(int sizeHint = 0);
|
||||
|
||||
Span<T> GetSpan(int sizeHint = 0);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace System.Buffers;
|
||||
|
||||
public interface IMemoryOwner<T> : IDisposable
|
||||
{
|
||||
Memory<T> Memory { get; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace System.Buffers;
|
||||
|
||||
public interface IPinnable
|
||||
{
|
||||
MemoryHandle Pin(int elementIndex);
|
||||
|
||||
void Unpin();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace System.Buffers;
|
||||
|
||||
public unsafe struct MemoryHandle(void* pointer, GCHandle handle = default(GCHandle), IPinnable pinnable = null) : IDisposable
|
||||
{
|
||||
private unsafe void* _pointer = pointer;
|
||||
|
||||
private GCHandle _handle = handle;
|
||||
|
||||
private IPinnable _pinnable = pinnable;
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public unsafe void* Pointer => _pointer;
|
||||
|
||||
public unsafe void Dispose()
|
||||
{
|
||||
if (_handle.IsAllocated)
|
||||
{
|
||||
_handle.Free();
|
||||
}
|
||||
if (_pinnable != null)
|
||||
{
|
||||
_pinnable.Unpin();
|
||||
_pinnable = null;
|
||||
}
|
||||
_pointer = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace System.Buffers;
|
||||
|
||||
public abstract class MemoryManager<T> : IMemoryOwner<T>, IDisposable, IPinnable
|
||||
{
|
||||
public virtual Memory<T> Memory => new Memory<T>(this, GetSpan().Length);
|
||||
|
||||
public abstract Span<T> GetSpan();
|
||||
|
||||
public abstract MemoryHandle Pin(int elementIndex = 0);
|
||||
|
||||
public abstract void Unpin();
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected Memory<T> CreateMemory(int length)
|
||||
{
|
||||
return new Memory<T>(this, length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected Memory<T> CreateMemory(int start, int length)
|
||||
{
|
||||
return new Memory<T>(this, start, length);
|
||||
}
|
||||
|
||||
protected internal virtual bool TryGetArray(out ArraySegment<T> segment)
|
||||
{
|
||||
segment = default(ArraySegment<T>);
|
||||
return false;
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected abstract void Dispose(bool disposing);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace System.Buffers;
|
||||
|
||||
public abstract class MemoryPool<T> : IDisposable
|
||||
{
|
||||
private static readonly MemoryPool<T> s_shared = new System.Buffers.ArrayMemoryPool<T>();
|
||||
|
||||
public static MemoryPool<T> Shared => s_shared;
|
||||
|
||||
public abstract int MaxBufferSize { get; }
|
||||
|
||||
public abstract IMemoryOwner<T> Rent(int minBufferSize = -1);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected abstract void Dispose(bool disposing);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace System.Buffers;
|
||||
|
||||
public enum OperationStatus
|
||||
{
|
||||
Done,
|
||||
DestinationTooSmall,
|
||||
NeedMoreData,
|
||||
InvalidData
|
||||
}
|
||||
@@ -0,0 +1,760 @@
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace System.Buffers;
|
||||
|
||||
[DebuggerTypeProxy(typeof(System.Buffers.ReadOnlySequenceDebugView<>))]
|
||||
[DebuggerDisplay("{ToString(),raw}")]
|
||||
public readonly struct ReadOnlySequence<T>
|
||||
{
|
||||
public struct Enumerator(in ReadOnlySequence<T> sequence)
|
||||
{
|
||||
private readonly ReadOnlySequence<T> _sequence = sequence;
|
||||
|
||||
private SequencePosition _next = sequence.Start;
|
||||
|
||||
private ReadOnlyMemory<T> _currentMemory = default(ReadOnlyMemory<T>);
|
||||
|
||||
public ReadOnlyMemory<T> Current => _currentMemory;
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_next.GetObject() == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return _sequence.TryGet(ref _next, out _currentMemory);
|
||||
}
|
||||
}
|
||||
|
||||
private enum SequenceType
|
||||
{
|
||||
MultiSegment,
|
||||
Array,
|
||||
MemoryManager,
|
||||
String,
|
||||
Empty
|
||||
}
|
||||
|
||||
private readonly SequencePosition _sequenceStart;
|
||||
|
||||
private readonly SequencePosition _sequenceEnd;
|
||||
|
||||
public static readonly ReadOnlySequence<T> Empty;
|
||||
|
||||
public long Length => GetLength();
|
||||
|
||||
public bool IsEmpty => Length == 0;
|
||||
|
||||
public bool IsSingleSegment
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get
|
||||
{
|
||||
return _sequenceStart.GetObject() == _sequenceEnd.GetObject();
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlyMemory<T> First => GetFirstBuffer();
|
||||
|
||||
public SequencePosition Start => _sequenceStart;
|
||||
|
||||
public SequencePosition End => _sequenceEnd;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private ReadOnlySequence(object startSegment, int startIndexAndFlags, object endSegment, int endIndexAndFlags)
|
||||
{
|
||||
_sequenceStart = new SequencePosition(startSegment, startIndexAndFlags);
|
||||
_sequenceEnd = new SequencePosition(endSegment, endIndexAndFlags);
|
||||
}
|
||||
|
||||
public ReadOnlySequence(ReadOnlySequenceSegment<T> startSegment, int startIndex, ReadOnlySequenceSegment<T> endSegment, int endIndex)
|
||||
{
|
||||
if (startSegment == null || endSegment == null || (startSegment != endSegment && startSegment.RunningIndex > endSegment.RunningIndex) || (uint)startSegment.Memory.Length < (uint)startIndex || (uint)endSegment.Memory.Length < (uint)endIndex || (startSegment == endSegment && endIndex < startIndex))
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentValidationException(startSegment, startIndex, endSegment);
|
||||
}
|
||||
_sequenceStart = new SequencePosition(startSegment, System.Buffers.ReadOnlySequence.SegmentToSequenceStart(startIndex));
|
||||
_sequenceEnd = new SequencePosition(endSegment, System.Buffers.ReadOnlySequence.SegmentToSequenceEnd(endIndex));
|
||||
}
|
||||
|
||||
public ReadOnlySequence(T[] array)
|
||||
{
|
||||
if (array == null)
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentNullException(System.ExceptionArgument.array);
|
||||
}
|
||||
_sequenceStart = new SequencePosition(array, System.Buffers.ReadOnlySequence.ArrayToSequenceStart(0));
|
||||
_sequenceEnd = new SequencePosition(array, System.Buffers.ReadOnlySequence.ArrayToSequenceEnd(array.Length));
|
||||
}
|
||||
|
||||
public ReadOnlySequence(T[] array, int start, int length)
|
||||
{
|
||||
if (array == null || (uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentValidationException(array, start);
|
||||
}
|
||||
_sequenceStart = new SequencePosition(array, System.Buffers.ReadOnlySequence.ArrayToSequenceStart(start));
|
||||
_sequenceEnd = new SequencePosition(array, System.Buffers.ReadOnlySequence.ArrayToSequenceEnd(start + length));
|
||||
}
|
||||
|
||||
public ReadOnlySequence(ReadOnlyMemory<T> memory)
|
||||
{
|
||||
ArraySegment<T> segment;
|
||||
if (MemoryMarshal.TryGetMemoryManager<T, MemoryManager<T>>(memory, out var manager, out var start, out var length))
|
||||
{
|
||||
_sequenceStart = new SequencePosition(manager, System.Buffers.ReadOnlySequence.MemoryManagerToSequenceStart(start));
|
||||
_sequenceEnd = new SequencePosition(manager, System.Buffers.ReadOnlySequence.MemoryManagerToSequenceEnd(start + length));
|
||||
}
|
||||
else if (MemoryMarshal.TryGetArray(memory, out segment))
|
||||
{
|
||||
T[] array = segment.Array;
|
||||
int offset = segment.Offset;
|
||||
_sequenceStart = new SequencePosition(array, System.Buffers.ReadOnlySequence.ArrayToSequenceStart(offset));
|
||||
_sequenceEnd = new SequencePosition(array, System.Buffers.ReadOnlySequence.ArrayToSequenceEnd(offset + segment.Count));
|
||||
}
|
||||
else if (typeof(T) == typeof(char))
|
||||
{
|
||||
if (!MemoryMarshal.TryGetString((ReadOnlyMemory<char>)(object)memory, out var text, out var start2, out length))
|
||||
{
|
||||
System.ThrowHelper.ThrowInvalidOperationException();
|
||||
}
|
||||
_sequenceStart = new SequencePosition(text, System.Buffers.ReadOnlySequence.StringToSequenceStart(start2));
|
||||
_sequenceEnd = new SequencePosition(text, System.Buffers.ReadOnlySequence.StringToSequenceEnd(start2 + length));
|
||||
}
|
||||
else
|
||||
{
|
||||
System.ThrowHelper.ThrowInvalidOperationException();
|
||||
_sequenceStart = default(SequencePosition);
|
||||
_sequenceEnd = default(SequencePosition);
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlySequence<T> Slice(long start, long length)
|
||||
{
|
||||
if (start < 0 || length < 0)
|
||||
{
|
||||
System.ThrowHelper.ThrowStartOrEndArgumentValidationException(start);
|
||||
}
|
||||
int index = GetIndex(in _sequenceStart);
|
||||
int index2 = GetIndex(in _sequenceEnd);
|
||||
object obj = _sequenceStart.GetObject();
|
||||
object obj2 = _sequenceEnd.GetObject();
|
||||
SequencePosition position;
|
||||
SequencePosition end;
|
||||
if (obj != obj2)
|
||||
{
|
||||
ReadOnlySequenceSegment<T> readOnlySequenceSegment = (ReadOnlySequenceSegment<T>)obj;
|
||||
int num = readOnlySequenceSegment.Memory.Length - index;
|
||||
if (num > start)
|
||||
{
|
||||
index += (int)start;
|
||||
position = new SequencePosition(obj, index);
|
||||
end = GetEndPosition(readOnlySequenceSegment, obj, index, obj2, index2, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num < 0)
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
|
||||
}
|
||||
position = SeekMultiSegment(readOnlySequenceSegment.Next, obj2, index2, start - num, System.ExceptionArgument.start);
|
||||
int index3 = GetIndex(in position);
|
||||
object obj3 = position.GetObject();
|
||||
if (obj3 != obj2)
|
||||
{
|
||||
end = GetEndPosition((ReadOnlySequenceSegment<T>)obj3, obj3, index3, obj2, index2, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index2 - index3 < length)
|
||||
{
|
||||
System.ThrowHelper.ThrowStartOrEndArgumentValidationException(0L);
|
||||
}
|
||||
end = new SequencePosition(obj3, index3 + (int)length);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index2 - index < start)
|
||||
{
|
||||
System.ThrowHelper.ThrowStartOrEndArgumentValidationException(-1L);
|
||||
}
|
||||
index += (int)start;
|
||||
position = new SequencePosition(obj, index);
|
||||
if (index2 - index < length)
|
||||
{
|
||||
System.ThrowHelper.ThrowStartOrEndArgumentValidationException(0L);
|
||||
}
|
||||
end = new SequencePosition(obj, index + (int)length);
|
||||
}
|
||||
return SliceImpl(in position, in end);
|
||||
}
|
||||
|
||||
public ReadOnlySequence<T> Slice(long start, SequencePosition end)
|
||||
{
|
||||
if (start < 0)
|
||||
{
|
||||
System.ThrowHelper.ThrowStartOrEndArgumentValidationException(start);
|
||||
}
|
||||
uint index = (uint)GetIndex(in end);
|
||||
object obj = end.GetObject();
|
||||
uint index2 = (uint)GetIndex(in _sequenceStart);
|
||||
object obj2 = _sequenceStart.GetObject();
|
||||
uint index3 = (uint)GetIndex(in _sequenceEnd);
|
||||
object obj3 = _sequenceEnd.GetObject();
|
||||
if (obj2 == obj3)
|
||||
{
|
||||
if (!InRange(index, index2, index3))
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
|
||||
}
|
||||
if (index - index2 < start)
|
||||
{
|
||||
System.ThrowHelper.ThrowStartOrEndArgumentValidationException(-1L);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadOnlySequenceSegment<T> readOnlySequenceSegment = (ReadOnlySequenceSegment<T>)obj2;
|
||||
ulong num = (ulong)(readOnlySequenceSegment.RunningIndex + index2);
|
||||
ulong num2 = (ulong)(((ReadOnlySequenceSegment<T>)obj).RunningIndex + index);
|
||||
if (!InRange(num2, num, (ulong)(((ReadOnlySequenceSegment<T>)obj3).RunningIndex + index3)))
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
|
||||
}
|
||||
if ((ulong)((long)num + start) > num2)
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.start);
|
||||
}
|
||||
int num3 = readOnlySequenceSegment.Memory.Length - (int)index2;
|
||||
if (num3 <= start)
|
||||
{
|
||||
if (num3 < 0)
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
|
||||
}
|
||||
return SliceImpl(SeekMultiSegment(readOnlySequenceSegment.Next, obj, (int)index, start - num3, System.ExceptionArgument.start), in end);
|
||||
}
|
||||
}
|
||||
return SliceImpl(new SequencePosition(obj2, (int)index2 + (int)start), in end);
|
||||
}
|
||||
|
||||
public ReadOnlySequence<T> Slice(SequencePosition start, long length)
|
||||
{
|
||||
uint index = (uint)GetIndex(in start);
|
||||
object obj = start.GetObject();
|
||||
uint index2 = (uint)GetIndex(in _sequenceStart);
|
||||
object obj2 = _sequenceStart.GetObject();
|
||||
uint index3 = (uint)GetIndex(in _sequenceEnd);
|
||||
object obj3 = _sequenceEnd.GetObject();
|
||||
if (obj2 == obj3)
|
||||
{
|
||||
if (!InRange(index, index2, index3))
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
|
||||
}
|
||||
if (length < 0)
|
||||
{
|
||||
System.ThrowHelper.ThrowStartOrEndArgumentValidationException(0L);
|
||||
}
|
||||
if (index3 - index < length)
|
||||
{
|
||||
System.ThrowHelper.ThrowStartOrEndArgumentValidationException(0L);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadOnlySequenceSegment<T> readOnlySequenceSegment = (ReadOnlySequenceSegment<T>)obj;
|
||||
ulong num = (ulong)(readOnlySequenceSegment.RunningIndex + index);
|
||||
ulong start2 = (ulong)(((ReadOnlySequenceSegment<T>)obj2).RunningIndex + index2);
|
||||
ulong num2 = (ulong)(((ReadOnlySequenceSegment<T>)obj3).RunningIndex + index3);
|
||||
if (!InRange(num, start2, num2))
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
|
||||
}
|
||||
if (length < 0)
|
||||
{
|
||||
System.ThrowHelper.ThrowStartOrEndArgumentValidationException(0L);
|
||||
}
|
||||
if ((ulong)((long)num + length) > num2)
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.length);
|
||||
}
|
||||
int num3 = readOnlySequenceSegment.Memory.Length - (int)index;
|
||||
if (num3 < length)
|
||||
{
|
||||
if (num3 < 0)
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
|
||||
}
|
||||
return SliceImpl(in start, SeekMultiSegment(readOnlySequenceSegment.Next, obj3, (int)index3, length - num3, System.ExceptionArgument.length));
|
||||
}
|
||||
}
|
||||
return SliceImpl(in start, new SequencePosition(obj, (int)index + (int)length));
|
||||
}
|
||||
|
||||
public ReadOnlySequence<T> Slice(int start, int length)
|
||||
{
|
||||
return Slice((long)start, (long)length);
|
||||
}
|
||||
|
||||
public ReadOnlySequence<T> Slice(int start, SequencePosition end)
|
||||
{
|
||||
return Slice((long)start, end);
|
||||
}
|
||||
|
||||
public ReadOnlySequence<T> Slice(SequencePosition start, int length)
|
||||
{
|
||||
return Slice(start, (long)length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ReadOnlySequence<T> Slice(SequencePosition start, SequencePosition end)
|
||||
{
|
||||
BoundsCheck((uint)GetIndex(in start), start.GetObject(), (uint)GetIndex(in end), end.GetObject());
|
||||
return SliceImpl(in start, in end);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ReadOnlySequence<T> Slice(SequencePosition start)
|
||||
{
|
||||
BoundsCheck(in start);
|
||||
return SliceImpl(in start, in _sequenceEnd);
|
||||
}
|
||||
|
||||
public ReadOnlySequence<T> Slice(long start)
|
||||
{
|
||||
if (start < 0)
|
||||
{
|
||||
System.ThrowHelper.ThrowStartOrEndArgumentValidationException(start);
|
||||
}
|
||||
if (start == 0L)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
return SliceImpl(Seek(in _sequenceStart, in _sequenceEnd, start, System.ExceptionArgument.start), in _sequenceEnd);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (typeof(T) == typeof(char))
|
||||
{
|
||||
ReadOnlySequence<T> source = this;
|
||||
ReadOnlySequence<char> sequence = Unsafe.As<ReadOnlySequence<T>, ReadOnlySequence<char>>(ref source);
|
||||
if (SequenceMarshal.TryGetString(sequence, out var text, out var start, out var length))
|
||||
{
|
||||
return text.Substring(start, length);
|
||||
}
|
||||
if (Length < int.MaxValue)
|
||||
{
|
||||
return new string(BuffersExtensions.ToArray(in sequence));
|
||||
}
|
||||
}
|
||||
return $"System.Buffers.ReadOnlySequence<{typeof(T).Name}>[{Length}]";
|
||||
}
|
||||
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
return new Enumerator(this);
|
||||
}
|
||||
|
||||
public SequencePosition GetPosition(long offset)
|
||||
{
|
||||
return GetPosition(offset, _sequenceStart);
|
||||
}
|
||||
|
||||
public SequencePosition GetPosition(long offset, SequencePosition origin)
|
||||
{
|
||||
if (offset < 0)
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException_OffsetOutOfRange();
|
||||
}
|
||||
return Seek(in origin, in _sequenceEnd, offset, System.ExceptionArgument.offset);
|
||||
}
|
||||
|
||||
public bool TryGet(ref SequencePosition position, out ReadOnlyMemory<T> memory, bool advance = true)
|
||||
{
|
||||
SequencePosition next;
|
||||
bool result = TryGetBuffer(in position, out memory, out next);
|
||||
if (advance)
|
||||
{
|
||||
position = next;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal bool TryGetBuffer(in SequencePosition position, out ReadOnlyMemory<T> memory, out SequencePosition next)
|
||||
{
|
||||
object obj = position.GetObject();
|
||||
next = default(SequencePosition);
|
||||
if (obj == null)
|
||||
{
|
||||
memory = default(ReadOnlyMemory<T>);
|
||||
return false;
|
||||
}
|
||||
SequenceType sequenceType = GetSequenceType();
|
||||
object obj2 = _sequenceEnd.GetObject();
|
||||
int index = GetIndex(in position);
|
||||
int index2 = GetIndex(in _sequenceEnd);
|
||||
if (sequenceType == SequenceType.MultiSegment)
|
||||
{
|
||||
ReadOnlySequenceSegment<T> readOnlySequenceSegment = (ReadOnlySequenceSegment<T>)obj;
|
||||
if (readOnlySequenceSegment != obj2)
|
||||
{
|
||||
ReadOnlySequenceSegment<T> next2 = readOnlySequenceSegment.Next;
|
||||
if (next2 == null)
|
||||
{
|
||||
System.ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
|
||||
}
|
||||
next = new SequencePosition(next2, 0);
|
||||
memory = readOnlySequenceSegment.Memory.Slice(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
memory = readOnlySequenceSegment.Memory.Slice(index, index2 - index);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (obj != obj2)
|
||||
{
|
||||
System.ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
|
||||
}
|
||||
if (sequenceType == SequenceType.Array)
|
||||
{
|
||||
memory = new ReadOnlyMemory<T>((T[])obj, index, index2 - index);
|
||||
}
|
||||
else if (typeof(T) == typeof(char) && sequenceType == SequenceType.String)
|
||||
{
|
||||
memory = (ReadOnlyMemory<T>)(object)MemoryExtensions.AsMemory((string)obj, index, index2 - index);
|
||||
}
|
||||
else
|
||||
{
|
||||
memory = ((MemoryManager<T>)obj).Memory.Slice(index, index2 - index);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private ReadOnlyMemory<T> GetFirstBuffer()
|
||||
{
|
||||
object obj = _sequenceStart.GetObject();
|
||||
if (obj == null)
|
||||
{
|
||||
return default(ReadOnlyMemory<T>);
|
||||
}
|
||||
int integer = _sequenceStart.GetInteger();
|
||||
int integer2 = _sequenceEnd.GetInteger();
|
||||
bool flag = obj != _sequenceEnd.GetObject();
|
||||
if (integer >= 0)
|
||||
{
|
||||
if (integer2 >= 0)
|
||||
{
|
||||
ReadOnlyMemory<T> memory = ((ReadOnlySequenceSegment<T>)obj).Memory;
|
||||
if (flag)
|
||||
{
|
||||
return memory.Slice(integer);
|
||||
}
|
||||
return memory.Slice(integer, integer2 - integer);
|
||||
}
|
||||
if (flag)
|
||||
{
|
||||
System.ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
|
||||
}
|
||||
return new ReadOnlyMemory<T>((T[])obj, integer, (integer2 & 0x7FFFFFFF) - integer);
|
||||
}
|
||||
if (flag)
|
||||
{
|
||||
System.ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
|
||||
}
|
||||
if (typeof(T) == typeof(char) && integer2 < 0)
|
||||
{
|
||||
return (ReadOnlyMemory<T>)(object)MemoryExtensions.AsMemory((string)obj, integer & 0x7FFFFFFF, integer2 - integer);
|
||||
}
|
||||
integer &= 0x7FFFFFFF;
|
||||
return ((MemoryManager<T>)obj).Memory.Slice(integer, integer2 - integer);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private SequencePosition Seek(in SequencePosition start, in SequencePosition end, long offset, System.ExceptionArgument argument)
|
||||
{
|
||||
int index = GetIndex(in start);
|
||||
int index2 = GetIndex(in end);
|
||||
object obj = start.GetObject();
|
||||
object obj2 = end.GetObject();
|
||||
if (obj != obj2)
|
||||
{
|
||||
ReadOnlySequenceSegment<T> readOnlySequenceSegment = (ReadOnlySequenceSegment<T>)obj;
|
||||
int num = readOnlySequenceSegment.Memory.Length - index;
|
||||
if (num <= offset)
|
||||
{
|
||||
if (num < 0)
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
|
||||
}
|
||||
return SeekMultiSegment(readOnlySequenceSegment.Next, obj2, index2, offset - num, argument);
|
||||
}
|
||||
}
|
||||
else if (index2 - index < offset)
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException(argument);
|
||||
}
|
||||
return new SequencePosition(obj, index + (int)offset);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private static SequencePosition SeekMultiSegment(ReadOnlySequenceSegment<T> currentSegment, object endObject, int endIndex, long offset, System.ExceptionArgument argument)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (currentSegment != null && currentSegment != endObject)
|
||||
{
|
||||
int length = currentSegment.Memory.Length;
|
||||
if (length > offset)
|
||||
{
|
||||
break;
|
||||
}
|
||||
offset -= length;
|
||||
currentSegment = currentSegment.Next;
|
||||
continue;
|
||||
}
|
||||
if (currentSegment == null || endIndex < offset)
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException(argument);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return new SequencePosition(currentSegment, (int)offset);
|
||||
}
|
||||
|
||||
private void BoundsCheck(in SequencePosition position)
|
||||
{
|
||||
uint index = (uint)GetIndex(in position);
|
||||
uint index2 = (uint)GetIndex(in _sequenceStart);
|
||||
uint index3 = (uint)GetIndex(in _sequenceEnd);
|
||||
object obj = _sequenceStart.GetObject();
|
||||
object obj2 = _sequenceEnd.GetObject();
|
||||
if (obj == obj2)
|
||||
{
|
||||
if (!InRange(index, index2, index3))
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
|
||||
}
|
||||
return;
|
||||
}
|
||||
ulong start = (ulong)(((ReadOnlySequenceSegment<T>)obj).RunningIndex + index2);
|
||||
if (!InRange((ulong)(((ReadOnlySequenceSegment<T>)position.GetObject()).RunningIndex + index), start, (ulong)(((ReadOnlySequenceSegment<T>)obj2).RunningIndex + index3)))
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
|
||||
}
|
||||
}
|
||||
|
||||
private void BoundsCheck(uint sliceStartIndex, object sliceStartObject, uint sliceEndIndex, object sliceEndObject)
|
||||
{
|
||||
uint index = (uint)GetIndex(in _sequenceStart);
|
||||
uint index2 = (uint)GetIndex(in _sequenceEnd);
|
||||
object obj = _sequenceStart.GetObject();
|
||||
object obj2 = _sequenceEnd.GetObject();
|
||||
if (obj == obj2)
|
||||
{
|
||||
if (sliceStartObject != sliceEndObject || sliceStartObject != obj || sliceStartIndex > sliceEndIndex || sliceStartIndex < index || sliceEndIndex > index2)
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
|
||||
}
|
||||
return;
|
||||
}
|
||||
ulong num = (ulong)(((ReadOnlySequenceSegment<T>)sliceStartObject).RunningIndex + sliceStartIndex);
|
||||
ulong num2 = (ulong)(((ReadOnlySequenceSegment<T>)sliceEndObject).RunningIndex + sliceEndIndex);
|
||||
if (num > num2)
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
|
||||
}
|
||||
if (num < (ulong)(((ReadOnlySequenceSegment<T>)obj).RunningIndex + index) || num2 > (ulong)(((ReadOnlySequenceSegment<T>)obj2).RunningIndex + index2))
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
|
||||
}
|
||||
}
|
||||
|
||||
private static SequencePosition GetEndPosition(ReadOnlySequenceSegment<T> startSegment, object startObject, int startIndex, object endObject, int endIndex, long length)
|
||||
{
|
||||
int num = startSegment.Memory.Length - startIndex;
|
||||
if (num > length)
|
||||
{
|
||||
return new SequencePosition(startObject, startIndex + (int)length);
|
||||
}
|
||||
if (num < 0)
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
|
||||
}
|
||||
return SeekMultiSegment(startSegment.Next, endObject, endIndex, length - num, System.ExceptionArgument.length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private SequenceType GetSequenceType()
|
||||
{
|
||||
return (SequenceType)(-(2 * (_sequenceStart.GetInteger() >> 31) + (_sequenceEnd.GetInteger() >> 31)));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int GetIndex(in SequencePosition position)
|
||||
{
|
||||
return position.GetInteger() & 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private ReadOnlySequence<T> SliceImpl(in SequencePosition start, in SequencePosition end)
|
||||
{
|
||||
return new ReadOnlySequence<T>(start.GetObject(), GetIndex(in start) | (_sequenceStart.GetInteger() & int.MinValue), end.GetObject(), GetIndex(in end) | (_sequenceEnd.GetInteger() & int.MinValue));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private long GetLength()
|
||||
{
|
||||
int index = GetIndex(in _sequenceStart);
|
||||
int index2 = GetIndex(in _sequenceEnd);
|
||||
object obj = _sequenceStart.GetObject();
|
||||
object obj2 = _sequenceEnd.GetObject();
|
||||
if (obj != obj2)
|
||||
{
|
||||
ReadOnlySequenceSegment<T> readOnlySequenceSegment = (ReadOnlySequenceSegment<T>)obj;
|
||||
ReadOnlySequenceSegment<T> readOnlySequenceSegment2 = (ReadOnlySequenceSegment<T>)obj2;
|
||||
return readOnlySequenceSegment2.RunningIndex + index2 - (readOnlySequenceSegment.RunningIndex + index);
|
||||
}
|
||||
return index2 - index;
|
||||
}
|
||||
|
||||
internal bool TryGetReadOnlySequenceSegment(out ReadOnlySequenceSegment<T> startSegment, out int startIndex, out ReadOnlySequenceSegment<T> endSegment, out int endIndex)
|
||||
{
|
||||
object obj = _sequenceStart.GetObject();
|
||||
if (obj == null || GetSequenceType() != SequenceType.MultiSegment)
|
||||
{
|
||||
startSegment = null;
|
||||
startIndex = 0;
|
||||
endSegment = null;
|
||||
endIndex = 0;
|
||||
return false;
|
||||
}
|
||||
startSegment = (ReadOnlySequenceSegment<T>)obj;
|
||||
startIndex = GetIndex(in _sequenceStart);
|
||||
endSegment = (ReadOnlySequenceSegment<T>)_sequenceEnd.GetObject();
|
||||
endIndex = GetIndex(in _sequenceEnd);
|
||||
return true;
|
||||
}
|
||||
|
||||
internal bool TryGetArray(out ArraySegment<T> segment)
|
||||
{
|
||||
if (GetSequenceType() != SequenceType.Array)
|
||||
{
|
||||
segment = default(ArraySegment<T>);
|
||||
return false;
|
||||
}
|
||||
int index = GetIndex(in _sequenceStart);
|
||||
segment = new ArraySegment<T>((T[])_sequenceStart.GetObject(), index, GetIndex(in _sequenceEnd) - index);
|
||||
return true;
|
||||
}
|
||||
|
||||
internal bool TryGetString(out string text, out int start, out int length)
|
||||
{
|
||||
if (typeof(T) != typeof(char) || GetSequenceType() != SequenceType.String)
|
||||
{
|
||||
start = 0;
|
||||
length = 0;
|
||||
text = null;
|
||||
return false;
|
||||
}
|
||||
start = GetIndex(in _sequenceStart);
|
||||
length = GetIndex(in _sequenceEnd) - start;
|
||||
text = (string)_sequenceStart.GetObject();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool InRange(uint value, uint start, uint end)
|
||||
{
|
||||
return value - start <= end - start;
|
||||
}
|
||||
|
||||
private static bool InRange(ulong value, ulong start, ulong end)
|
||||
{
|
||||
return value - start <= end - start;
|
||||
}
|
||||
|
||||
static ReadOnlySequence()
|
||||
{
|
||||
Empty = new ReadOnlySequence<T>(System.SpanHelpers.PerTypeValues<T>.EmptyArray);
|
||||
}
|
||||
}
|
||||
internal static class ReadOnlySequence
|
||||
{
|
||||
public const int FlagBitMask = int.MinValue;
|
||||
|
||||
public const int IndexBitMask = int.MaxValue;
|
||||
|
||||
public const int SegmentStartMask = 0;
|
||||
|
||||
public const int SegmentEndMask = 0;
|
||||
|
||||
public const int ArrayStartMask = 0;
|
||||
|
||||
public const int ArrayEndMask = int.MinValue;
|
||||
|
||||
public const int MemoryManagerStartMask = int.MinValue;
|
||||
|
||||
public const int MemoryManagerEndMask = 0;
|
||||
|
||||
public const int StringStartMask = int.MinValue;
|
||||
|
||||
public const int StringEndMask = int.MinValue;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int SegmentToSequenceStart(int startIndex)
|
||||
{
|
||||
return startIndex | 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int SegmentToSequenceEnd(int endIndex)
|
||||
{
|
||||
return endIndex | 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int ArrayToSequenceStart(int startIndex)
|
||||
{
|
||||
return startIndex | 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int ArrayToSequenceEnd(int endIndex)
|
||||
{
|
||||
return endIndex | int.MinValue;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int MemoryManagerToSequenceStart(int startIndex)
|
||||
{
|
||||
return startIndex | int.MinValue;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int MemoryManagerToSequenceEnd(int endIndex)
|
||||
{
|
||||
return endIndex | 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int StringToSequenceStart(int startIndex)
|
||||
{
|
||||
return startIndex | int.MinValue;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int StringToSequenceEnd(int endIndex)
|
||||
{
|
||||
return endIndex | int.MinValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.Buffers;
|
||||
|
||||
internal sealed class ReadOnlySequenceDebugView<T>
|
||||
{
|
||||
[DebuggerDisplay("Count: {Segments.Length}", Name = "Segments")]
|
||||
public struct ReadOnlySequenceDebugViewSegments
|
||||
{
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
|
||||
public ReadOnlyMemory<T>[] Segments { get; set; }
|
||||
}
|
||||
|
||||
private readonly T[] _array;
|
||||
|
||||
private readonly ReadOnlySequenceDebugViewSegments _segments;
|
||||
|
||||
public ReadOnlySequenceDebugViewSegments BufferSegments => _segments;
|
||||
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
|
||||
public T[] Items => _array;
|
||||
|
||||
public ReadOnlySequenceDebugView(ReadOnlySequence<T> sequence)
|
||||
{
|
||||
_array = BuffersExtensions.ToArray(in sequence);
|
||||
int num = 0;
|
||||
ReadOnlySequence<T>.Enumerator enumerator = sequence.GetEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
ReadOnlyMemory<T> current = enumerator.Current;
|
||||
num++;
|
||||
}
|
||||
ReadOnlyMemory<T>[] array = new ReadOnlyMemory<T>[num];
|
||||
int num2 = 0;
|
||||
ReadOnlySequence<T>.Enumerator enumerator2 = sequence.GetEnumerator();
|
||||
while (enumerator2.MoveNext())
|
||||
{
|
||||
ReadOnlyMemory<T> current2 = enumerator2.Current;
|
||||
array[num2] = current2;
|
||||
num2++;
|
||||
}
|
||||
_segments = new ReadOnlySequenceDebugViewSegments
|
||||
{
|
||||
Segments = array
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace System.Buffers;
|
||||
|
||||
public abstract class ReadOnlySequenceSegment<T>
|
||||
{
|
||||
public ReadOnlyMemory<T> Memory { get; protected set; }
|
||||
|
||||
public ReadOnlySequenceSegment<T> Next { get; protected set; }
|
||||
|
||||
public long RunningIndex { get; protected set; }
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
namespace System.Buffers;
|
||||
|
||||
public readonly struct StandardFormat : IEquatable<StandardFormat>
|
||||
{
|
||||
public const byte NoPrecision = byte.MaxValue;
|
||||
|
||||
public const byte MaxPrecision = 99;
|
||||
|
||||
private readonly byte _format;
|
||||
|
||||
private readonly byte _precision;
|
||||
|
||||
public char Symbol => (char)_format;
|
||||
|
||||
public byte Precision => _precision;
|
||||
|
||||
public bool HasPrecision => _precision != byte.MaxValue;
|
||||
|
||||
public bool IsDefault
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_format == 0)
|
||||
{
|
||||
return _precision == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public StandardFormat(char symbol, byte precision = byte.MaxValue)
|
||||
{
|
||||
if (precision != byte.MaxValue && precision > 99)
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException_PrecisionTooLarge();
|
||||
}
|
||||
if (symbol != (byte)symbol)
|
||||
{
|
||||
System.ThrowHelper.ThrowArgumentOutOfRangeException_SymbolDoesNotFit();
|
||||
}
|
||||
_format = (byte)symbol;
|
||||
_precision = precision;
|
||||
}
|
||||
|
||||
public static implicit operator StandardFormat(char symbol)
|
||||
{
|
||||
return new StandardFormat(symbol);
|
||||
}
|
||||
|
||||
public static StandardFormat Parse(ReadOnlySpan<char> format)
|
||||
{
|
||||
if (format.Length == 0)
|
||||
{
|
||||
return default(StandardFormat);
|
||||
}
|
||||
char symbol = format[0];
|
||||
byte precision;
|
||||
if (format.Length == 1)
|
||||
{
|
||||
precision = byte.MaxValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint num = 0u;
|
||||
for (int i = 1; i < format.Length; i++)
|
||||
{
|
||||
uint num2 = (uint)(format[i] - 48);
|
||||
if (num2 > 9)
|
||||
{
|
||||
throw new FormatException(System.SR.Format(System.SR.Argument_CannotParsePrecision, (byte)99));
|
||||
}
|
||||
num = num * 10 + num2;
|
||||
if (num > 99)
|
||||
{
|
||||
throw new FormatException(System.SR.Format(System.SR.Argument_PrecisionTooLarge, (byte)99));
|
||||
}
|
||||
}
|
||||
precision = (byte)num;
|
||||
}
|
||||
return new StandardFormat(symbol, precision);
|
||||
}
|
||||
|
||||
public static StandardFormat Parse(string format)
|
||||
{
|
||||
if (format != null)
|
||||
{
|
||||
return Parse(MemoryExtensions.AsSpan(format));
|
||||
}
|
||||
return default(StandardFormat);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is StandardFormat other)
|
||||
{
|
||||
return Equals(other);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
byte format = _format;
|
||||
int hashCode = format.GetHashCode();
|
||||
format = _precision;
|
||||
return hashCode ^ format.GetHashCode();
|
||||
}
|
||||
|
||||
public bool Equals(StandardFormat other)
|
||||
{
|
||||
if (_format == other._format)
|
||||
{
|
||||
return _precision == other._precision;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public unsafe override string ToString()
|
||||
{
|
||||
char* ptr = stackalloc char[4];
|
||||
int length = 0;
|
||||
char symbol = Symbol;
|
||||
if (symbol != 0)
|
||||
{
|
||||
ptr[length++] = symbol;
|
||||
byte b = Precision;
|
||||
if (b != byte.MaxValue)
|
||||
{
|
||||
if (b >= 100)
|
||||
{
|
||||
ptr[length++] = (char)(48 + b / 100 % 10);
|
||||
b %= 100;
|
||||
}
|
||||
if (b >= 10)
|
||||
{
|
||||
ptr[length++] = (char)(48 + b / 10 % 10);
|
||||
b %= 10;
|
||||
}
|
||||
ptr[length++] = (char)(48 + b);
|
||||
}
|
||||
}
|
||||
return new string(ptr, 0, length);
|
||||
}
|
||||
|
||||
public static bool operator ==(StandardFormat left, StandardFormat right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(StandardFormat left, StandardFormat right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user