ArrayBuffer
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace System.Net
{
[StructLayout(LayoutKind.Auto)]
internal struct ArrayBuffer : IDisposable
{
private const int ArrayMaxLength = 2147483591;
private readonly bool _usePool;
private byte[] _bytes;
private int _activeStart;
private int _availableStart;
public int ActiveLength => _availableStart - _activeStart;
public Span<byte> ActiveSpan => new Span<byte>(_bytes, _activeStart, _availableStart - _activeStart);
public ReadOnlySpan<byte> ActiveReadOnlySpan => new ReadOnlySpan<byte>(_bytes, _activeStart, _availableStart - _activeStart);
public Memory<byte> ActiveMemory => new Memory<byte>(_bytes, _activeStart, _availableStart - _activeStart);
public int AvailableLength => _bytes.Length - _availableStart;
public Span<byte> AvailableSpan => _bytes.AsSpan(_availableStart);
public Memory<byte> AvailableMemory => _bytes.AsMemory(_availableStart);
public int Capacity => _bytes.Length;
public int ActiveStartOffset => _activeStart;
public ArrayBuffer(int initialSize, bool usePool = false)
{
_usePool = usePool;
_bytes = ((initialSize == 0) ? Array.Empty<byte>() : (usePool ? ArrayPool<byte>.Shared.Rent(initialSize) : new byte[initialSize]));
_activeStart = 0;
_availableStart = 0;
}
public ArrayBuffer(byte[] buffer)
{
_usePool = false;
_bytes = buffer;
_activeStart = 0;
_availableStart = 0;
}
public void Dispose()
{
_activeStart = 0;
_availableStart = 0;
byte[] bytes = _bytes;
_bytes = null;
if (bytes != null)
ReturnBufferIfPooled(bytes);
}
public void ClearAndReturnBuffer()
{
_activeStart = 0;
_availableStart = 0;
byte[] bytes = _bytes;
_bytes = Array.Empty<byte>();
ReturnBufferIfPooled(bytes);
}
public Memory<byte> AvailableMemorySliced(int length)
{
return new Memory<byte>(_bytes, _availableStart, length);
}
public byte[] DangerousGetUnderlyingBuffer()
{
return _bytes;
}
public void Discard(int byteCount)
{
_activeStart += byteCount;
if (_activeStart == _availableStart) {
_activeStart = 0;
_availableStart = 0;
}
}
public void Commit(int byteCount)
{
_availableStart += byteCount;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void EnsureAvailableSpace(int byteCount)
{
if (byteCount > AvailableLength)
EnsureAvailableSpaceCore(byteCount);
}
private void EnsureAvailableSpaceCore(int byteCount)
{
if (_bytes.Length == 0)
_bytes = ArrayPool<byte>.Shared.Rent(byteCount);
else {
int num = _activeStart + AvailableLength;
if (byteCount <= num) {
Buffer.BlockCopy(_bytes, _activeStart, _bytes, 0, ActiveLength);
_availableStart = ActiveLength;
_activeStart = 0;
} else {
int num2 = ActiveLength + byteCount;
if ((uint)num2 > 2147483591)
throw new OutOfMemoryException();
int num3 = Math.Max(num2, (int)Math.Min(2147483591, (uint)(2 * _bytes.Length)));
byte[] array = _usePool ? ArrayPool<byte>.Shared.Rent(num3) : new byte[num3];
byte[] bytes = _bytes;
if (ActiveLength != 0)
Buffer.BlockCopy(bytes, _activeStart, array, 0, ActiveLength);
_availableStart = ActiveLength;
_activeStart = 0;
_bytes = array;
ReturnBufferIfPooled(bytes);
}
}
}
public void Grow()
{
EnsureAvailableSpaceCore(AvailableLength + 1);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReturnBufferIfPooled(byte[] buffer)
{
if (_usePool && buffer.Length != 0)
ArrayPool<byte>.Shared.Return(buffer, false);
}
}
}