优化工程目录结构
This commit is contained in:
parent
09e78ce4dd
commit
8849ccf5ce
@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: f74afe8474234514a52ccfc40a8c069c
|
|
||||||
timeCreated: 1708529284
|
|
||||||
@ -1,496 +0,0 @@
|
|||||||
// Copyright (c) All contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
/* Licensed to the .NET Foundation under one or more agreements.
|
|
||||||
* The .NET Foundation licenses this file to you under the MIT license.
|
|
||||||
* See the LICENSE file in the project root for more information. */
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Buffers;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace AlicizaX
|
|
||||||
{
|
|
||||||
public ref partial struct SequenceReader<T> where T : unmanaged, IEquatable<T>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A value indicating whether we're using <see cref="sequence"/> (as opposed to <see cref="memory"/>.
|
|
||||||
/// </summary>
|
|
||||||
private bool usingSequence;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Backing for the entire sequence when we're not using <see cref="memory"/>.
|
|
||||||
/// </summary>
|
|
||||||
private ReadOnlySequence<T> sequence;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The position at the start of the <see cref="CurrentSpan"/>.
|
|
||||||
/// </summary>
|
|
||||||
private SequencePosition currentPosition;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The position at the end of the <see cref="CurrentSpan"/>.
|
|
||||||
/// </summary>
|
|
||||||
private SequencePosition nextPosition;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Backing for the entire sequence when we're not using <see cref="sequence"/>.
|
|
||||||
/// </summary>
|
|
||||||
private ReadOnlyMemory<T> memory;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A value indicating whether there is unread data remaining.
|
|
||||||
/// </summary>
|
|
||||||
private bool moreData;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The total number of elements in the sequence.
|
|
||||||
/// </summary>
|
|
||||||
private long length;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="SequenceReader{T}"/> struct
|
|
||||||
/// over the given <see cref="ReadOnlySequence{T}"/>.
|
|
||||||
/// </summary>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public SequenceReader(in ReadOnlySequence<T> sequence)
|
|
||||||
{
|
|
||||||
this.usingSequence = true;
|
|
||||||
this.CurrentSpanIndex = 0;
|
|
||||||
this.Consumed = 0;
|
|
||||||
this.sequence = sequence;
|
|
||||||
this.memory = default;
|
|
||||||
this.currentPosition = sequence.Start;
|
|
||||||
this.length = -1;
|
|
||||||
|
|
||||||
ReadOnlySpan<T> first = sequence.First.Span;
|
|
||||||
this.nextPosition = sequence.GetPosition(first.Length);
|
|
||||||
this.CurrentSpan = first;
|
|
||||||
this.moreData = first.Length > 0;
|
|
||||||
|
|
||||||
if (!this.moreData && !sequence.IsSingleSegment)
|
|
||||||
{
|
|
||||||
this.moreData = true;
|
|
||||||
this.GetNextSpan();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="SequenceReader{T}"/> struct
|
|
||||||
/// over the given <see cref="ReadOnlyMemory{T}"/>.
|
|
||||||
/// </summary>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public SequenceReader(ReadOnlyMemory<T> memory)
|
|
||||||
{
|
|
||||||
this.usingSequence = false;
|
|
||||||
this.CurrentSpanIndex = 0;
|
|
||||||
this.Consumed = 0;
|
|
||||||
this.memory = memory;
|
|
||||||
this.CurrentSpan = memory.Span;
|
|
||||||
this.length = memory.Length;
|
|
||||||
this.moreData = memory.Length > 0;
|
|
||||||
|
|
||||||
this.currentPosition = default;
|
|
||||||
this.nextPosition = default;
|
|
||||||
this.sequence = default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether there is no more data in the <see cref="Sequence"/>.
|
|
||||||
/// </summary>
|
|
||||||
public bool End => !this.moreData;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the underlying <see cref="ReadOnlySequence{T}"/> for the reader.
|
|
||||||
/// </summary>
|
|
||||||
public ReadOnlySequence<T> Sequence
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (this.sequence.IsEmpty && !this.memory.IsEmpty)
|
|
||||||
{
|
|
||||||
// We're in memory mode (instead of sequence mode).
|
|
||||||
// Lazily fill in the sequence data.
|
|
||||||
this.sequence = new ReadOnlySequence<T>(this.memory);
|
|
||||||
this.currentPosition = this.sequence.Start;
|
|
||||||
this.nextPosition = this.sequence.End;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.sequence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the current position in the <see cref="Sequence"/>.
|
|
||||||
/// </summary>
|
|
||||||
public SequencePosition Position
|
|
||||||
=> this.Sequence.GetPosition(this.CurrentSpanIndex, this.currentPosition);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the current segment in the <see cref="Sequence"/> as a span.
|
|
||||||
/// </summary>
|
|
||||||
public ReadOnlySpan<T> CurrentSpan { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the index in the <see cref="CurrentSpan"/>.
|
|
||||||
/// </summary>
|
|
||||||
public int CurrentSpanIndex { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the unread portion of the <see cref="CurrentSpan"/>.
|
|
||||||
/// </summary>
|
|
||||||
public ReadOnlySpan<T> UnreadSpan
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => this.CurrentSpan.Slice(this.CurrentSpanIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the total number of <typeparamref name="T"/>'s processed by the reader.
|
|
||||||
/// </summary>
|
|
||||||
public long Consumed { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets remaining <typeparamref name="T"/>'s in the reader's <see cref="Sequence"/>.
|
|
||||||
/// </summary>
|
|
||||||
public long Remaining => this.Length - this.Consumed;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets count of <typeparamref name="T"/> in the reader's <see cref="Sequence"/>.
|
|
||||||
/// </summary>
|
|
||||||
public long Length
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (this.length < 0)
|
|
||||||
{
|
|
||||||
// Cache the length
|
|
||||||
this.length = this.Sequence.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Peeks at the next value without advancing the reader.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The next value or default if at the end.</param>
|
|
||||||
/// <returns>False if at the end of the reader.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool TryPeek(out T value)
|
|
||||||
{
|
|
||||||
if (this.moreData)
|
|
||||||
{
|
|
||||||
value = this.CurrentSpan[this.CurrentSpanIndex];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Read the next value and advance the reader.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The next value or default if at the end.</param>
|
|
||||||
/// <returns>False if at the end of the reader.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool TryRead(out T value)
|
|
||||||
{
|
|
||||||
if (this.End)
|
|
||||||
{
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = this.CurrentSpan[this.CurrentSpanIndex];
|
|
||||||
this.CurrentSpanIndex++;
|
|
||||||
this.Consumed++;
|
|
||||||
|
|
||||||
if (this.CurrentSpanIndex >= this.CurrentSpan.Length)
|
|
||||||
{
|
|
||||||
if (this.usingSequence)
|
|
||||||
{
|
|
||||||
this.GetNextSpan();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.moreData = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Move the reader back the specified number of items.
|
|
||||||
/// </summary>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Rewind(long count)
|
|
||||||
{
|
|
||||||
if (count < 0)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(count));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Consumed -= count;
|
|
||||||
|
|
||||||
if (this.CurrentSpanIndex >= count)
|
|
||||||
{
|
|
||||||
this.CurrentSpanIndex -= (int)count;
|
|
||||||
this.moreData = true;
|
|
||||||
}
|
|
||||||
else if (this.usingSequence)
|
|
||||||
{
|
|
||||||
// Current segment doesn't have enough data, scan backward through segments
|
|
||||||
this.RetreatToPreviousSpan(this.Consumed);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException("Rewind went past the start of the memory.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
||||||
private void RetreatToPreviousSpan(long consumed)
|
|
||||||
{
|
|
||||||
Debug.Assert(this.usingSequence, "usingSequence");
|
|
||||||
this.ResetReader();
|
|
||||||
this.Advance(consumed);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ResetReader()
|
|
||||||
{
|
|
||||||
Debug.Assert(this.usingSequence, "usingSequence");
|
|
||||||
this.CurrentSpanIndex = 0;
|
|
||||||
this.Consumed = 0;
|
|
||||||
this.currentPosition = this.Sequence.Start;
|
|
||||||
this.nextPosition = this.currentPosition;
|
|
||||||
|
|
||||||
if (this.Sequence.TryGet(ref this.nextPosition, out ReadOnlyMemory<T> memory, advance: true))
|
|
||||||
{
|
|
||||||
this.moreData = true;
|
|
||||||
|
|
||||||
if (memory.Length == 0)
|
|
||||||
{
|
|
||||||
this.CurrentSpan = default;
|
|
||||||
|
|
||||||
// No data in the first span, move to one with data
|
|
||||||
this.GetNextSpan();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.CurrentSpan = memory.Span;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// No data in any spans and at end of sequence
|
|
||||||
this.moreData = false;
|
|
||||||
this.CurrentSpan = default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the next segment with available data, if any.
|
|
||||||
/// </summary>
|
|
||||||
private void GetNextSpan()
|
|
||||||
{
|
|
||||||
Debug.Assert(this.usingSequence, "usingSequence");
|
|
||||||
if (!this.Sequence.IsSingleSegment)
|
|
||||||
{
|
|
||||||
SequencePosition previousNextPosition = this.nextPosition;
|
|
||||||
while (this.Sequence.TryGet(ref this.nextPosition, out ReadOnlyMemory<T> memory, advance: true))
|
|
||||||
{
|
|
||||||
this.currentPosition = previousNextPosition;
|
|
||||||
if (memory.Length > 0)
|
|
||||||
{
|
|
||||||
this.CurrentSpan = memory.Span;
|
|
||||||
this.CurrentSpanIndex = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.CurrentSpan = default;
|
|
||||||
this.CurrentSpanIndex = 0;
|
|
||||||
previousNextPosition = this.nextPosition;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.moreData = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Move the reader ahead the specified number of items.
|
|
||||||
/// </summary>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Advance(long count)
|
|
||||||
{
|
|
||||||
const long TooBigOrNegative = unchecked((long)0xFFFFFFFF80000000);
|
|
||||||
if ((count & TooBigOrNegative) == 0 && this.CurrentSpan.Length - this.CurrentSpanIndex > (int)count)
|
|
||||||
{
|
|
||||||
this.CurrentSpanIndex += (int)count;
|
|
||||||
this.Consumed += count;
|
|
||||||
}
|
|
||||||
else if (this.usingSequence)
|
|
||||||
{
|
|
||||||
// Can't satisfy from the current span
|
|
||||||
this.AdvanceToNextSpan(count);
|
|
||||||
}
|
|
||||||
else if (this.CurrentSpan.Length - this.CurrentSpanIndex == (int)count)
|
|
||||||
{
|
|
||||||
this.CurrentSpanIndex += (int)count;
|
|
||||||
this.Consumed += count;
|
|
||||||
this.moreData = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(count));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Unchecked helper to avoid unnecessary checks where you know count is valid.
|
|
||||||
/// </summary>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal void AdvanceCurrentSpan(long count)
|
|
||||||
{
|
|
||||||
Debug.Assert(count >= 0, "count >= 0");
|
|
||||||
|
|
||||||
this.Consumed += count;
|
|
||||||
this.CurrentSpanIndex += (int)count;
|
|
||||||
if (this.usingSequence && this.CurrentSpanIndex >= this.CurrentSpan.Length)
|
|
||||||
{
|
|
||||||
this.GetNextSpan();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Only call this helper if you know that you are advancing in the current span
|
|
||||||
/// with valid count and there is no need to fetch the next one.
|
|
||||||
/// </summary>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal void AdvanceWithinSpan(long count)
|
|
||||||
{
|
|
||||||
Debug.Assert(count >= 0, "count >= 0");
|
|
||||||
|
|
||||||
this.Consumed += count;
|
|
||||||
this.CurrentSpanIndex += (int)count;
|
|
||||||
|
|
||||||
Debug.Assert(this.CurrentSpanIndex < this.CurrentSpan.Length, "this.CurrentSpanIndex < this.CurrentSpan.Length");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Move the reader ahead the specified number of items
|
|
||||||
/// if there are enough elements remaining in the sequence.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns><see langword="true"/> if there were enough elements to advance; otherwise <see langword="false"/>.</returns>
|
|
||||||
internal bool TryAdvance(long count)
|
|
||||||
{
|
|
||||||
if (this.Remaining < count)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Advance(count);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AdvanceToNextSpan(long count)
|
|
||||||
{
|
|
||||||
Debug.Assert(this.usingSequence, "usingSequence");
|
|
||||||
if (count < 0)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(count));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Consumed += count;
|
|
||||||
while (this.moreData)
|
|
||||||
{
|
|
||||||
int remaining = this.CurrentSpan.Length - this.CurrentSpanIndex;
|
|
||||||
|
|
||||||
if (remaining > count)
|
|
||||||
{
|
|
||||||
this.CurrentSpanIndex += (int)count;
|
|
||||||
count = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// As there may not be any further segments we need to
|
|
||||||
// push the current index to the end of the span.
|
|
||||||
this.CurrentSpanIndex += remaining;
|
|
||||||
count -= remaining;
|
|
||||||
Debug.Assert(count >= 0, "count >= 0");
|
|
||||||
|
|
||||||
this.GetNextSpan();
|
|
||||||
|
|
||||||
if (count == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count != 0)
|
|
||||||
{
|
|
||||||
// Not enough data left- adjust for where we actually ended and throw
|
|
||||||
this.Consumed -= count;
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(count));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Copies data from the current <see cref="Position"/> to the given <paramref name="destination"/> span.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="destination">Destination to copy to.</param>
|
|
||||||
/// <returns>True if there is enough data to copy to the <paramref name="destination"/>.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool TryCopyTo(Span<T> destination)
|
|
||||||
{
|
|
||||||
ReadOnlySpan<T> firstSpan = this.UnreadSpan;
|
|
||||||
if (firstSpan.Length >= destination.Length)
|
|
||||||
{
|
|
||||||
firstSpan.Slice(0, destination.Length).CopyTo(destination);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.TryCopyMultisegment(destination);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal bool TryCopyMultisegment(Span<T> destination)
|
|
||||||
{
|
|
||||||
if (this.Remaining < destination.Length)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReadOnlySpan<T> firstSpan = this.UnreadSpan;
|
|
||||||
Debug.Assert(firstSpan.Length < destination.Length, "firstSpan.Length < destination.Length");
|
|
||||||
firstSpan.CopyTo(destination);
|
|
||||||
int copied = firstSpan.Length;
|
|
||||||
|
|
||||||
SequencePosition next = this.nextPosition;
|
|
||||||
while (this.Sequence.TryGet(ref next, out ReadOnlyMemory<T> nextSegment, true))
|
|
||||||
{
|
|
||||||
if (nextSegment.Length > 0)
|
|
||||||
{
|
|
||||||
ReadOnlySpan<T> nextSpan = nextSegment.Span;
|
|
||||||
int toCopy = Math.Min(nextSpan.Length, destination.Length - copied);
|
|
||||||
nextSpan.Slice(0, toCopy).CopyTo(destination.Slice(copied));
|
|
||||||
copied += toCopy;
|
|
||||||
if (copied >= destination.Length)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 25906ef608f044e4948c7171c50a8e50
|
|
||||||
timeCreated: 1708529317
|
|
||||||
@ -1,238 +0,0 @@
|
|||||||
// Copyright (c) All contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
/* Licensed to the .NET Foundation under one or more agreements.
|
|
||||||
* The .NET Foundation licenses this file to you under the MIT license.
|
|
||||||
* See the LICENSE file in the project root for more information. */
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Buffers.Binary;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace AlicizaX
|
|
||||||
{
|
|
||||||
public static partial class SequenceReaderExtensions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Try to read the given type out of the buffer if possible. Warning: this is dangerous to use with arbitrary
|
|
||||||
/// structs- see remarks for full details.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// IMPORTANT: The read is a straight copy of bits. If a struct depends on specific state of its members to
|
|
||||||
/// behave correctly this can lead to exceptions, etc. If reading endian specific integers, use the explicit
|
|
||||||
/// overloads such as <see cref="TryReadBigEndian(ref SequenceReader{byte}, out short)"/>.
|
|
||||||
/// </remarks>
|
|
||||||
/// <returns>
|
|
||||||
/// True if successful. <paramref name="value"/> will be default if failed (due to lack of space).
|
|
||||||
/// </returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal static unsafe bool TryRead<T>(ref this SequenceReader<byte> reader, out T value)
|
|
||||||
where T : unmanaged
|
|
||||||
{
|
|
||||||
ReadOnlySpan<byte> span = reader.UnreadSpan;
|
|
||||||
if (span.Length < sizeof(T))
|
|
||||||
{
|
|
||||||
return TryReadMultisegment(ref reader, out value);
|
|
||||||
}
|
|
||||||
|
|
||||||
value = Unsafe.ReadUnaligned<T>(ref MemoryMarshal.GetReference(span));
|
|
||||||
reader.Advance(sizeof(T));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static unsafe bool TryReadMultisegment<T>(ref SequenceReader<byte> reader, out T value)
|
|
||||||
where T : unmanaged
|
|
||||||
{
|
|
||||||
Debug.Assert(reader.UnreadSpan.Length < sizeof(T), "reader.UnreadSpan.Length < sizeof(T)");
|
|
||||||
|
|
||||||
// Not enough data in the current segment, try to peek for the data we need.
|
|
||||||
T buffer = default;
|
|
||||||
Span<byte> tempSpan = new Span<byte>(&buffer, sizeof(T));
|
|
||||||
|
|
||||||
if (!reader.TryCopyTo(tempSpan))
|
|
||||||
{
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = Unsafe.ReadUnaligned<T>(ref MemoryMarshal.GetReference(tempSpan));
|
|
||||||
reader.Advance(sizeof(T));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads an <see cref="sbyte"/> from the next position in the sequence.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="reader">The reader to read from.</param>
|
|
||||||
/// <param name="value">Receives the value read.</param>
|
|
||||||
/// <returns><see langword="true"/> if there was another byte in the sequence; <see langword="false"/> otherwise.</returns>
|
|
||||||
public static bool TryRead(ref this SequenceReader<byte> reader, out sbyte value)
|
|
||||||
{
|
|
||||||
if (TryRead(ref reader, out byte byteValue))
|
|
||||||
{
|
|
||||||
value = unchecked((sbyte)byteValue);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads an <see cref="Int16"/> as big endian.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>False if there wasn't enough data for an <see cref="Int16"/>.</returns>
|
|
||||||
public static bool TryReadBigEndian(ref this SequenceReader<byte> reader, out short value)
|
|
||||||
{
|
|
||||||
if (!BitConverter.IsLittleEndian)
|
|
||||||
{
|
|
||||||
return reader.TryRead(out value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TryReadReverseEndianness(ref reader, out value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads an <see cref="UInt16"/> as big endian.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>False if there wasn't enough data for an <see cref="UInt16"/>.</returns>
|
|
||||||
public static bool TryReadBigEndian(ref this SequenceReader<byte> reader, out ushort value)
|
|
||||||
{
|
|
||||||
if (TryReadBigEndian(ref reader, out short shortValue))
|
|
||||||
{
|
|
||||||
value = unchecked((ushort)shortValue);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryReadReverseEndianness(ref SequenceReader<byte> reader, out short value)
|
|
||||||
{
|
|
||||||
if (reader.TryRead(out value))
|
|
||||||
{
|
|
||||||
value = BinaryPrimitives.ReverseEndianness(value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads an <see cref="Int32"/> as big endian.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>False if there wasn't enough data for an <see cref="Int32"/>.</returns>
|
|
||||||
public static bool TryReadBigEndian(ref this SequenceReader<byte> reader, out int value)
|
|
||||||
{
|
|
||||||
if (!BitConverter.IsLittleEndian)
|
|
||||||
{
|
|
||||||
return reader.TryRead(out value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TryReadReverseEndianness(ref reader, out value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads an <see cref="UInt32"/> as big endian.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>False if there wasn't enough data for an <see cref="UInt32"/>.</returns>
|
|
||||||
public static bool TryReadBigEndian(ref this SequenceReader<byte> reader, out uint value)
|
|
||||||
{
|
|
||||||
if (TryReadBigEndian(ref reader, out int intValue))
|
|
||||||
{
|
|
||||||
value = unchecked((uint)intValue);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryReadReverseEndianness(ref SequenceReader<byte> reader, out int value)
|
|
||||||
{
|
|
||||||
if (reader.TryRead(out value))
|
|
||||||
{
|
|
||||||
value = BinaryPrimitives.ReverseEndianness(value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads an <see cref="Int64"/> as big endian.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>False if there wasn't enough data for an <see cref="Int64"/>.</returns>
|
|
||||||
public static bool TryReadBigEndian(ref this SequenceReader<byte> reader, out long value)
|
|
||||||
{
|
|
||||||
if (!BitConverter.IsLittleEndian)
|
|
||||||
{
|
|
||||||
return reader.TryRead(out value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TryReadReverseEndianness(ref reader, out value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads an <see cref="UInt64"/> as big endian.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>False if there wasn't enough data for an <see cref="UInt64"/>.</returns>
|
|
||||||
public static bool TryReadBigEndian(ref this SequenceReader<byte> reader, out ulong value)
|
|
||||||
{
|
|
||||||
if (TryReadBigEndian(ref reader, out long longValue))
|
|
||||||
{
|
|
||||||
value = unchecked((ulong)longValue);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryReadReverseEndianness(ref SequenceReader<byte> reader, out long value)
|
|
||||||
{
|
|
||||||
if (reader.TryRead(out value))
|
|
||||||
{
|
|
||||||
value = BinaryPrimitives.ReverseEndianness(value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads a <see cref="Single"/> as big endian.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>False if there wasn't enough data for a <see cref="Single"/>.</returns>
|
|
||||||
public static unsafe bool TryReadBigEndian(ref this SequenceReader<byte> reader, out float value)
|
|
||||||
{
|
|
||||||
if (TryReadBigEndian(ref reader, out int intValue))
|
|
||||||
{
|
|
||||||
value = *(float*)&intValue;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads a <see cref="Double"/> as big endian.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>False if there wasn't enough data for a <see cref="Double"/>.</returns>
|
|
||||||
public static unsafe bool TryReadBigEndian(ref this SequenceReader<byte> reader, out double value)
|
|
||||||
{
|
|
||||||
if (TryReadBigEndian(ref reader, out long longValue))
|
|
||||||
{
|
|
||||||
value = *(double*)&longValue;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 70685780749541938090d6e7433fd406
|
|
||||||
timeCreated: 1708529295
|
|
||||||
3
Runtime/ABase/Extension/Unity.meta
Normal file
3
Runtime/ABase/Extension/Unity.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: cb5e864a579747cbb83715ba15a22e66
|
||||||
|
timeCreated: 1776835707
|
||||||
@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: a4c9cbd4e6d1ba84fb42b601118e51a1
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: dbc2edb7919142ca9461e0335753a7df
|
|
||||||
timeCreated: 1694526362
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 62437af40e3e46868cd21e6e32601d44
|
|
||||||
timeCreated: 1694526450
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 4b84b3e6d60942c39f9fbc6e5b967d15
|
|
||||||
timeCreated: 1694526550
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 7e89a99f77d34c2ea459fd54fc6f202d
|
|
||||||
timeCreated: 1694526562
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user