Use pooled arrays in RecyclableDictionary

This commit is contained in:
Marek Lemańczyk committed 2025-07-14 06:24:40 +02:00
1 parent 0f2d05f60d
commit f9af1086e5
1 file changed
+65 -6
+65 -6
View File
@@ -2,6 +2,7 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Recyclable.Collections.Pools;
namespace Recyclable.Collections namespace Recyclable.Collections
{ {
@@ -14,7 +15,9 @@ namespace Recyclable.Collections
private readonly int _blockSizeMinus1; private readonly int _blockSizeMinus1;
private readonly byte _blockShift; private readonly byte _blockShift;
#nullable disable
private Entry[][] _entries; private Entry[][] _entries;
#nullable restore
private int[] _buckets; private int[] _buckets;
private int _count; private int _count;
private bool _disposed; private bool _disposed;
@@ -38,8 +41,12 @@ namespace Recyclable.Collections
_blockSizeMinus1 = blockSize - 1; _blockSizeMinus1 = blockSize - 1;
_blockShift = (byte)(31 - BitOperations.LeadingZeroCount((uint)blockSize)); _blockShift = (byte)(31 - BitOperations.LeadingZeroCount((uint)blockSize));
_entries = new Entry[4][]; _entries = 4 >= RecyclableDefaults.MinPooledArrayLength
_entries[0] = new Entry[blockSize]; ? RecyclableArrayPool<Entry[]>.RentShared(4)
: new Entry[4][];
_entries[0] = blockSize >= RecyclableDefaults.MinPooledArrayLength
? RecyclableArrayPool<Entry>.RentShared(blockSize)
: new Entry[blockSize];
_buckets = new int[4]; _buckets = new int[4];
Array.Fill(_buckets, -1); Array.Fill(_buckets, -1);
} }
@@ -170,12 +177,38 @@ namespace Recyclable.Collections
} }
public void Clear() public void Clear()
{
if (_count == 0)
{
Array.Fill(_buckets, -1);
return;
}
int blockIndex = 0;
if (_blockSize >= RecyclableDefaults.MinPooledArrayLength)
{
while (blockIndex < _entries.Length && _entries[blockIndex] != null)
{
RecyclableArrayPool<Entry>.ReturnShared(_entries[blockIndex]!, _needsClearing);
_entries[blockIndex++] = null!;
}
}
else
{ {
if (_needsClearing) if (_needsClearing)
{ {
for (var i = 0; i < _count; i++) while (blockIndex < _entries.Length && _entries[blockIndex] != null)
{ {
ClearEntry(i); Array.Clear(_entries[blockIndex]!, 0, _entries[blockIndex]!.Length);
_entries[blockIndex++] = null!;
}
}
else
{
while (blockIndex < _entries.Length && _entries[blockIndex] != null)
{
_entries[blockIndex++] = null!;
}
} }
} }
@@ -201,6 +234,16 @@ namespace Recyclable.Collections
} }
Clear(); Clear();
if (_entries.Length >= RecyclableDefaults.MinPooledArrayLength)
{
RecyclableArrayPool<Entry[]>.ReturnShared(_entries, false);
}
if (_buckets.Length >= RecyclableDefaults.MinPooledArrayLength)
{
RecyclableArrayPool<int>.ReturnShared(_buckets, false);
}
_entries = Array.Empty<Entry[]>(); _entries = Array.Empty<Entry[]>();
_buckets = Array.Empty<int>(); _buckets = Array.Empty<int>();
_disposed = true; _disposed = true;
@@ -254,12 +297,28 @@ namespace Recyclable.Collections
int requiredBlocks = (min + _blockSizeMinus1) >> _blockShift; int requiredBlocks = (min + _blockSizeMinus1) >> _blockShift;
if (_entries.Length < requiredBlocks) if (_entries.Length < requiredBlocks)
{ {
Array.Resize(ref _entries, requiredBlocks); var newBlocks = requiredBlocks >= RecyclableDefaults.MinPooledArrayLength
? RecyclableArrayPool<Entry[]>.RentShared(requiredBlocks)
: new Entry[requiredBlocks][];
Array.Copy(_entries, newBlocks, _entries.Length);
if (_entries.Length >= RecyclableDefaults.MinPooledArrayLength)
{
RecyclableArrayPool<Entry[]>.ReturnShared(_entries, false);
}
_entries = newBlocks;
} }
for (int i = 0; i < requiredBlocks; i++) for (int i = 0; i < requiredBlocks; i++)
{ {
_entries[i] ??= new Entry[_blockSize]; if (_entries[i] == null)
{
_entries[i] = _blockSize >= RecyclableDefaults.MinPooledArrayLength
? RecyclableArrayPool<Entry>.RentShared(_blockSize)
: new Entry[_blockSize];
}
} }
} }