Add iterators to UnsafeBitSet and SpanBitSet
Introduced `Iterator` structs in `UnsafeBitSet` and `SpanBitSet` to enable efficient traversal of set bits. Added `GetIterator` methods to both structs to return iterator instances. Implemented `NextSetBit` in `SpanBitSet` to support iterator functionality. Changed constants in `UnsafeBitSet` from `private` to `internal` for broader assembly access. Removed redundant methods from `SpanBitSet` to streamline the API in favor of iterator-based operations. Updated constructors in `UnsafeSlotMap` and `UnsafeSparseSet` to conditionally clear arrays based on `AllocationOption.Clear`. Incremented assembly version to 1.2.7 to reflect these updates.
This commit is contained in:
@@ -10,10 +10,29 @@ namespace Misaki.HighPerformance.LowLevel.Collections;
|
||||
|
||||
public unsafe struct UnsafeBitSet : IDisposable
|
||||
{
|
||||
private const int _BIT_SIZE = sizeof(uint) * 8 - 1; // 31
|
||||
private const int _INDEX_SIZE = 5; // log_2(BitSize + 1)
|
||||
private const int _MASK = (1 << 5) - 1; // 0x1F, the mask to get the bit index inside a uint
|
||||
private static readonly int s_padding = Vector<uint>.Count; // The padding used for vectorization, the amount of uints required for being vectorized basically
|
||||
public ref struct Iterator
|
||||
{
|
||||
private UnsafeBitSet _bitSet;
|
||||
private int _currentBit;
|
||||
|
||||
public Iterator (UnsafeBitSet bitSet)
|
||||
{
|
||||
_bitSet = bitSet;
|
||||
_currentBit = -1;
|
||||
}
|
||||
|
||||
public bool Next(out int bitIndex)
|
||||
{
|
||||
_currentBit = _bitSet.NextSetBit(_currentBit + 1);
|
||||
bitIndex = _currentBit;
|
||||
return _currentBit != -1;
|
||||
}
|
||||
}
|
||||
|
||||
internal const int _BIT_SIZE = sizeof(uint) * 8 - 1; // 31
|
||||
internal const int _INDEX_SIZE = 5; // log_2(BitSize + 1)
|
||||
internal const int _MASK = (1 << 5) - 1; // 0x1F, the mask to get the bit index inside a uint
|
||||
internal static readonly int s_padding = Vector<uint>.Count; // The padding used for vectorization, the amount of uints required for being vectorized basically
|
||||
|
||||
private UnsafeArray<uint> _bits;
|
||||
private int _highestBit;
|
||||
@@ -97,6 +116,11 @@ public unsafe struct UnsafeBitSet : IDisposable
|
||||
return (id >> _INDEX_SIZE) + int.Sign(id & _BIT_SIZE);
|
||||
}
|
||||
|
||||
public readonly Iterator GetIterator()
|
||||
{
|
||||
return new Iterator(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a bit is set at the index.
|
||||
/// </summary>
|
||||
@@ -717,6 +741,25 @@ public unsafe struct UnsafeBitSet : IDisposable
|
||||
/// </summary>
|
||||
public readonly ref struct SpanBitSet
|
||||
{
|
||||
public ref struct Iterator
|
||||
{
|
||||
private SpanBitSet _bitSet;
|
||||
private int _currentBit;
|
||||
|
||||
public Iterator(SpanBitSet bitSet)
|
||||
{
|
||||
_bitSet = bitSet;
|
||||
_currentBit = -1;
|
||||
}
|
||||
|
||||
public bool Next(out int bitIndex)
|
||||
{
|
||||
_currentBit = _bitSet.NextSetBit(_currentBit + 1);
|
||||
bitIndex = _currentBit;
|
||||
return _currentBit != -1;
|
||||
}
|
||||
}
|
||||
|
||||
private const int _BIT_SIZE = sizeof(uint) * 8 - 1; // 31
|
||||
// NOTE: Is a byte not 8 bits?
|
||||
private const int _BYTE_SIZE = 5; // log_2(BitSize + 1)
|
||||
@@ -734,12 +777,16 @@ public readonly ref struct SpanBitSet
|
||||
_bits = bits;
|
||||
}
|
||||
|
||||
public readonly Iterator GetIterator()
|
||||
{
|
||||
return new Iterator(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a bit is set at the index.
|
||||
/// </summary>
|
||||
/// <param name="index">The index.</param>
|
||||
/// <returns>True if it is, otherwise false</returns>
|
||||
|
||||
public bool IsSet(int index)
|
||||
{
|
||||
var b = index >> _BYTE_SIZE;
|
||||
@@ -756,7 +803,6 @@ public readonly ref struct SpanBitSet
|
||||
/// Resizes its internal array if necessary.
|
||||
/// </summary>
|
||||
/// <param name="index">The index.</param>
|
||||
|
||||
public void SetBit(int index)
|
||||
{
|
||||
var b = index >> _BYTE_SIZE;
|
||||
@@ -772,7 +818,6 @@ public readonly ref struct SpanBitSet
|
||||
/// Clears the bit at the given index.
|
||||
/// </summary>
|
||||
/// <param name="index">The index.</param>
|
||||
|
||||
public void ClearBit(int index)
|
||||
{
|
||||
var b = index >> _BYTE_SIZE;
|
||||
@@ -787,7 +832,6 @@ public readonly ref struct SpanBitSet
|
||||
/// <summary>
|
||||
/// Sets all bits.
|
||||
/// </summary>
|
||||
|
||||
public void SetAll()
|
||||
{
|
||||
var count = _bits.Length;
|
||||
@@ -800,12 +844,40 @@ public readonly ref struct SpanBitSet
|
||||
/// <summary>
|
||||
/// Clears all set bits.
|
||||
/// </summary>
|
||||
|
||||
public void ClearAll()
|
||||
{
|
||||
_bits.Clear();
|
||||
}
|
||||
|
||||
public int NextSetBit(int startIndex)
|
||||
{
|
||||
var wordIndex = startIndex >> _BIT_SIZE;
|
||||
if (wordIndex >= _bits.Length)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Mask off bits below startIndex in the first word:
|
||||
var word = _bits[wordIndex] & ~0u << (startIndex & UnsafeBitSet._MASK);
|
||||
while (true)
|
||||
{
|
||||
if (word != 0)
|
||||
{
|
||||
// get the least-significant set bit
|
||||
var bit = BitOperations.TrailingZeroCount(word);
|
||||
return (wordIndex << _BIT_SIZE) + bit;
|
||||
}
|
||||
|
||||
wordIndex++;
|
||||
if (wordIndex >= _bits.Length)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
word = _bits[wordIndex];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="Span{T}"/> to access the <see cref="_bits"/>.
|
||||
/// </summary>
|
||||
|
||||
@@ -91,6 +91,10 @@ public unsafe struct UnsafeSlotMap<T> : IUnsafeCollection<T>
|
||||
_freeSlots = new UnsafeQueue<int>(capacity, ref handle, allocationOption);
|
||||
_validBits = new UnsafeBitSet(GetBitSetCapacity(capacity), ref handle, allocationOption);
|
||||
|
||||
if (!allocationOption.HasFlag(AllocationOption.Clear))
|
||||
{
|
||||
_generations.AsSpan().Clear();
|
||||
}
|
||||
_validBits.ClearAll();
|
||||
|
||||
_count = 0;
|
||||
|
||||
@@ -94,6 +94,12 @@ public unsafe struct UnsafeSparseSet<T> : IUnsafeCollection<T>
|
||||
_reverse = new UnsafeArray<int>(capacity, ref handle, allocationOption);
|
||||
_freeSparse = new UnsafeStack<int>(capacity, ref handle, allocationOption);
|
||||
|
||||
if (!allocationOption.HasFlag(AllocationOption.Clear))
|
||||
{
|
||||
_generations.AsSpan().Clear();
|
||||
_sparse.AsSpan().Clear();
|
||||
}
|
||||
|
||||
_count = 0;
|
||||
_nextId = 0;
|
||||
_capacity = capacity;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<Authors>Misaki</Authors>
|
||||
<AssemblyVersion>1.2.6</AssemblyVersion>
|
||||
<AssemblyVersion>1.2.7</AssemblyVersion>
|
||||
<Version>$(AssemblyVersion)</Version>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<PackageProjectUrl>https://git.personalnas.com/Misaki/Misaki.HighPerformance.git</PackageProjectUrl>
|
||||
|
||||
Reference in New Issue
Block a user