zxl
/
CTT
forked from Cal/CTT
1
0
Fork 0
CTT/Unity/Assets/ThirdParty/protobuf-net/BufferPool.cs

150 lines
4.3 KiB
C#

using System;
namespace ProtoBuf
{
internal sealed class BufferPool
{
internal static void Flush()
{
lock (Pool)
{
for (int i = 0; i < Pool.Length; i++)
Pool[i] = null;
}
}
private BufferPool() { }
private const int POOL_SIZE = 20;
internal const int BUFFER_LENGTH = 1024;
private static readonly CachedBuffer[] Pool = new CachedBuffer[POOL_SIZE];
internal static byte[] GetBuffer() => GetBuffer(BUFFER_LENGTH);
internal static byte[] GetBuffer(int minSize)
{
byte[] cachedBuff = GetCachedBuffer(minSize);
return cachedBuff ?? new byte[minSize];
}
internal static byte[] GetCachedBuffer(int minSize)
{
lock (Pool)
{
int bestIndex = -1;
byte[] bestMatch = null;
for (int i = 0; i < Pool.Length; i++)
{
CachedBuffer buffer = Pool[i];
if (buffer == null || buffer.Size < minSize)
{
continue;
}
if (bestMatch != null && bestMatch.Length < buffer.Size)
{
continue;
}
byte[] tmp = buffer.Buffer;
if (tmp == null)
{
Pool[i] = null;
}
else
{
bestMatch = tmp;
bestIndex = i;
}
}
if (bestIndex >= 0)
{
Pool[bestIndex] = null;
}
return bestMatch;
}
}
/// <remarks>
/// https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/runtime/gcallowverylargeobjects-element
/// </remarks>
private const int MaxByteArraySize = int.MaxValue - 56;
internal static void ResizeAndFlushLeft(ref byte[] buffer, int toFitAtLeastBytes, int copyFromIndex, int copyBytes)
{
Helpers.DebugAssert(buffer != null);
Helpers.DebugAssert(toFitAtLeastBytes > buffer.Length);
Helpers.DebugAssert(copyFromIndex >= 0);
Helpers.DebugAssert(copyBytes >= 0);
int newLength = buffer.Length * 2;
if (newLength < 0)
{
newLength = MaxByteArraySize;
}
if (newLength < toFitAtLeastBytes) newLength = toFitAtLeastBytes;
if (copyBytes == 0)
{
ReleaseBufferToPool(ref buffer);
}
byte[] newBuffer = GetCachedBuffer(toFitAtLeastBytes) ?? new byte[newLength];
if (copyBytes > 0)
{
Buffer.BlockCopy(buffer, copyFromIndex, newBuffer, 0, copyBytes);
ReleaseBufferToPool(ref buffer);
}
buffer = newBuffer;
}
internal static void ReleaseBufferToPool(ref byte[] buffer)
{
if (buffer == null) return;
lock (Pool)
{
int minIndex = 0;
int minSize = int.MaxValue;
for (int i = 0; i < Pool.Length; i++)
{
CachedBuffer tmp = Pool[i];
if (tmp == null || !tmp.IsAlive)
{
minIndex = 0;
break;
}
if (tmp.Size < minSize)
{
minIndex = i;
minSize = tmp.Size;
}
}
Pool[minIndex] = new CachedBuffer(buffer);
}
buffer = null;
}
private class CachedBuffer
{
private readonly WeakReference _reference;
public int Size { get; }
public bool IsAlive => _reference.IsAlive;
public byte[] Buffer => (byte[])_reference.Target;
public CachedBuffer(byte[] buffer)
{
Size = buffer.Length;
_reference = new WeakReference(buffer);
}
}
}
}