Files
even-perfect-numbers-scanner/PerfectNumbers.Core/UlongArrayPool.cs

103 lines
3.3 KiB
C#

using System.Numerics;
using System.Runtime.CompilerServices;
namespace PerfectNumbers.Core
{
public struct UlongArrayPool(int poolCapacity)
{
private const int MinBucketPower = 1;
private static readonly int MaxBucketPower = CalculateMaxBucketPower();
private static readonly int MaxBucketLength = 1 << MaxBucketPower;
private static readonly int BucketCount = MaxBucketPower - MinBucketPower + 1;
private readonly ulong[][] _arrays = new ulong[poolCapacity * BucketCount][];
private readonly int[] _counts = new int[BucketCount];
private readonly int _bucketCapacity = poolCapacity;
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public readonly ulong[] Rent(int length)
{
int bucketIndex = GetBucketIndex(length);
if (bucketIndex < 0)
{
return new ulong[length];
}
int[] counts = _counts;
int available = counts[bucketIndex];
int bucketLength = GetBucketLength(bucketIndex);
if (available == 0)
{
return new ulong[bucketLength];
}
int offset = (bucketIndex * _bucketCapacity) + (available - 1);
counts[bucketIndex] = available - 1;
return _arrays[offset];
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public readonly void Return(ulong[] array)
{
int capacity = array.Length;
int bucketIndex = GetBucketIndex(capacity);
if (bucketIndex < 0)
{
return;
}
int bucketLength = GetBucketLength(bucketIndex);
if (capacity < bucketLength)
{
return;
}
int[] counts = _counts;
int available = counts[bucketIndex];
int bucketCapacity = _bucketCapacity;
if (available >= bucketCapacity)
{
return;
}
int offset = (bucketIndex * bucketCapacity) + available;
_arrays[offset] = array;
counts[bucketIndex] = available + 1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static int GetBucketIndex(int length)
{
if (length <= 0 || length > MaxBucketLength)
{
return -1;
}
if (length <= (1 << MinBucketPower))
{
return 0;
}
int power = 32 - BitOperations.LeadingZeroCount((uint)(length - 1));
if (power > MaxBucketPower)
{
return -1;
}
return power - MinBucketPower;
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static int GetBucketLength(int bucketIndex) => 1 << (bucketIndex + MinBucketPower);
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static int CalculateMaxBucketPower()
{
int maxLength = Math.Min(int.MaxValue, Array.MaxLength);
int leadingZeros = BitOperations.LeadingZeroCount((uint)maxLength);
return 31 - leadingZeros;
}
}
}