Skip to content

Commit b383057

Browse files
committed
Added ability to reset the pool and create an empty one
1 parent 0a44651 commit b383057

File tree

1 file changed

+39
-19
lines changed

1 file changed

+39
-19
lines changed

src/DotNext.Threading/Collections/Concurrent/IndexPool.cs

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace DotNext.Collections.Concurrent;
1515
/// </remarks>
1616
[EditorBrowsable(EditorBrowsableState.Advanced)]
1717
[StructLayout(LayoutKind.Auto)]
18-
public struct IndexPool : ISupplier<int>, IConsumer<int>, IReadOnlyCollection<int>
18+
public struct IndexPool : ISupplier<int>, IConsumer<int>, IReadOnlyCollection<int>, IResettable
1919
{
2020
private readonly int maxValue;
2121
private ulong bitmask;
@@ -46,6 +46,21 @@ public IndexPool(int maxValue)
4646
this.maxValue = maxValue;
4747
}
4848

49+
/// <summary>
50+
/// Initializes a new pool that can return an integer within the range [0..<paramref name="maxValue"/>].
51+
/// </summary>
52+
/// <param name="maxValue">The maximum possible value to return, inclusive.</param>
53+
/// <param name="isEmpty"><see langword="true"/> to initialize a pool with an empty set of integers; otherwise, <see langword="false"/>.</param>
54+
/// <exception cref="ArgumentOutOfRangeException"></exception>
55+
public IndexPool(int maxValue, bool isEmpty)
56+
{
57+
if ((uint)maxValue > (uint)MaxValue)
58+
throw new ArgumentOutOfRangeException(nameof(maxValue));
59+
60+
this.maxValue = maxValue;
61+
bitmask = isEmpty ? 0UL : ulong.MaxValue;
62+
}
63+
4964
/// <summary>
5065
/// Gets the maximum number that can be returned by the pool.
5166
/// </summary>
@@ -109,28 +124,28 @@ public int Take()
109124
}
110125

111126
/// <summary>
112-
/// Takes all available indicies, atomically.
127+
/// Takes all available indices, atomically.
113128
/// </summary>
114-
/// <param name="indicies">
115-
/// The buffer to be modified with the indicies taken from the pool.
129+
/// <param name="indices">
130+
/// The buffer to be modified with the indices taken from the pool.
116131
/// The size of the buffer should not be less than <see cref="Capacity"/>.
117132
/// </param>
118-
/// <returns>The number of indicies written to the buffer.</returns>
119-
/// <exception cref="ArgumentOutOfRangeException"><paramref name="indicies"/> is too small to place indicies.</exception>
133+
/// <returns>The number of indices written to the buffer.</returns>
134+
/// <exception cref="ArgumentOutOfRangeException"><paramref name="indices"/> is too small to place indices.</exception>
120135
/// <seealso cref="Return(ReadOnlySpan{int})"/>
121-
public int Take(Span<int> indicies)
136+
public int Take(Span<int> indices)
122137
{
123-
if (indicies.Length < Capacity)
124-
throw new ArgumentOutOfRangeException(nameof(indicies));
138+
if (indices.Length < Capacity)
139+
throw new ArgumentOutOfRangeException(nameof(indices));
125140

126141
var oldValue = Interlocked.Exchange(ref bitmask, 0UL);
127142
var bufferOffset = 0;
128143

129-
for (int bitPosition = 0; bitPosition < Capacity; bitPosition++)
144+
for (var bitPosition = 0; bitPosition < Capacity; bitPosition++)
130145
{
131146
if (Contains(oldValue, bitPosition))
132147
{
133-
indicies[bufferOffset++] = bitPosition;
148+
indices[bufferOffset++] = bitPosition;
134149
}
135150
}
136151

@@ -160,21 +175,26 @@ static void ThrowArgumentOutOfRangeException()
160175
}
161176

162177
/// <summary>
163-
/// Returns multiple indicies, atomically.
178+
/// Returns multiple indices, atomically.
164179
/// </summary>
165-
/// <param name="indicies">The buffer of indicies to return back to the pool.</param>
166-
public void Return(ReadOnlySpan<int> indicies)
180+
/// <param name="indices">The buffer of indices to return back to the pool.</param>
181+
public void Return(ReadOnlySpan<int> indices)
167182
{
168183
var newValue = 0UL;
169184

170-
foreach (var index in indicies)
185+
foreach (var index in indices)
171186
{
172187
newValue |= 1UL << index;
173188
}
174189

175190
Interlocked.Or(ref bitmask, newValue);
176191
}
177192

193+
/// <summary>
194+
/// Returns all values to the pool.
195+
/// </summary>
196+
public void Reset() => Volatile.Write(ref bitmask, ulong.MaxValue);
197+
178198
/// <inheritdoc/>
179199
void IConsumer<int>.Invoke(int value) => Return(value);
180200

@@ -190,14 +210,14 @@ private static bool Contains(ulong bitmask, int index)
190210
=> (bitmask & (1UL << index)) is not 0UL;
191211

192212
/// <summary>
193-
/// Gets the number of available indicies.
213+
/// Gets the number of available indices.
194214
/// </summary>
195215
public readonly int Count => Math.Min(BitOperations.PopCount(bitmask), maxValue + 1);
196216

197217
/// <summary>
198-
/// Gets an enumerator over available indicies in the pool.
218+
/// Gets an enumerator over available indices in the pool.
199219
/// </summary>
200-
/// <returns>The enumerator over available indicies in this pool.</returns>
220+
/// <returns>The enumerator over available indices in this pool.</returns>
201221
public readonly Enumerator GetEnumerator() => new(Volatile.Read(in bitmask), maxValue);
202222

203223
/// <inheritdoc/>
@@ -207,7 +227,7 @@ private static bool Contains(ulong bitmask, int index)
207227
readonly IEnumerator IEnumerable.GetEnumerator() => GetEnumerator().AsClassicEnumerator();
208228

209229
/// <summary>
210-
/// Represents an enumerator over available indicies in the pool.
230+
/// Represents an enumerator over available indices in the pool.
211231
/// </summary>
212232
[StructLayout(LayoutKind.Auto)]
213233
public struct Enumerator

0 commit comments

Comments
 (0)