diff --git a/PerfectNumbers.Core/PrimeOrderCalculator.cs b/PerfectNumbers.Core/PrimeOrderCalculator.cs index da15d5c..b3da51d 100644 --- a/PerfectNumbers.Core/PrimeOrderCalculator.cs +++ b/PerfectNumbers.Core/PrimeOrderCalculator.cs @@ -799,8 +799,8 @@ internal static partial class PrimeOrderCalculator gpuFactored = PrimeOrderGpuHeuristics.TryPartialFactor(value, limit, primeSlots, exponentSlots, out factorCount, out remaining, out _); } - Span pendingStorage = stackalloc ulong[4]; - PendingBuffer pending = new PendingBuffer(pendingStorage); + List pending = ThreadStaticPools.RentUlongList(2); + Stack? compositeStack = null; PartialFactorResult result; if (!gpuFactored) @@ -822,10 +822,8 @@ internal static partial class PrimeOrderCalculator if (config.PollardRhoMilliseconds > 0 && pending.Count > 0) { - Span compositeStorage = stackalloc ulong[8]; - CompositeStack compositeStack = new CompositeStack(compositeStorage); - long deadlineTimestamp = CreateDeadlineTimestamp(config.PollardRhoMilliseconds); + compositeStack = ThreadStaticPools.RentUlongStack(Math.Max(pending.Count * 2, 4)); compositeStack.Push(remaining); pending.Clear(); @@ -862,16 +860,13 @@ internal static partial class PrimeOrderCalculator compositeStack.Push(factor); compositeStack.Push(quotient); } - - compositeStack.Dispose(); } ulong cofactor = 1UL; - ReadOnlySpan pendingSpan = pending.AsSpan(); - int pendingCount = pendingSpan.Length; + int pendingCount = pending.Count; for (int i = 0; i < pendingCount; i++) { - ulong composite = pendingSpan[i]; + ulong composite = pending[i]; bool isPrime = Open.Numeric.Primes.Prime.Numbers.IsPrime(composite); if (isPrime) { @@ -961,183 +956,17 @@ internal static partial class PrimeOrderCalculator ThreadStaticPools.ReturnUlongIntDictionary(counts); } - pending.Dispose(); + if (compositeStack is not null) + { + compositeStack.Clear(); + ThreadStaticPools.ReturnUlongStack(compositeStack); + } + + pending.Clear(); + ThreadStaticPools.ReturnUlongList(pending); return result; } - private ref struct PendingBuffer - { - private Span _stack; - private ulong[]? _pooled; - private int _count; - - public PendingBuffer(Span stack) - { - _stack = stack; - _pooled = null; - _count = 0; - } - - public int Count => _count; - - public void Add(ulong value) - { - if (_pooled is null) - { - if (_count < _stack.Length) - { - _stack[_count] = value; - _count++; - return; - } - - int initialCapacity = _stack.Length == 0 ? 4 : _stack.Length * 2; - ulong[] newArray = ArrayPool.Shared.Rent(initialCapacity); - for (int i = 0; i < _count; i++) - { - newArray[i] = _stack[i]; - } - - _pooled = newArray; - } - - EnsurePooledCapacity(_count + 1); - _pooled![_count] = value; - _count++; - } - - private void EnsurePooledCapacity(int required) - { - ulong[] array = _pooled!; - if (required <= array.Length) - { - return; - } - - int newCapacity = array.Length * 2; - if (newCapacity < required) - { - newCapacity = required; - } - - ulong[] newArray = ArrayPool.Shared.Rent(newCapacity); - Array.Copy(array, 0, newArray, 0, _count); - ArrayPool.Shared.Return(array, clearArray: false); - _pooled = newArray; - } - - public void Clear() - { - _count = 0; - } - - public ReadOnlySpan AsSpan() - { - if (_pooled is null) - { - return _stack.Slice(0, _count); - } - - return new ReadOnlySpan(_pooled, 0, _count); - } - - public void Dispose() - { - if (_pooled is not null) - { - ArrayPool.Shared.Return(_pooled, clearArray: false); - _pooled = null; - } - - _count = 0; - } - } - - private ref struct CompositeStack - { - private Span _stack; - private ulong[]? _pooled; - private int _count; - - public CompositeStack(Span stack) - { - _stack = stack; - _pooled = null; - _count = 0; - } - - public int Count => _count; - - public void Push(ulong value) - { - if (_pooled is null) - { - if (_count < _stack.Length) - { - _stack[_count] = value; - _count++; - return; - } - - int initialCapacity = _stack.Length == 0 ? 4 : _stack.Length * 2; - ulong[] newArray = ArrayPool.Shared.Rent(initialCapacity); - for (int i = 0; i < _count; i++) - { - newArray[i] = _stack[i]; - } - - _pooled = newArray; - } - - EnsurePooledCapacity(_count + 1); - _pooled![_count] = value; - _count++; - } - - private void EnsurePooledCapacity(int required) - { - ulong[] array = _pooled!; - if (required <= array.Length) - { - return; - } - - int newCapacity = array.Length * 2; - if (newCapacity < required) - { - newCapacity = required; - } - - ulong[] newArray = ArrayPool.Shared.Rent(newCapacity); - Array.Copy(array, 0, newArray, 0, _count); - ArrayPool.Shared.Return(array, clearArray: false); - _pooled = newArray; - } - - public ulong Pop() - { - int index = _count - 1; - _count = index; - if (_pooled is null) - { - return _stack[index]; - } - - return _pooled[index]; - } - - public void Dispose() - { - if (_pooled is not null) - { - ArrayPool.Shared.Return(_pooled, clearArray: false); - _pooled = null; - } - - _count = 0; - } - } - private const int GpuSmallPrimeFactorSlots = 64; private static bool TryPopulateSmallPrimeFactorsCpu(