- Initial commit
This commit is contained in:
130
Runtime/Shared/PlatformSupport/Memory/BufferSegment.cs
Normal file
130
Runtime/Shared/PlatformSupport/Memory/BufferSegment.cs
Normal file
@ -0,0 +1,130 @@
|
||||
using Best.HTTP.Shared.PlatformSupport.Text;
|
||||
|
||||
using System;
|
||||
|
||||
namespace Best.HTTP.Shared.PlatformSupport.Memory
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a segment (a continuous section) of a byte array, providing functionalities to
|
||||
/// work with a portion of the data without copying.
|
||||
/// </summary>
|
||||
[Best.HTTP.Shared.PlatformSupport.IL2CPP.Il2CppEagerStaticClassConstructionAttribute]
|
||||
public readonly struct BufferSegment
|
||||
{
|
||||
internal const int ToStringMaxDumpLength = 128;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an empty buffer segment.
|
||||
/// </summary>
|
||||
public static readonly BufferSegment Empty = new BufferSegment(null, 0, 0);
|
||||
|
||||
/// <summary>
|
||||
/// The underlying data of the buffer segment.
|
||||
/// </summary>
|
||||
public readonly byte[] Data;
|
||||
|
||||
/// <summary>
|
||||
/// The starting offset of the segment within the data.
|
||||
/// </summary>
|
||||
public readonly int Offset;
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes in the segment that contain valid data.
|
||||
/// </summary>
|
||||
public readonly int Count;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the BufferSegment struct.
|
||||
/// </summary>
|
||||
/// <param name="data">The data for the buffer segment.</param>
|
||||
/// <param name="offset">The starting offset of the segment.</param>
|
||||
/// <param name="count">The number of bytes in the segment.</param>
|
||||
public BufferSegment(byte[] data, int offset, int count)
|
||||
{
|
||||
this.Data = data;
|
||||
this.Offset = offset;
|
||||
this.Count = count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the buffer segment to an AutoReleaseBuffer to use it in a local using statement.
|
||||
/// </summary>
|
||||
/// <returns>A new AutoReleaseBuffer instance containing the data of the buffer segment.</returns>
|
||||
public AutoReleaseBuffer AsAutoRelease() => new AutoReleaseBuffer(this);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new segment starting from the specified offset.
|
||||
/// </summary>
|
||||
/// <remarks>The new segment will reference the same underlying byte[] as the original, without creating a copy of the data.</remarks>
|
||||
/// <param name="newOffset">The starting offset of the new segment.</param>
|
||||
/// <returns>A new buffer segment that references the same underlying data.</returns>
|
||||
public BufferSegment Slice(int newOffset) => new BufferSegment(this.Data, newOffset, this.Count - (newOffset - this.Offset));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new segment with the specified offset and count.
|
||||
/// </summary>
|
||||
/// <remarks>The new segment will reference the same underlying byte[] as the original, without creating a copy of the data.</remarks>
|
||||
/// <param name="offset">The starting offset of the new segment.</param>
|
||||
/// <param name="count">The number of bytes in the new segment.</param>
|
||||
/// <returns>A new buffer segment that references the same underlying data.</returns>
|
||||
public BufferSegment Slice(int offset, int count) => new BufferSegment(this.Data, offset, count);
|
||||
|
||||
/// <summary>
|
||||
/// Copyies the buffer's content to the received array.
|
||||
/// </summary>
|
||||
/// <param name="to">The array the data will be copied into.</param>
|
||||
public void CopyTo(byte[] to) => Array.Copy(this.Data, this.Offset, to, 0, this.Count);
|
||||
|
||||
public Span<byte> AsSpan() => new Span<byte>(this.Data, this.Offset, this.Count);
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || !(obj is BufferSegment))
|
||||
return false;
|
||||
|
||||
return Equals((BufferSegment)obj);
|
||||
}
|
||||
|
||||
public bool Equals(BufferSegment other) => this.Data == other.Data && this.Offset == other.Offset && this.Count == other.Count;
|
||||
public bool Equals(AutoReleaseBuffer other) => this.Data == other.Data && this.Offset == other.Offset && this.Count == other.Count;
|
||||
|
||||
public override int GetHashCode() => (this.Data != null ? this.Data.GetHashCode() : 0) * 21 + this.Offset + this.Count;
|
||||
|
||||
public static bool operator ==(BufferSegment left, BufferSegment right) => left.Equals(right);
|
||||
public static bool operator !=(BufferSegment left, BufferSegment right) => !left.Equals(right);
|
||||
public static bool operator ==(BufferSegment left, AutoReleaseBuffer right) => left.Equals(right);
|
||||
public static bool operator !=(BufferSegment left, AutoReleaseBuffer right) => !left.Equals(right);
|
||||
public static implicit operator byte[](BufferSegment left) => left.Data;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = StringBuilderPool.Get(this.Count + 5);
|
||||
sb.Append("[BufferSegment ");
|
||||
|
||||
if (this.Count > 0)
|
||||
{
|
||||
sb.AppendFormat("Offset: {0:N0} ", this.Offset);
|
||||
sb.AppendFormat("Count: {0:N0} ", this.Count);
|
||||
sb.Append("Data: [");
|
||||
|
||||
if (this.Count > 0)
|
||||
{
|
||||
int dumpCount = Math.Min(this.Count, ToStringMaxDumpLength);
|
||||
|
||||
sb.AppendFormat("{0:X2}", this.Data[this.Offset]);
|
||||
for (int i = 1; i < dumpCount; ++i)
|
||||
sb.AppendFormat(", {0:X2}", this.Data[this.Offset + i]);
|
||||
|
||||
if (this.Count > dumpCount)
|
||||
sb.Append(", ...");
|
||||
}
|
||||
|
||||
sb.Append("]]");
|
||||
}
|
||||
else
|
||||
sb.Append(']');
|
||||
|
||||
return StringBuilderPool.ReleaseAndGrab(sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user