Files
ThingsGateway/src/Admin/ThingsGateway.NewLife.X/Buffers/PooledByteBufferWriter.cs
2025-05-23 12:55:21 +08:00

125 lines
3.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#if NETFRAMEWORK || NETSTANDARD2_0
using ValueTask = System.Threading.Tasks.Task;
#endif
namespace ThingsGateway.NewLife.Buffers;
/// <summary>池化缓冲区写入器</summary>
public sealed class PooledByteBufferWriter : IBufferWriter<Byte>, IDisposable
{
#region
private Byte[] _rentedBuffer;
private Int32 _index;
/// <summary>已写入内存</summary>
public ReadOnlyMemory<Byte> WrittenMemory => _rentedBuffer.AsMemory(0, _index);
/// <summary>容量</summary>
public Int32 Capacity => _rentedBuffer.Length;
#endregion
#region
/// <summary>指定初始容量并初始化写入器</summary>
/// <param name="initialCapacity"></param>
public PooledByteBufferWriter(Int32 initialCapacity)
{
_rentedBuffer = ArrayPool<Byte>.Shared.Rent(initialCapacity);
_index = 0;
}
/// <summary>销毁。释放内存并返回池里</summary>
public void Dispose()
{
if (_rentedBuffer != null)
ClearAndReturnBuffers();
}
#endregion
#region
/// <summary>初始化空实例</summary>
/// <param name="initialCapacity"></param>
public void InitializeEmptyInstance(Int32 initialCapacity)
{
_rentedBuffer = ArrayPool<Byte>.Shared.Rent(initialCapacity);
_index = 0;
}
/// <summary>清空写入器</summary>
public void Clear()
{
_rentedBuffer.AsSpan(0, _index).Clear();
_index = 0;
}
/// <summary>清空写入器并归还到对象池</summary>
public void ClearAndReturnBuffers()
{
Clear();
var rentedBuffer = _rentedBuffer;
_rentedBuffer = null!;
ArrayPool<Byte>.Shared.Return(rentedBuffer);
}
/// <summary>通知 IBufferWriter已向输出写入 count 数据项。</summary>
/// <param name="count"></param>
public void Advance(Int32 count) => _index += count;
/// <summary>返回要向其中写入数据的 Memory且大小至少是 sizeHint 指定的请求大小。</summary>
/// <param name="sizeHint"></param>
/// <returns></returns>
public Memory<Byte> GetMemory(Int32 sizeHint = 256)
{
CheckAndResizeBuffer(sizeHint);
return _rentedBuffer.AsMemory(_index);
}
/// <summary>返回要向其中写入数据的 Span且大小至少是 sizeHint 指定的请求大小。</summary>
/// <param name="sizeHint"></param>
/// <returns></returns>
public Span<Byte> GetSpan(Int32 sizeHint = 256)
{
CheckAndResizeBuffer(sizeHint);
return _rentedBuffer.AsSpan(_index);
}
/// <summary>写入到数据流</summary>
/// <param name="destination"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public ValueTask WriteToStreamAsync(Stream destination, CancellationToken cancellationToken) => destination.WriteAsync(WrittenMemory, cancellationToken);
/// <summary>写入到数据流</summary>
/// <param name="destination"></param>
public void WriteToStream(Stream destination) => destination.Write(_rentedBuffer, 0, _index);
private void CheckAndResizeBuffer(Int32 sizeHint)
{
var num = _rentedBuffer.Length;
var num2 = num - _index;
if (_index >= 1073741795)
{
sizeHint = Math.Max(sizeHint, 2147483591 - num);
}
if (sizeHint <= num2) return;
var num3 = Math.Max(sizeHint, num);
var num4 = num + num3;
if ((UInt32)num4 > 2147483591u)
{
num4 = num + sizeHint;
if ((UInt32)num4 > 2147483591u)
{
throw new OutOfMemoryException($"BufferMaximumSizeExceeded({num4})");
}
}
var rentedBuffer = _rentedBuffer;
_rentedBuffer = ArrayPool<Byte>.Shared.Rent(num4);
var span = rentedBuffer.AsSpan(0, _index);
span.CopyTo(_rentedBuffer);
span.Clear();
ArrayPool<Byte>.Shared.Return(rentedBuffer);
}
#endregion
}