com.alicizax.unity/Runtime/Extension/Extension/SpanExtension.cs
陈思海 bf0d8340af init
2025-02-07 16:04:12 +08:00

538 lines
18 KiB
C#

using System;
using System.Runtime.InteropServices;
[UnityEngine.Scripting.Preserve]
public static class SpanExtension
{
/// <summary>
/// 整型的大小
/// </summary>
public const int IntSize = sizeof(int);
/// <summary>
/// 短整型的大小
/// </summary>
public const int ShortSize = sizeof(short);
/// <summary>
/// 长整型的大小
/// </summary>
public const int LongSize = sizeof(long);
/// <summary>
/// 单精度浮点数的大小
/// </summary>
public const int FloatSize = sizeof(float);
/// <summary>
/// 双精度浮点数的大小
/// </summary>
public const int DoubleSize = sizeof(double);
/// <summary>
/// 字节的大小
/// </summary>
public const int ByteSize = sizeof(byte);
/// <summary>
/// 有符号字节的大小
/// </summary>
public const int SbyteSize = sizeof(sbyte);
/// <summary>
/// 布尔值的大小
/// </summary>
public const int BoolSize = sizeof(bool);
#region WriteSpan
/// <summary>
/// 将一个整数写入到字节数组中。
/// </summary>
/// <param name="buffer">要写入的字节数组。</param>
/// <param name="value">要写入的整数值。</param>
/// <param name="offset">写入操作的偏移量。</param>
public static unsafe void WriteInt(this Span<byte> buffer, int value, ref int offset)
{
if (offset + IntSize > buffer.Length)
{
throw new ArgumentException($"buffer write out of index {offset + IntSize}, {buffer.Length}");
}
fixed (byte* ptr = buffer)
{
*(int*)(ptr + offset) = System.Net.IPAddress.HostToNetworkOrder(value);
offset += IntSize;
}
}
/// <summary>
/// 将一个短整数写入到字节数组中。
/// </summary>
/// <param name="buffer">要写入的字节数组。</param>
/// <param name="value">要写入的短整数值。</param>
/// <param name="offset">写入操作的偏移量。</param>
public static unsafe void WriteShort(this Span<byte> buffer, short value, ref int offset)
{
if (offset + ShortSize > buffer.Length)
{
throw new ArgumentException($"buffer write out of index {offset + ShortSize}, {buffer.Length}");
}
fixed (byte* ptr = buffer)
{
*(short*)(ptr + offset) = System.Net.IPAddress.HostToNetworkOrder(value);
offset += ShortSize;
}
}
/// <summary>
/// 将一个长整数写入到字节数组中。
/// </summary>
/// <param name="buffer">要写入的字节数组。</param>
/// <param name="value">要写入的长整数值。</param>
/// <param name="offset">写入操作的偏移量。</param>
public static unsafe void WriteLong(this Span<byte> buffer, long value, ref int offset)
{
if (offset + LongSize > buffer.Length)
{
throw new ArgumentException($"buffer write out of index {offset + LongSize}, {buffer.Length}");
}
fixed (byte* ptr = buffer)
{
*(long*)(ptr + offset) = System.Net.IPAddress.HostToNetworkOrder(value);
offset += LongSize;
}
}
/// <summary>
/// 将一个浮点数写入到字节数组中。
/// </summary>
/// <param name="buffer">要写入的字节数组。</param>
/// <param name="value">要写入的浮点数值。</param>
/// <param name="offset">写入操作的偏移量。</param>
public static unsafe void WriteFloat(this Span<byte> buffer, float value, ref int offset)
{
if (offset + FloatSize > buffer.Length)
{
throw new ArgumentException($"buffer write out of index {offset + FloatSize}, {buffer.Length}");
}
fixed (byte* ptr = buffer)
{
*(float*)(ptr + offset) = value;
*(int*)(ptr + offset) = System.Net.IPAddress.HostToNetworkOrder(*(int*)(ptr + offset));
offset += FloatSize;
}
}
/// <summary>
/// 将双精度浮点数写入缓冲区。
/// </summary>
/// <param name="buffer">要写入的字节范围。</param>
/// <param name="value">要写入的双精度浮点数值。</param>
/// <param name="offset">偏移量,指示从何处开始写入。</param>
public static unsafe void WriteDouble(this Span<byte> buffer, double value, ref int offset)
{
if (offset + DoubleSize > buffer.Length)
{
throw new ArgumentException($"buffer write out of index {offset + DoubleSize}, {buffer.Length}");
}
fixed (byte* ptr = buffer)
{
*(double*)(ptr + offset) = value;
*(long*)(ptr + offset) = System.Net.IPAddress.HostToNetworkOrder(*(long*)(ptr + offset));
offset += DoubleSize;
}
}
/// <summary>
/// 将字节写入缓冲区。
/// </summary>
/// <param name="buffer">要写入的字节范围。</param>
/// <param name="value">要写入的字节值。</param>
/// <param name="offset">偏移量,指示从何处开始写入。</param>
public static unsafe void WriteByte(this Span<byte> buffer, byte value, ref int offset)
{
if (offset + ByteSize > buffer.Length)
{
throw new ArgumentException($"buffer write out of index {offset + ByteSize}, {buffer.Length}");
}
fixed (byte* ptr = buffer)
{
*(ptr + offset) = value;
offset += ByteSize;
}
}
/// <summary>
/// 将字节数组写入缓冲区。
/// </summary>
/// <param name="buffer">要写入的字节范围。</param>
/// <param name="value">要写入的字节数组。</param>
/// <param name="offset">偏移量,指示从何处开始写入。</param>
public static unsafe void WriteBytes(this Span<byte> buffer, byte[] value, ref int offset)
{
if (value == null)
{
buffer.WriteInt(0, ref offset);
return;
}
if (offset + value.Length + IntSize > buffer.Length)
{
throw new ArgumentException($"buffer write out of index {offset + value.Length + IntSize}, {buffer.Length}");
}
buffer.WriteInt(value.Length, ref offset);
//System.Array.Copy(value, 0, buffer, offset, value.Length);
//offset += value.Length;
fixed (byte* ptr = buffer, valPtr = value)
{
Buffer.MemoryCopy(valPtr, ptr + offset, value.Length, value.Length);
offset += value.Length;
}
}
/// <summary>
/// 将字节数组写入缓冲区,不包括长度信息。
/// </summary>
/// <param name="buffer">要写入的字节范围。</param>
/// <param name="value">要写入的字节数组。</param>
/// <param name="offset">偏移量,指示从缓冲区的哪个位置开始写入。</param>
public static unsafe void WriteBytesWithoutLength(this Span<byte> buffer, byte[] value, ref int offset)
{
if (value == null)
{
buffer.WriteInt(0, ref offset);
return;
}
if (offset + value.Length + IntSize > buffer.Length)
{
throw new ArgumentException($"buffer write out of index {offset + value.Length + IntSize}, {buffer.Length}");
}
fixed (byte* ptr = buffer, valPtr = value)
{
Buffer.MemoryCopy(valPtr, ptr + offset, value.Length, value.Length);
offset += value.Length;
}
}
/// <summary>
/// 将有符号字节写入缓冲区。
/// </summary>
/// <param name="buffer">要写入的字节范围。</param>
/// <param name="value">要写入的有符号字节值。</param>
/// <param name="offset">偏移量,指示从缓冲区的哪个位置开始写入。</param>
public static unsafe void WriteSByte(this Span<byte> buffer, sbyte value, ref int offset)
{
if (offset + SbyteSize > buffer.Length)
{
throw new ArgumentException($"buffer write out of index {offset + SbyteSize}, {buffer.Length}");
}
fixed (byte* ptr = buffer)
{
*(sbyte*)(ptr + offset) = value;
offset += SbyteSize;
}
}
/// <summary>
/// 将字符串写入缓冲区
/// </summary>
/// <param name="buffer">要写入的缓冲区</param>
/// <param name="value">要写入的字符串</param>
/// <param name="offset">偏移量</param>
public static unsafe void WriteString(this Span<byte> buffer, string value, ref int offset)
{
if (value == null)
{
value = string.Empty;
}
int len = System.Text.Encoding.UTF8.GetByteCount(value);
if (len > short.MaxValue)
{
throw new ArgumentException($"string length exceed short.MaxValue {len}, {short.MaxValue}");
}
//预判已经超出长度了,直接计算长度就行了
if (offset + len + ShortSize > buffer.Length)
{
throw new ArgumentException($"buffer write out of index {offset + len + ShortSize}, {buffer.Length}");
}
buffer.WriteShort((short)len, ref offset);
var val = System.Text.Encoding.UTF8.GetBytes(value);
fixed (byte* ptr = buffer, valPtr = val)
{
//System.Text.Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, offset + ShortSize);
//WriteShort((short)len, buffer, ref offset);
//offset += len;
Buffer.MemoryCopy(valPtr, ptr + offset, len, len);
offset += len;
}
}
/// <summary>
/// 将布尔值写入缓冲区
/// </summary>
/// <param name="buffer">要写入的缓冲区</param>
/// <param name="value">要写入的布尔值</param>
/// <param name="offset">偏移量</param>
public static unsafe void WriteBool(this Span<byte> buffer, bool value, ref int offset)
{
if (offset + BoolSize > buffer.Length)
{
throw new ArgumentException($"buffer write out of index {offset + BoolSize}, {buffer.Length}");
}
fixed (byte* ptr = buffer)
{
*(bool*)(ptr + offset) = value;
offset += BoolSize;
}
}
#endregion
#region ReadSpan
/// <summary>
/// 从字节数组中读取一个整数。
/// </summary>
/// <param name="buffer">包含整数的字节数组。</param>
/// <param name="offset">偏移量,指示从何处开始读取整数。</param>
/// <returns>从字节数组中读取的整数。</returns>
public static unsafe int ReadInt(this Span<byte> buffer, ref int offset)
{
if (offset > buffer.Length + IntSize)
{
throw new ArgumentOutOfRangeException(nameof(offset), "buffer read out of index");
}
fixed (byte* ptr = buffer)
{
var value = *(int*)(ptr + offset);
offset += IntSize;
return System.Net.IPAddress.NetworkToHostOrder(value);
}
}
/// <summary>
/// 从指定的字节数组中读取一个 16 位有符号整数,并将偏移量向前移动 2 个字节。
/// </summary>
/// <param name="buffer">包含要读取的数据的字节数组。</param>
/// <param name="offset">要开始读取的位置。读取完成后,此参数将包含新的偏移量值。</param>
/// <returns>一个 16 位有符号整数。</returns>
public static unsafe short ReadShort(this Span<byte> buffer, ref int offset)
{
if (offset > buffer.Length + ShortSize)
{
throw new ArgumentOutOfRangeException(nameof(offset), "buffer read out of index");
}
fixed (byte* ptr = buffer)
{
var value = *(short*)(ptr + offset);
offset += ShortSize;
return System.Net.IPAddress.NetworkToHostOrder(value);
}
}
/// <summary>
/// 从字节数组中读取一个64位整数。
/// </summary>
/// <param name="buffer">包含数据的字节数组。</param>
/// <param name="offset">偏移量,指示从何处开始读取。</param>
/// <returns>读取的64位整数。</returns>
public static unsafe long ReadLong(this Span<byte> buffer, ref int offset)
{
if (offset > buffer.Length + LongSize)
{
throw new ArgumentOutOfRangeException(nameof(offset), "buffer read out of index");
}
fixed (byte* ptr = buffer)
{
var value = *(long*)(ptr + offset);
offset += LongSize;
return System.Net.IPAddress.NetworkToHostOrder(value);
}
}
/// <summary>
/// 从字节数组中读取一个单精度浮点数。
/// </summary>
/// <param name="buffer">包含数据的字节数组。</param>
/// <param name="offset">偏移量,指示从何处开始读取。</param>
/// <returns>读取的单精度浮点数。</returns>
public static unsafe float ReadFloat(this Span<byte> buffer, ref int offset)
{
if (offset > buffer.Length + FloatSize)
{
throw new ArgumentOutOfRangeException(nameof(offset), "buffer read out of index");
}
fixed (byte* ptr = buffer)
{
*(int*)(ptr + offset) = System.Net.IPAddress.NetworkToHostOrder(*(int*)(ptr + offset));
var value = *(float*)(ptr + offset);
offset += FloatSize;
return value;
}
}
/// <summary>
/// 从字节数组中读取一个双精度浮点数。
/// </summary>
/// <param name="buffer">包含数据的 Span<byte> 对象。</param>
/// <param name="offset">从字节数组开始读取的偏移量。</param>
/// <returns>从字节数组中读取的双精度浮点数。</returns>
public static unsafe double ReadDouble(this Span<byte> buffer, ref int offset)
{
if (offset > buffer.Length + DoubleSize)
{
throw new ArgumentOutOfRangeException(nameof(offset), "buffer read out of index");
}
fixed (byte* ptr = buffer)
{
*(long*)(ptr + offset) = System.Net.IPAddress.NetworkToHostOrder(*(long*)(ptr + offset));
var value = *(double*)(ptr + offset);
offset += DoubleSize;
return value;
}
}
/// <summary>
/// 从字节数组中读取一个字节。
/// </summary>
/// <param name="buffer">包含数据的 Span<byte> 对象。</param>
/// <param name="offset">从字节数组开始读取的偏移量。</param>
/// <returns>从字节数组中读取的字节。</returns>
public static unsafe byte ReadByte(this Span<byte> buffer, ref int offset)
{
if (offset > buffer.Length + ByteSize)
{
throw new ArgumentOutOfRangeException(nameof(offset), "buffer read out of index");
}
fixed (byte* ptr = buffer)
{
var value = *(ptr + offset);
offset += ByteSize;
return value;
}
}
/// <summary>
/// 从给定的缓冲区中读取字节数组。
/// </summary>
/// <param name="buffer">包含数据的 Span。</param>
/// <param name="offset">从缓冲区中读取数据的偏移量。</param>
/// <returns>从缓冲区中读取的字节数组。</returns>
public static unsafe byte[] ReadBytes(this Span<byte> buffer, ref int offset)
{
var len = ReadInt(buffer, ref offset);
//数据不可信
if (len <= 0 || offset > buffer.Length + len * ByteSize)
return Array.Empty<byte>();
//var data = new byte[len];
//System.Array.Copy(buffer, offset, data, 0, len);
var data = buffer.Slice(offset, len).ToArray();
offset += len;
return data;
}
/// <summary>
/// 从给定的缓冲区中读取有符号字节。
/// </summary>
/// <param name="buffer">包含数据的 Span。</param>
/// <param name="offset">从缓冲区中读取数据的偏移量。</param>
/// <returns>从缓冲区中读取的有符号字节。</returns>
public static unsafe sbyte ReadSByte(this Span<byte> buffer, ref int offset)
{
if (offset > buffer.Length + ByteSize)
{
throw new ArgumentOutOfRangeException(nameof(offset), "buffer read out of index");
}
fixed (byte* ptr = buffer)
{
var value = *(sbyte*)(ptr + offset);
offset += ByteSize;
return value;
}
}
/// <summary>
/// 从字节范围中读取字符串。
/// </summary>
/// <param name="buffer">包含字符串的字节范围。</param>
/// <param name="offset">偏移量。</param>
/// <returns>从字节范围中读取的字符串。</returns>
public static unsafe string ReadString(this Span<byte> buffer, ref int offset)
{
var len = ReadShort(buffer, ref offset);
//数据不可信
if (len <= 0 || offset > buffer.Length + len * ByteSize)
{
return string.Empty;
}
fixed (byte* ptr = buffer)
{
var value = System.Text.Encoding.UTF8.GetString(ptr + offset, len);
offset += len;
return value;
}
}
/// <summary>
/// 从字节范围中读取布尔值。
/// </summary>
/// <param name="buffer">包含布尔值的字节范围。</param>
/// <param name="offset">偏移量。</param>
/// <returns>从字节范围中读取的布尔值。</returns>
public static unsafe bool ReadBool(this Span<byte> buffer, ref int offset)
{
if (offset > buffer.Length + BoolSize)
{
throw new ArgumentOutOfRangeException(nameof(offset), "buffer read out of index");
}
fixed (byte* ptr = buffer)
{
var value = *(bool*)(ptr + offset);
offset += BoolSize;
return value;
}
}
#endregion
/// <summary>
/// 将只读内存转换为数组段。
/// </summary>
/// <param name="memory">只读内存。</param>
/// <returns>数组段。</returns>
public static ArraySegment<byte> GetArray(this ReadOnlyMemory<byte> memory)
{
if (!MemoryMarshal.TryGetArray(memory, out var result))
{
throw new InvalidOperationException("Buffer backed by array was expected");
}
return result;
}
}