#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using System; using System.Threading; namespace Cysharp.Threading.Tasks.Internal { // Same interface as System.Buffers.ArrayPool but only provides Shared. internal sealed class ArrayPool { // Same size as System.Buffers.DefaultArrayPool const int DefaultMaxNumberOfArraysPerBucket = 50; static readonly T[] EmptyArray = new T[0]; public static readonly ArrayPool Shared = new ArrayPool(); readonly MinimumQueue[] buckets; readonly SpinLock[] locks; ArrayPool() { // see: GetQueueIndex buckets = new MinimumQueue[18]; locks = new SpinLock[18]; for (int i = 0; i < buckets.Length; i++) { buckets[i] = new MinimumQueue(4); locks[i] = new SpinLock(false); } } public T[] Rent(int minimumLength) { if (minimumLength < 0) { throw new ArgumentOutOfRangeException("minimumLength"); } else if (minimumLength == 0) { return EmptyArray; } var size = CalculateSize(minimumLength); var index = GetQueueIndex(size); if (index != -1) { var q = buckets[index]; var lockTaken = false; try { locks[index].Enter(ref lockTaken); if (q.Count != 0) { return q.Dequeue(); } } finally { if (lockTaken) locks[index].Exit(false); } } return new T[size]; } public void Return(T[] array, bool clearArray = false) { if (array == null || array.Length == 0) { return; } var index = GetQueueIndex(array.Length); if (index != -1) { if (clearArray) { Array.Clear(array, 0, array.Length); } var q = buckets[index]; var lockTaken = false; try { locks[index].Enter(ref lockTaken); if (q.Count > DefaultMaxNumberOfArraysPerBucket) { return; } q.Enqueue(array); } finally { if (lockTaken) locks[index].Exit(false); } } } static int CalculateSize(int size) { size--; size |= size >> 1; size |= size >> 2; size |= size >> 4; size |= size >> 8; size |= size >> 16; size += 1; if (size < 8) { size = 8; } return size; } static int GetQueueIndex(int size) { switch (size) { case 8: return 0; case 16: return 1; case 32: return 2; case 64: return 3; case 128: return 4; case 256: return 5; case 512: return 6; case 1024: return 7; case 2048: return 8; case 4096: return 9; case 8192: return 10; case 16384: return 11; case 32768: return 12; case 65536: return 13; case 131072: return 14; case 262144: return 15; case 524288: return 16; case 1048576: return 17; // max array length default: return -1; } } } }