diff --git a/PerfectNumbers.Core/ConcurrentFixedCapacityStack.cs b/PerfectNumbers.Core/ConcurrentFixedCapacityStack.cs index 3efa874..dcc983e 100644 --- a/PerfectNumbers.Core/ConcurrentFixedCapacityStack.cs +++ b/PerfectNumbers.Core/ConcurrentFixedCapacityStack.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace PerfectNumbers.Core; @@ -29,7 +30,11 @@ public sealed class ConcurrentFixedCapacityStack(int capacity) public T? Pop() => TryPop(out T? item) ? item : default; [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] - public bool TryPop(out T? item) + /// + /// Tries popping the first element from the stack. It doesn't clear the internal memory buffer from unused references. + /// + /// Returns false when the stack is empty. Returns true otherwise. If the stack was not empty, item contains the first element from the stack. + public bool TryPop([NotNullWhen(true)] out T? item) { while (true) { @@ -43,7 +48,7 @@ public sealed class ConcurrentFixedCapacityStack(int capacity) int next = observed - 1; if (Interlocked.CompareExchange(ref _count, next, observed) == observed) { - item = _items[next]; + item = _items[next]!; return true; } } @@ -59,8 +64,7 @@ public sealed class ConcurrentFixedCapacityStack(int capacity) return; } - Interlocked.Decrement(ref _count); - throw new InvalidOperationException("Stack is full."); + ArgumentOutOfRangeException.ThrowIfGreaterThan(next, _capacity); } [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] diff --git a/PerfectNumbers.Core/FixedCapacityPools.cs b/PerfectNumbers.Core/FixedCapacityPools.cs index 78dc992..81fbcdd 100644 --- a/PerfectNumbers.Core/FixedCapacityPools.cs +++ b/PerfectNumbers.Core/FixedCapacityPools.cs @@ -6,7 +6,7 @@ namespace PerfectNumbers.Core { [ThreadStatic] private static FixedCapacityArrayPool? _arrayPool; - internal static FixedCapacityArrayPool ExclusiveArray + public static FixedCapacityArrayPool ExclusiveArray { [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] @@ -18,7 +18,7 @@ namespace PerfectNumbers.Core { [ThreadStatic] private static IntArrayPool? _intArrayPool; - internal static IntArrayPool ExclusiveIntArray + public static IntArrayPool ExclusiveIntArray { [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] @@ -27,7 +27,7 @@ namespace PerfectNumbers.Core [ThreadStatic] private static UlongArrayPool? _ulongArrayPool; - internal static UlongArrayPool ExclusiveUlongArray + public static UlongArrayPool ExclusiveUlongArray { [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] diff --git a/PerfectNumbers.Core/FixedCapacityStack.cs b/PerfectNumbers.Core/FixedCapacityStack.cs index 19bc6c4..e5c0440 100644 --- a/PerfectNumbers.Core/FixedCapacityStack.cs +++ b/PerfectNumbers.Core/FixedCapacityStack.cs @@ -27,9 +27,16 @@ public sealed class FixedCapacityStack(int capacity) } } + /// + /// Sets the no. of elements on the stack to 0. It doesn't clear the internal memory buffer from unused references. + /// [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] public void Clear() => Count = 0; + /// + /// Pops and returns the first element from the stack. It doesn't clear the internal memory buffer from unused references. + /// + /// The first element on the stack or null / default when the stack is empty. [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] public T? Pop() => Count > 0 ? _items[Count--] : default; @@ -37,9 +44,10 @@ public sealed class FixedCapacityStack(int capacity) public void Push(T item) { int newCount = Count + 1; - if (newCount < _items.Length) + T[] items = _items; + if (newCount < items.Length) { - _items[newCount] = item; + items[newCount] = item; Count = newCount; } }