123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- using System;
- namespace ProtoBuf
- {
- internal sealed class BufferPool
- {
- internal static void Flush()
- {
- lock (Pool)
- {
- for (var 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)
- {
- var bestIndex = -1;
- byte[] bestMatch = null;
- for (var i = 0; i < Pool.Length; i++)
- {
- var buffer = Pool[i];
- if (buffer == null || buffer.Size < minSize)
- {
- continue;
- }
- if (bestMatch != null && bestMatch.Length < buffer.Size)
- {
- continue;
- }
- var 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);
- }
- var 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)
- {
- var minIndex = 0;
- var minSize = int.MaxValue;
- for (var i = 0; i < Pool.Length; i++)
- {
- var 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);
- }
- }
- }
- }
|