feat(collections)!: switch to ref struct enumerators
Refactor all unsafe collection enumerators to use ref struct types, removing support for boxing and standard .NET enumeration interfaces. GetEnumerator methods now return stack-only, more efficient enumerators with [UnscopedRef] and inlining attributes. IEnumerable<T> and IEnumerable implementations are removed from affected types. Interfaces now require unmanaged types. Also includes minor doc and bug fixes. BREAKING CHANGE: Enumerators are no longer compatible with LINQ, and collections no longer implement IEnumerable/IEnumerator.
This commit is contained in:
@@ -27,7 +27,7 @@ public unsafe interface IUnsafeCollection : IDisposable
|
|||||||
void* GetUnsafePtr();
|
void* GetUnsafePtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IUnsafeCollection<T> : IUnsafeCollection, IEnumerable<T>
|
public interface IUnsafeCollection<T> : IUnsafeCollection
|
||||||
where T : unmanaged
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -47,7 +47,7 @@ public interface IUnsafeCollection<T> : IUnsafeCollection, IEnumerable<T>
|
|||||||
void Resize(int newSize, AllocationOption option);
|
void Resize(int newSize, AllocationOption option);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IUnsafeHashCollection<T> : IEnumerable<T>, IDisposable
|
public interface IUnsafeHashCollection<T> : IDisposable
|
||||||
where T : unmanaged
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -9,16 +9,16 @@ namespace Misaki.HighPerformance.LowLevel.Collections;
|
|||||||
public unsafe struct HashMapHelper<TKey> : IDisposable
|
public unsafe struct HashMapHelper<TKey> : IDisposable
|
||||||
where TKey : unmanaged, IEquatable<TKey>
|
where TKey : unmanaged, IEquatable<TKey>
|
||||||
{
|
{
|
||||||
internal struct Enumerator
|
internal ref struct Enumerator
|
||||||
{
|
{
|
||||||
public HashMapHelper<TKey>* buffer;
|
public ref HashMapHelper<TKey> helper;
|
||||||
public int index;
|
public int index;
|
||||||
public int bucketIndex;
|
public int bucketIndex;
|
||||||
public int nextIndex;
|
public int nextIndex;
|
||||||
|
|
||||||
public Enumerator(HashMapHelper<TKey>* data)
|
public Enumerator(ref HashMapHelper<TKey> data)
|
||||||
{
|
{
|
||||||
buffer = data;
|
helper = ref data;
|
||||||
index = -1;
|
index = -1;
|
||||||
bucketIndex = 0;
|
bucketIndex = 0;
|
||||||
nextIndex = -1;
|
nextIndex = -1;
|
||||||
@@ -27,7 +27,7 @@ public unsafe struct HashMapHelper<TKey> : IDisposable
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool MoveNext()
|
public bool MoveNext()
|
||||||
{
|
{
|
||||||
return buffer->MoveNext(ref bucketIndex, ref nextIndex, out index);
|
return helper.MoveNext(ref bucketIndex, ref nextIndex, out index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
@@ -41,7 +41,7 @@ public unsafe struct HashMapHelper<TKey> : IDisposable
|
|||||||
public KeyValuePair<TKey, TValue> GetCurrent<TValue>()
|
public KeyValuePair<TKey, TValue> GetCurrent<TValue>()
|
||||||
where TValue : unmanaged
|
where TValue : unmanaged
|
||||||
{
|
{
|
||||||
return new KeyValuePair<TKey, TValue>(buffer->_keys[index], UnsafeUtility.ReadArrayElementRef<TValue>(buffer->_buffer, index));
|
return new KeyValuePair<TKey, TValue>(helper._keys[index], UnsafeUtility.ReadArrayElementRef<TValue>(helper._buffer, index));
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -49,7 +49,7 @@ public unsafe struct HashMapHelper<TKey> : IDisposable
|
|||||||
{
|
{
|
||||||
if (index != -1)
|
if (index != -1)
|
||||||
{
|
{
|
||||||
return buffer->_keys[index];
|
return helper._keys[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Misaki.HighPerformance.LowLevel.Collections.Contracts;
|
|||||||
using Misaki.HighPerformance.LowLevel.Utilities;
|
using Misaki.HighPerformance.LowLevel.Utilities;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.LowLevel.Collections;
|
namespace Misaki.HighPerformance.LowLevel.Collections;
|
||||||
@@ -42,18 +43,16 @@ internal class UnsafeArrayDebugView<T>
|
|||||||
public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>
|
public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>
|
||||||
where T : unmanaged
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
public struct Enumerator : IEnumerator<T>
|
public ref struct Enumerator
|
||||||
{
|
{
|
||||||
private readonly UnsafeArray<T>* _collection;
|
private ref UnsafeArray<T> _collection;
|
||||||
private int _index;
|
private int _index;
|
||||||
|
|
||||||
public readonly ref T Current => ref _collection->_buffer[_index];
|
public readonly ref T Current => ref _collection._buffer[_index];
|
||||||
readonly T IEnumerator<T>.Current => Current;
|
|
||||||
readonly object IEnumerator.Current => Current;
|
|
||||||
|
|
||||||
public Enumerator(UnsafeArray<T>* collection)
|
public Enumerator(ref UnsafeArray<T> collection)
|
||||||
{
|
{
|
||||||
_collection = collection;
|
_collection = ref collection;
|
||||||
_index = -1;
|
_index = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,17 +60,13 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>
|
|||||||
public bool MoveNext()
|
public bool MoveNext()
|
||||||
{
|
{
|
||||||
_index++;
|
_index++;
|
||||||
return _index < _collection->_count;
|
return _index < _collection._count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
_index = -1;
|
_index = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private T* _buffer;
|
private T* _buffer;
|
||||||
@@ -130,21 +125,6 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumerator GetEnumerator()
|
|
||||||
{
|
|
||||||
return new((UnsafeArray<T>*)UnsafeUtility.AddressOf(ref this));
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invalid constructor, use <see cref="UnsafeArray(int, Allocator, AllocationOption)"/> or <see cref="UnsafeArray(int, AllocationHandle, AllocationOption)"/> instead.
|
/// Invalid constructor, use <see cref="UnsafeArray(int, Allocator, AllocationOption)"/> or <see cref="UnsafeArray(int, AllocationHandle, AllocationOption)"/> instead.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -245,6 +225,13 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>
|
|||||||
return new ReadOnlyUnsafeCollection<T>(_buffer, _count);
|
return new ReadOnlyUnsafeCollection<T>(_buffer, _count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[UnscopedRef]
|
||||||
|
public Enumerator GetEnumerator()
|
||||||
|
{
|
||||||
|
return new Enumerator(ref this);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Resize(int newSize, AllocationOption option = AllocationOption.None)
|
public void Resize(int newSize, AllocationOption option = AllocationOption.None)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
|
using Misaki.HighPerformance.LowLevel.Utilities;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@@ -36,18 +38,18 @@ public unsafe struct UnsafeBitSet : IDisposable, IEquatable<UnsafeBitSet>
|
|||||||
{
|
{
|
||||||
public ref struct Iterator
|
public ref struct Iterator
|
||||||
{
|
{
|
||||||
private readonly UnsafeBitSet* _bitSet;
|
private ref UnsafeBitSet _bitSet;
|
||||||
private int _currentBit;
|
private int _currentBit;
|
||||||
|
|
||||||
public Iterator(UnsafeBitSet* bitSet, int start)
|
public Iterator(ref UnsafeBitSet bitSet, int start)
|
||||||
{
|
{
|
||||||
_bitSet = bitSet;
|
_bitSet = ref bitSet;
|
||||||
_currentBit = start - 1;
|
_currentBit = start - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Next(out int bitIndex)
|
public bool Next(out int bitIndex)
|
||||||
{
|
{
|
||||||
_currentBit = _bitSet->NextSetBit(_currentBit + 1);
|
_currentBit = _bitSet.NextSetBit(_currentBit + 1);
|
||||||
bitIndex = _currentBit;
|
bitIndex = _currentBit;
|
||||||
return _currentBit != -1;
|
return _currentBit != -1;
|
||||||
}
|
}
|
||||||
@@ -128,6 +130,7 @@ public unsafe struct UnsafeBitSet : IDisposable, IEquatable<UnsafeBitSet>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static int RoundToPadding(int length)
|
private static int RoundToPadding(int length)
|
||||||
{
|
{
|
||||||
return (length + s_padding - 1) / s_padding * s_padding;
|
return (length + s_padding - 1) / s_padding * s_padding;
|
||||||
@@ -138,14 +141,17 @@ public unsafe struct UnsafeBitSet : IDisposable, IEquatable<UnsafeBitSet>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The ID or bit.</param>
|
/// <param name="id">The ID or bit.</param>
|
||||||
/// <returns>A size of required <see cref="uint"/>s for the bitset.</returns>
|
/// <returns>A size of required <see cref="uint"/>s for the bitset.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int RequiredLength(int id)
|
public static int RequiredLength(int id)
|
||||||
{
|
{
|
||||||
return (id >> _INDEX_SIZE) + int.Sign(id & _BIT_SIZE);
|
return (id >> _INDEX_SIZE) + int.Sign(id & _BIT_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly Iterator GetIterator(int start = 0)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[UnscopedRef]
|
||||||
|
public Iterator GetIterator(int start = 0)
|
||||||
{
|
{
|
||||||
return new Iterator((UnsafeBitSet*)Unsafe.AsPointer(in this), start);
|
return new Iterator(ref this, start);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -153,6 +159,7 @@ public unsafe struct UnsafeBitSet : IDisposable, IEquatable<UnsafeBitSet>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index">The index.</param>
|
/// <param name="index">The index.</param>
|
||||||
/// <returns>True if it is, otherwise false</returns>
|
/// <returns>True if it is, otherwise false</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public readonly bool IsSet(int index)
|
public readonly bool IsSet(int index)
|
||||||
{
|
{
|
||||||
var b = index >> _INDEX_SIZE;
|
var b = index >> _INDEX_SIZE;
|
||||||
@@ -169,6 +176,7 @@ public unsafe struct UnsafeBitSet : IDisposable, IEquatable<UnsafeBitSet>
|
|||||||
/// Resizes its internal array if necessary.
|
/// Resizes its internal array if necessary.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index">The index.</param>
|
/// <param name="index">The index.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void SetBit(int index)
|
public void SetBit(int index)
|
||||||
{
|
{
|
||||||
var b = index >> _INDEX_SIZE;
|
var b = index >> _INDEX_SIZE;
|
||||||
@@ -188,6 +196,7 @@ public unsafe struct UnsafeBitSet : IDisposable, IEquatable<UnsafeBitSet>
|
|||||||
/// Clears the bit at the given index.
|
/// Clears the bit at the given index.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index">The index.</param>
|
/// <param name="index">The index.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void ClearBit(int index)
|
public void ClearBit(int index)
|
||||||
{
|
{
|
||||||
var b = index >> _INDEX_SIZE;
|
var b = index >> _INDEX_SIZE;
|
||||||
@@ -202,6 +211,7 @@ public unsafe struct UnsafeBitSet : IDisposable, IEquatable<UnsafeBitSet>
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets all bits.
|
/// Sets all bits.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void SetAll()
|
public void SetAll()
|
||||||
{
|
{
|
||||||
_bits.AsSpan().Fill(0xffffffff);
|
_bits.AsSpan().Fill(0xffffffff);
|
||||||
@@ -213,6 +223,7 @@ public unsafe struct UnsafeBitSet : IDisposable, IEquatable<UnsafeBitSet>
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears all set bits.
|
/// Clears all set bits.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void ClearAll()
|
public void ClearAll()
|
||||||
{
|
{
|
||||||
_bits.Clear();
|
_bits.Clear();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using Misaki.HighPerformance.LowLevel.Buffer;
|
|||||||
using Misaki.HighPerformance.LowLevel.Collections.Contracts;
|
using Misaki.HighPerformance.LowLevel.Collections.Contracts;
|
||||||
using Misaki.HighPerformance.LowLevel.Utilities;
|
using Misaki.HighPerformance.LowLevel.Utilities;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.LowLevel.Collections;
|
namespace Misaki.HighPerformance.LowLevel.Collections;
|
||||||
@@ -10,16 +11,15 @@ public unsafe struct UnsafeHashMap<TKey, TValue> : IUnsafeHashCollection<KeyValu
|
|||||||
where TKey : unmanaged, IEquatable<TKey>
|
where TKey : unmanaged, IEquatable<TKey>
|
||||||
where TValue : unmanaged
|
where TValue : unmanaged
|
||||||
{
|
{
|
||||||
public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>
|
public ref struct Enumerator
|
||||||
{
|
{
|
||||||
internal HashMapHelper<TKey>.Enumerator _enumerator;
|
internal HashMapHelper<TKey>.Enumerator _enumerator;
|
||||||
|
|
||||||
public KeyValuePair<TKey, TValue> Current => _enumerator.GetCurrent<TValue>();
|
public KeyValuePair<TKey, TValue> Current => _enumerator.GetCurrent<TValue>();
|
||||||
object IEnumerator.Current => Current;
|
|
||||||
|
|
||||||
public Enumerator(HashMapHelper<TKey>* data)
|
public Enumerator(ref HashMapHelper<TKey> data)
|
||||||
{
|
{
|
||||||
_enumerator = new HashMapHelper<TKey>.Enumerator(data);
|
_enumerator = new HashMapHelper<TKey>.Enumerator(ref data);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -75,21 +75,6 @@ public unsafe struct UnsafeHashMap<TKey, TValue> : IUnsafeHashCollection<KeyValu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumerator GetEnumerator()
|
|
||||||
{
|
|
||||||
return new((HashMapHelper<TKey>*)UnsafeUtility.AddressOf(ref this));
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invalid constructor, use <see cref="UnsafeHashMap(int, Allocator, AllocationOption)"/> or <see cref="UnsafeHashMap(int, AllocationHandle, AllocationOption)"/> instead.
|
/// Invalid constructor, use <see cref="UnsafeHashMap(int, Allocator, AllocationOption)"/> or <see cref="UnsafeHashMap(int, AllocationHandle, AllocationOption)"/> instead.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -108,6 +93,13 @@ public unsafe struct UnsafeHashMap<TKey, TValue> : IUnsafeHashCollection<KeyValu
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[UnscopedRef]
|
||||||
|
public Enumerator GetEnumerator()
|
||||||
|
{
|
||||||
|
return new Enumerator(ref _helper);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a new key-value pair.
|
/// Adds a new key-value pair.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections.Contracts;
|
using Misaki.HighPerformance.LowLevel.Collections.Contracts;
|
||||||
using Misaki.HighPerformance.LowLevel.Utilities;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Collections;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.LowLevel.Collections;
|
namespace Misaki.HighPerformance.LowLevel.Collections;
|
||||||
@@ -11,19 +10,18 @@ namespace Misaki.HighPerformance.LowLevel.Collections;
|
|||||||
/// removing, and checking for values.
|
/// removing, and checking for values.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">Represents an unmanaged type that can be compared for equality.</typeparam>
|
/// <typeparam name="T">Represents an unmanaged type that can be compared for equality.</typeparam>
|
||||||
public unsafe struct UnsafeHashSet<T> : IUnsafeHashCollection<T>, IEnumerable<T>
|
public unsafe struct UnsafeHashSet<T> : IUnsafeHashCollection<T>
|
||||||
where T : unmanaged, IEquatable<T>
|
where T : unmanaged, IEquatable<T>
|
||||||
{
|
{
|
||||||
public struct Enumerator : IEnumerator<T>
|
public ref struct Enumerator
|
||||||
{
|
{
|
||||||
internal HashMapHelper<T>.Enumerator _enumerator;
|
internal HashMapHelper<T>.Enumerator _enumerator;
|
||||||
|
|
||||||
public readonly T Current => _enumerator.buffer->_keys[_enumerator.index];
|
public readonly T Current => _enumerator.helper._keys[_enumerator.index];
|
||||||
readonly object IEnumerator.Current => Current;
|
|
||||||
|
|
||||||
public Enumerator(HashMapHelper<T>* hashMap)
|
public Enumerator(ref HashMapHelper<T> hashMap)
|
||||||
{
|
{
|
||||||
_enumerator = new HashMapHelper<T>.Enumerator(hashMap);
|
_enumerator = new HashMapHelper<T>.Enumerator(ref hashMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -36,10 +34,6 @@ public unsafe struct UnsafeHashSet<T> : IUnsafeHashCollection<T>, IEnumerable<T>
|
|||||||
{
|
{
|
||||||
_enumerator.Reset();
|
_enumerator.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private HashMapHelper<T> _helper;
|
private HashMapHelper<T> _helper;
|
||||||
@@ -48,21 +42,6 @@ public unsafe struct UnsafeHashSet<T> : IUnsafeHashCollection<T>, IEnumerable<T>
|
|||||||
public readonly int Capacity => _helper.Capacity;
|
public readonly int Capacity => _helper.Capacity;
|
||||||
public readonly bool IsCreated => _helper.IsCreated;
|
public readonly bool IsCreated => _helper.IsCreated;
|
||||||
|
|
||||||
public Enumerator GetEnumerator()
|
|
||||||
{
|
|
||||||
return new((HashMapHelper<T>*)UnsafeUtility.AddressOf(ref this));
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invalid constructor. Use <see cref="UnsafeHashSet(int, Allocator, AllocationOption)"/> or <see cref="UnsafeHashSet(int, AllocationHandle, AllocationOption)"/> instead."/>
|
/// Invalid constructor. Use <see cref="UnsafeHashSet(int, Allocator, AllocationOption)"/> or <see cref="UnsafeHashSet(int, AllocationHandle, AllocationOption)"/> instead."/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -81,6 +60,13 @@ public unsafe struct UnsafeHashSet<T> : IUnsafeHashCollection<T>, IEnumerable<T>
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[UnscopedRef]
|
||||||
|
public Enumerator GetEnumerator()
|
||||||
|
{
|
||||||
|
return new Enumerator(ref _helper);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a new value (unless it is already present).
|
/// Adds a new value (unless it is already present).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Misaki.HighPerformance.LowLevel.Collections.Contracts;
|
|||||||
using Misaki.HighPerformance.LowLevel.Utilities;
|
using Misaki.HighPerformance.LowLevel.Utilities;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.LowLevel.Collections;
|
namespace Misaki.HighPerformance.LowLevel.Collections;
|
||||||
@@ -39,18 +40,16 @@ internal class UnsafeListDebugView<T>
|
|||||||
public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
||||||
where T : unmanaged
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
public struct Enumerator : IEnumerator<T>
|
public ref struct Enumerator
|
||||||
{
|
{
|
||||||
private readonly UnsafeList<T>* _collection;
|
private ref UnsafeList<T> _collection;
|
||||||
private int _index;
|
private int _index;
|
||||||
|
|
||||||
public readonly ref T Current => ref _collection->_array[_index];
|
public readonly ref T Current => ref _collection._array[_index];
|
||||||
readonly T IEnumerator<T>.Current => Current;
|
|
||||||
readonly object IEnumerator.Current => Current;
|
|
||||||
|
|
||||||
public Enumerator(UnsafeList<T>* collection)
|
public Enumerator(ref UnsafeList<T> collection)
|
||||||
{
|
{
|
||||||
_collection = collection;
|
_collection = ref collection;
|
||||||
_index = -1;
|
_index = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,17 +57,13 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
|||||||
public bool MoveNext()
|
public bool MoveNext()
|
||||||
{
|
{
|
||||||
_index++;
|
_index++;
|
||||||
return _index < _collection->_count;
|
return _index < _collection._count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
_index = -1;
|
_index = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -76,7 +71,7 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Use <see cref="AsParallelReader"/> to create a parallel reader for a list.
|
/// Use <see cref="AsParallelReader"/> to create a parallel reader for a list.
|
||||||
/// The list must live at least as long as the parallel reader, and the parallel reader must not be used after the list is disposed.
|
/// The list must live and the address of the list remain stable at least as long as the parallel reader, and the parallel reader must not be used after the list is disposed.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public readonly unsafe struct ParallelReader
|
public readonly unsafe struct ParallelReader
|
||||||
{
|
{
|
||||||
@@ -102,7 +97,7 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
|||||||
|
|
||||||
public readonly Enumerator GetEnumerator()
|
public readonly Enumerator GetEnumerator()
|
||||||
{
|
{
|
||||||
return new Enumerator(listData);
|
return new Enumerator(ref *listData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly ReadOnlySpan<T> AsSpan()
|
public readonly ReadOnlySpan<T> AsSpan()
|
||||||
@@ -116,7 +111,7 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Use <see cref="AsParallelWriter"/> to create a parallel writer for a list.
|
/// Use <see cref="AsParallelWriter"/> to create a parallel writer for a list.
|
||||||
/// The list must live at least as long as the parallel writer, and the parallel writer must not be used after the list is disposed.
|
/// The list must live and the address of the list remain stable at least as long as the parallel writer, and the parallel writer must not be used after the list is disposed.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public readonly struct ParallelWriter
|
public readonly struct ParallelWriter
|
||||||
{
|
{
|
||||||
@@ -247,21 +242,10 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[UnscopedRef]
|
||||||
public Enumerator GetEnumerator()
|
public Enumerator GetEnumerator()
|
||||||
{
|
{
|
||||||
return new((UnsafeList<T>*)UnsafeUtility.AddressOf(ref this));
|
return new Enumerator(ref this);
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using Misaki.HighPerformance.LowLevel.Buffer;
|
|||||||
using Misaki.HighPerformance.LowLevel.Collections.Contracts;
|
using Misaki.HighPerformance.LowLevel.Collections.Contracts;
|
||||||
using Misaki.HighPerformance.LowLevel.Utilities;
|
using Misaki.HighPerformance.LowLevel.Utilities;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.LowLevel.Collections;
|
namespace Misaki.HighPerformance.LowLevel.Collections;
|
||||||
@@ -10,16 +11,15 @@ public unsafe struct UnsafeMultiHashMap<TKey, TValue> : IUnsafeHashCollection<Ke
|
|||||||
where TKey : unmanaged, IEquatable<TKey>
|
where TKey : unmanaged, IEquatable<TKey>
|
||||||
where TValue : unmanaged
|
where TValue : unmanaged
|
||||||
{
|
{
|
||||||
public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>
|
public ref struct Enumerator
|
||||||
{
|
{
|
||||||
internal HashMapHelper<TKey>.Enumerator _enumerator;
|
internal HashMapHelper<TKey>.Enumerator _enumerator;
|
||||||
|
|
||||||
public readonly KeyValuePair<TKey, TValue> Current => _enumerator.GetCurrent<TValue>();
|
public readonly KeyValuePair<TKey, TValue> Current => _enumerator.GetCurrent<TValue>();
|
||||||
readonly object IEnumerator.Current => Current;
|
|
||||||
|
|
||||||
public Enumerator(HashMapHelper<TKey>* data)
|
public Enumerator(ref HashMapHelper<TKey> data)
|
||||||
{
|
{
|
||||||
_enumerator = new HashMapHelper<TKey>.Enumerator(data);
|
_enumerator = new HashMapHelper<TKey>.Enumerator(ref data);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -32,10 +32,6 @@ public unsafe struct UnsafeMultiHashMap<TKey, TValue> : IUnsafeHashCollection<Ke
|
|||||||
{
|
{
|
||||||
_enumerator.Reset();
|
_enumerator.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct Iterator
|
public struct Iterator
|
||||||
@@ -50,36 +46,35 @@ public unsafe struct UnsafeMultiHashMap<TKey, TValue> : IUnsafeHashCollection<Ke
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ValueEnumerable
|
public ref struct ValueEnumerable
|
||||||
{
|
{
|
||||||
private readonly HashMapHelper<TKey>* _data;
|
private ref HashMapHelper<TKey> _helper;
|
||||||
private readonly TKey _key;
|
private readonly TKey _key;
|
||||||
|
|
||||||
internal ValueEnumerable(HashMapHelper<TKey>* data, scoped in TKey key)
|
internal ValueEnumerable(ref HashMapHelper<TKey> data, scoped in TKey key)
|
||||||
{
|
{
|
||||||
_data = data;
|
_helper = ref data;
|
||||||
_key = key;
|
_key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly ValueEnumerator GetEnumerator()
|
public readonly ValueEnumerator GetEnumerator()
|
||||||
{
|
{
|
||||||
return new(_data, _key);
|
return new ValueEnumerator(ref _helper, _key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ValueEnumerator : IEnumerator<TValue>
|
public ref struct ValueEnumerator
|
||||||
{
|
{
|
||||||
private readonly HashMapHelper<TKey>* _data;
|
private ref HashMapHelper<TKey> helper;
|
||||||
private readonly TKey _key;
|
private readonly TKey _key;
|
||||||
private int _entryIndex;
|
private int _entryIndex;
|
||||||
private bool _started;
|
private bool _started;
|
||||||
|
|
||||||
public readonly TValue Current => UnsafeUtility.ReadArrayElement<TValue>(_data->Buffer, _entryIndex);
|
public readonly TValue Current => UnsafeUtility.ReadArrayElement<TValue>(helper.Buffer, _entryIndex);
|
||||||
readonly object IEnumerator.Current => Current;
|
|
||||||
|
|
||||||
internal ValueEnumerator(HashMapHelper<TKey>* data, scoped in TKey key)
|
internal ValueEnumerator(ref HashMapHelper<TKey> data, scoped in TKey key)
|
||||||
{
|
{
|
||||||
_data = data;
|
helper = ref data;
|
||||||
_key = key;
|
_key = key;
|
||||||
_entryIndex = -1;
|
_entryIndex = -1;
|
||||||
_started = false;
|
_started = false;
|
||||||
@@ -90,7 +85,7 @@ public unsafe struct UnsafeMultiHashMap<TKey, TValue> : IUnsafeHashCollection<Ke
|
|||||||
{
|
{
|
||||||
if (!_started)
|
if (!_started)
|
||||||
{
|
{
|
||||||
_entryIndex = _data->Find(_key);
|
_entryIndex = helper.Find(_key);
|
||||||
_started = true;
|
_started = true;
|
||||||
return _entryIndex != -1;
|
return _entryIndex != -1;
|
||||||
}
|
}
|
||||||
@@ -100,7 +95,7 @@ public unsafe struct UnsafeMultiHashMap<TKey, TValue> : IUnsafeHashCollection<Ke
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_entryIndex = _data->FindNext(_entryIndex, _key);
|
_entryIndex = helper.FindNext(_entryIndex, _key);
|
||||||
return _entryIndex != -1;
|
return _entryIndex != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,10 +104,6 @@ public unsafe struct UnsafeMultiHashMap<TKey, TValue> : IUnsafeHashCollection<Ke
|
|||||||
_entryIndex = -1;
|
_entryIndex = -1;
|
||||||
_started = false;
|
_started = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private HashMapHelper<TKey> _helper;
|
private HashMapHelper<TKey> _helper;
|
||||||
@@ -121,21 +112,6 @@ public unsafe struct UnsafeMultiHashMap<TKey, TValue> : IUnsafeHashCollection<Ke
|
|||||||
public readonly int Capacity => _helper.Capacity;
|
public readonly int Capacity => _helper.Capacity;
|
||||||
public readonly bool IsCreated => _helper.IsCreated;
|
public readonly bool IsCreated => _helper.IsCreated;
|
||||||
|
|
||||||
public Enumerator GetEnumerator()
|
|
||||||
{
|
|
||||||
return new((HashMapHelper<TKey>*)UnsafeUtility.AddressOf(ref this));
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnsafeMultiHashMap()
|
public UnsafeMultiHashMap()
|
||||||
: this(0, Allocator.Invalid)
|
: this(0, Allocator.Invalid)
|
||||||
{
|
{
|
||||||
@@ -151,12 +127,21 @@ public unsafe struct UnsafeMultiHashMap<TKey, TValue> : IUnsafeHashCollection<Ke
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[UnscopedRef]
|
||||||
|
public Enumerator GetEnumerator()
|
||||||
|
{
|
||||||
|
return new Enumerator(ref _helper);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Add(scoped in TKey key, TValue item)
|
public void Add(scoped in TKey key, TValue item)
|
||||||
{
|
{
|
||||||
var idx = _helper.Add(key);
|
var idx = _helper.Add(key);
|
||||||
UnsafeUtility.WriteArrayElement(_helper.Buffer, idx, item);
|
UnsafeUtility.WriteArrayElement(_helper.Buffer, idx, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Remove(scoped in TKey key)
|
public bool Remove(scoped in TKey key)
|
||||||
{
|
{
|
||||||
return _helper.RemoveAll(key) != 0;
|
return _helper.RemoveAll(key) != 0;
|
||||||
@@ -198,11 +183,13 @@ public unsafe struct UnsafeMultiHashMap<TKey, TValue> : IUnsafeHashCollection<Ke
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool TryGetValue(scoped in TKey key, out TValue item)
|
public bool TryGetValue(scoped in TKey key, out TValue item)
|
||||||
{
|
{
|
||||||
return _helper.TryGetValue(key, out item);
|
return _helper.TryGetValue(key, out item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public TValue GetValueOrDefault(scoped in TKey key, TValue defaultValue = default)
|
public TValue GetValueOrDefault(scoped in TKey key, TValue defaultValue = default)
|
||||||
{
|
{
|
||||||
if (_helper.TryGetValue<TValue>(key, out var value))
|
if (_helper.TryGetValue<TValue>(key, out var value))
|
||||||
@@ -213,46 +200,57 @@ public unsafe struct UnsafeMultiHashMap<TKey, TValue> : IUnsafeHashCollection<Ke
|
|||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[UnscopedRef]
|
||||||
public ValueEnumerable GetValuesForKey(scoped in TKey key)
|
public ValueEnumerable GetValuesForKey(scoped in TKey key)
|
||||||
{
|
{
|
||||||
return new((HashMapHelper<TKey>*)UnsafeUtility.AddressOf(ref this), key);
|
return new ValueEnumerable(ref _helper, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public int CountValuesForKey(scoped in TKey key)
|
public int CountValuesForKey(scoped in TKey key)
|
||||||
{
|
{
|
||||||
return _helper.CountValuesForKey(key);
|
return _helper.CountValuesForKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool ContainsKey(scoped in TKey key)
|
public bool ContainsKey(scoped in TKey key)
|
||||||
{
|
{
|
||||||
return _helper.Find(key) != -1;
|
return _helper.Find(key) != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void TrimExcess()
|
public void TrimExcess()
|
||||||
{
|
{
|
||||||
_helper.TrimExcess();
|
_helper.TrimExcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Resize(int newSize, AllocationOption option = AllocationOption.None)
|
public void Resize(int newSize, AllocationOption option = AllocationOption.None)
|
||||||
{
|
{
|
||||||
_helper.Resize(newSize);
|
_helper.Resize(newSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
_helper.Clear();
|
_helper.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public UnsafeArray<TKey> GetKeyArray(Allocator allocator)
|
public UnsafeArray<TKey> GetKeyArray(Allocator allocator)
|
||||||
{
|
{
|
||||||
return _helper.GetKeyArray(allocator);
|
return _helper.GetKeyArray(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public UnsafeArray<TValue> GetValueArray(Allocator allocator)
|
public UnsafeArray<TValue> GetValueArray(Allocator allocator)
|
||||||
{
|
{
|
||||||
return _helper.GetValueArray<TValue>(allocator);
|
return _helper.GetValueArray<TValue>(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public UnsafeArray<KeyValuePair<TKey, TValue>> GetKeyValueArrays(Allocator allocator)
|
public UnsafeArray<KeyValuePair<TKey, TValue>> GetKeyValueArrays(Allocator allocator)
|
||||||
{
|
{
|
||||||
return _helper.GetKeyValueArrays<TValue>(allocator);
|
return _helper.GetKeyValueArrays<TValue>(allocator);
|
||||||
@@ -264,6 +262,7 @@ public unsafe struct UnsafeMultiHashMap<TKey, TValue> : IUnsafeHashCollection<Ke
|
|||||||
return _helper.Buffer;
|
return _helper.Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_helper.Dispose();
|
_helper.Dispose();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using Misaki.HighPerformance.LowLevel.Buffer;
|
|||||||
using Misaki.HighPerformance.LowLevel.Collections.Contracts;
|
using Misaki.HighPerformance.LowLevel.Collections.Contracts;
|
||||||
using Misaki.HighPerformance.LowLevel.Utilities;
|
using Misaki.HighPerformance.LowLevel.Utilities;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.LowLevel.Collections;
|
namespace Misaki.HighPerformance.LowLevel.Collections;
|
||||||
@@ -13,19 +14,17 @@ namespace Misaki.HighPerformance.LowLevel.Collections;
|
|||||||
public unsafe struct UnsafeQueue<T> : IUnsafeCollection<T>
|
public unsafe struct UnsafeQueue<T> : IUnsafeCollection<T>
|
||||||
where T : unmanaged
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
public struct Enumerator : IEnumerator<T>
|
public ref struct Enumerator
|
||||||
{
|
{
|
||||||
private readonly UnsafeQueue<T>* _collection;
|
private readonly ref UnsafeQueue<T> _collection;
|
||||||
private int _currentIndex;
|
private int _currentIndex;
|
||||||
|
|
||||||
// We assume _currentIndex will always be in range when accessed.
|
// We assume _currentIndex will always be in range when accessed.
|
||||||
public readonly ref T Current => ref _collection->_array[(_collection->_offset + _currentIndex) % _collection->Capacity];
|
public readonly ref T Current => ref _collection._array[(_collection._offset + _currentIndex) % _collection.Capacity];
|
||||||
readonly T IEnumerator<T>.Current => Current;
|
|
||||||
readonly object IEnumerator.Current => Current;
|
|
||||||
|
|
||||||
public Enumerator(UnsafeQueue<T>* collection)
|
public Enumerator(ref UnsafeQueue<T> collection)
|
||||||
{
|
{
|
||||||
_collection = collection;
|
_collection = ref collection;
|
||||||
_currentIndex = -1;
|
_currentIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,17 +32,13 @@ public unsafe struct UnsafeQueue<T> : IUnsafeCollection<T>
|
|||||||
public bool MoveNext()
|
public bool MoveNext()
|
||||||
{
|
{
|
||||||
_currentIndex++;
|
_currentIndex++;
|
||||||
return _currentIndex < _collection->_count;
|
return _currentIndex < _collection._count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
_currentIndex = -1;
|
_currentIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private UnsafeArray<T> _array;
|
private UnsafeArray<T> _array;
|
||||||
@@ -62,21 +57,6 @@ public unsafe struct UnsafeQueue<T> : IUnsafeCollection<T>
|
|||||||
set => _array[index] = value;
|
set => _array[index] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumerator GetEnumerator()
|
|
||||||
{
|
|
||||||
return new((UnsafeQueue<T>*)UnsafeUtility.AddressOf(ref this));
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invalid constructor. Use <see cref="UnsafeQueue(int, Allocator, AllocationOption)"/> or <see cref="UnsafeQueue(int, AllocationHandle, AllocationOption)"/> instead."/>
|
/// Invalid constructor. Use <see cref="UnsafeQueue(int, Allocator, AllocationOption)"/> or <see cref="UnsafeQueue(int, AllocationHandle, AllocationOption)"/> instead."/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -97,6 +77,13 @@ public unsafe struct UnsafeQueue<T> : IUnsafeCollection<T>
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[UnscopedRef]
|
||||||
|
public Enumerator GetEnumerator()
|
||||||
|
{
|
||||||
|
return new Enumerator(ref this);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a reference to the item at the front of the queue without removing it.
|
/// Returns a reference to the item at the front of the queue without removing it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Misaki.HighPerformance.LowLevel.Collections.Contracts;
|
|||||||
using Misaki.HighPerformance.LowLevel.Utilities;
|
using Misaki.HighPerformance.LowLevel.Utilities;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.LowLevel.Collections;
|
namespace Misaki.HighPerformance.LowLevel.Collections;
|
||||||
@@ -42,24 +43,22 @@ internal class UnsafeSlotMapDebugView<T>
|
|||||||
public unsafe struct UnsafeSlotMap<T> : IUnsafeCollection<T>
|
public unsafe struct UnsafeSlotMap<T> : IUnsafeCollection<T>
|
||||||
where T : unmanaged
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
public struct Enumerator : IEnumerator<T>
|
public ref struct Enumerator
|
||||||
{
|
{
|
||||||
private readonly UnsafeSlotMap<T>* _collection;
|
private ref UnsafeSlotMap<T> _collection;
|
||||||
private int _currentIndex;
|
private int _currentIndex;
|
||||||
|
|
||||||
public readonly ref T Current => ref _collection->_data[_currentIndex];
|
public readonly ref T Current => ref _collection._data[_currentIndex];
|
||||||
readonly T IEnumerator<T>.Current => Current;
|
|
||||||
readonly object? IEnumerator.Current => Current;
|
|
||||||
|
|
||||||
public Enumerator(UnsafeSlotMap<T>* collection)
|
public Enumerator(ref UnsafeSlotMap<T> collection)
|
||||||
{
|
{
|
||||||
_collection = collection;
|
_collection = ref collection;
|
||||||
_currentIndex = -1;
|
_currentIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool MoveNext()
|
public bool MoveNext()
|
||||||
{
|
{
|
||||||
_currentIndex = _collection->_validBits.NextSetBit(_currentIndex + 1);
|
_currentIndex = _collection._validBits.NextSetBit(_currentIndex + 1);
|
||||||
return _currentIndex != -1;
|
return _currentIndex != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,10 +66,6 @@ public unsafe struct UnsafeSlotMap<T> : IUnsafeCollection<T>
|
|||||||
{
|
{
|
||||||
_currentIndex = -1;
|
_currentIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private UnsafeArray<T> _data;
|
private UnsafeArray<T> _data;
|
||||||
@@ -86,21 +81,6 @@ public unsafe struct UnsafeSlotMap<T> : IUnsafeCollection<T>
|
|||||||
|
|
||||||
public readonly bool IsCreated => _data.IsCreated && _generations.IsCreated && _freeSlots.IsCreated && _validBits.IsCreated;
|
public readonly bool IsCreated => _data.IsCreated && _generations.IsCreated && _freeSlots.IsCreated && _validBits.IsCreated;
|
||||||
|
|
||||||
public Enumerator GetEnumerator()
|
|
||||||
{
|
|
||||||
return new((UnsafeSlotMap<T>*)UnsafeUtility.AddressOf(ref this));
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invalid constructor. Use <see cref="UnsafeSlotMap(int, Allocator, AllocationOption)"/> or <see cref="UnsafeSlotMap(int, AllocationHandle, AllocationOption)"/> instead."/>
|
/// Invalid constructor. Use <see cref="UnsafeSlotMap(int, Allocator, AllocationOption)"/> or <see cref="UnsafeSlotMap(int, AllocationHandle, AllocationOption)"/> instead."/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -151,6 +131,13 @@ public unsafe struct UnsafeSlotMap<T> : IUnsafeCollection<T>
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[UnscopedRef]
|
||||||
|
public Enumerator GetEnumerator()
|
||||||
|
{
|
||||||
|
return new Enumerator(ref this);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds the specified item to the collection and returns the index of the slot where it was stored.
|
/// Adds the specified item to the collection and returns the index of the slot where it was stored.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -328,7 +315,7 @@ public unsafe struct UnsafeSlotMap<T> : IUnsafeCollection<T>
|
|||||||
|
|
||||||
public readonly void* GetUnsafePtr()
|
public readonly void* GetUnsafePtr()
|
||||||
{
|
{
|
||||||
return (T*)_data.GetUnsafePtr() + 1;
|
return (T*)_data.GetUnsafePtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Misaki.HighPerformance.LowLevel.Collections.Contracts;
|
|||||||
using Misaki.HighPerformance.LowLevel.Utilities;
|
using Misaki.HighPerformance.LowLevel.Utilities;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.LowLevel.Collections;
|
namespace Misaki.HighPerformance.LowLevel.Collections;
|
||||||
@@ -44,35 +45,29 @@ internal class ConcurrentSparseSetDebugView<T>
|
|||||||
public unsafe struct UnsafeSparseSet<T> : IUnsafeCollection<T>
|
public unsafe struct UnsafeSparseSet<T> : IUnsafeCollection<T>
|
||||||
where T : unmanaged
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
public struct Enumerator : IEnumerator<T>
|
public ref struct Enumerator
|
||||||
{
|
{
|
||||||
private readonly UnsafeSparseSet<T>* _collection;
|
private ref UnsafeSparseSet<T> _collection;
|
||||||
private int _currentIndex;
|
private int _currentIndex;
|
||||||
|
|
||||||
public readonly ref T Current => ref _collection->_dense[_currentIndex];
|
public readonly ref T Current => ref _collection._dense[_currentIndex];
|
||||||
readonly T IEnumerator<T>.Current => Current;
|
|
||||||
readonly object IEnumerator.Current => Current;
|
|
||||||
|
|
||||||
public Enumerator(UnsafeSparseSet<T>* collection)
|
public Enumerator(ref UnsafeSparseSet<T> collection)
|
||||||
{
|
{
|
||||||
_collection = collection;
|
_collection = ref collection;
|
||||||
_currentIndex = -1;
|
_currentIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool MoveNext()
|
public bool MoveNext()
|
||||||
{
|
{
|
||||||
_currentIndex++;
|
_currentIndex++;
|
||||||
return _currentIndex < _collection->_count;
|
return _currentIndex < _collection._count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
_currentIndex = -1;
|
_currentIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private UnsafeArray<T> _dense;
|
private UnsafeArray<T> _dense;
|
||||||
@@ -89,26 +84,11 @@ public unsafe struct UnsafeSparseSet<T> : IUnsafeCollection<T>
|
|||||||
public readonly int Capacity => _capacity;
|
public readonly int Capacity => _capacity;
|
||||||
public readonly bool IsCreated => _dense.IsCreated && _sparse.IsCreated && _reverse.IsCreated;
|
public readonly bool IsCreated => _dense.IsCreated && _sparse.IsCreated && _reverse.IsCreated;
|
||||||
|
|
||||||
public Enumerator GetEnumerator()
|
|
||||||
{
|
|
||||||
return new((UnsafeSparseSet<T>*)UnsafeUtility.AddressOf(ref this));
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs an UnsafeSparseSet with a default size of 1 and uses the Persistent allocator.
|
/// Constructs an UnsafeSparseSet with a default size of 1 and uses the Persistent allocator.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public UnsafeSparseSet()
|
public UnsafeSparseSet()
|
||||||
: this(1, Allocator.Persistent)
|
: this(0, Allocator.Invalid)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,6 +144,13 @@ public unsafe struct UnsafeSparseSet<T> : IUnsafeCollection<T>
|
|||||||
return ref _dense[_sparse[sparseIndex]];
|
return ref _dense[_sparse[sparseIndex]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[UnscopedRef]
|
||||||
|
public Enumerator GetEnumerator()
|
||||||
|
{
|
||||||
|
return new Enumerator(ref this);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a value to the sparse set and returns a unique sparse index for the value.
|
/// Adds a value to the sparse set and returns a unique sparse index for the value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Misaki.HighPerformance.LowLevel.Collections.Contracts;
|
|||||||
using Misaki.HighPerformance.LowLevel.Utilities;
|
using Misaki.HighPerformance.LowLevel.Utilities;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.LowLevel.Collections;
|
namespace Misaki.HighPerformance.LowLevel.Collections;
|
||||||
@@ -42,19 +43,17 @@ internal class UnsafeStackDebugView<T>
|
|||||||
public unsafe struct UnsafeStack<T> : IUnsafeCollection<T>
|
public unsafe struct UnsafeStack<T> : IUnsafeCollection<T>
|
||||||
where T : unmanaged
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
public struct Enumerator : IEnumerator<T>
|
public ref struct Enumerator
|
||||||
{
|
{
|
||||||
private readonly UnsafeStack<T>* _collection;
|
private readonly ref UnsafeStack<T> _collection;
|
||||||
private int _index;
|
private int _index;
|
||||||
|
|
||||||
public readonly ref T Current => ref _collection->_array[_index];
|
public readonly ref T Current => ref _collection._array[_index];
|
||||||
readonly T IEnumerator<T>.Current => Current;
|
|
||||||
readonly object IEnumerator.Current => Current;
|
|
||||||
|
|
||||||
public Enumerator(UnsafeStack<T>* collection)
|
public Enumerator(ref UnsafeStack<T> collection)
|
||||||
{
|
{
|
||||||
_collection = collection;
|
_collection = ref collection;
|
||||||
_index = collection->Count;
|
_index = collection.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -66,11 +65,7 @@ public unsafe struct UnsafeStack<T> : IUnsafeCollection<T>
|
|||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
_index = _collection->Count;
|
_index = _collection.Count;
|
||||||
}
|
|
||||||
|
|
||||||
public readonly void Dispose()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,21 +76,6 @@ public unsafe struct UnsafeStack<T> : IUnsafeCollection<T>
|
|||||||
public readonly int Capacity => _array.Count;
|
public readonly int Capacity => _array.Count;
|
||||||
public readonly bool IsCreated => _array.IsCreated;
|
public readonly bool IsCreated => _array.IsCreated;
|
||||||
|
|
||||||
public Enumerator GetEnumerator()
|
|
||||||
{
|
|
||||||
return new((UnsafeStack<T>*)UnsafeUtility.AddressOf(ref this));
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invalid constructor, use <see cref="UnsafeStack(int, Allocator, AllocationOption)"/> or <see cref="UnsafeStack(int, AllocationHandle, AllocationOption)"/> instead.
|
/// Invalid constructor, use <see cref="UnsafeStack(int, Allocator, AllocationOption)"/> or <see cref="UnsafeStack(int, AllocationHandle, AllocationOption)"/> instead.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -127,6 +107,13 @@ public unsafe struct UnsafeStack<T> : IUnsafeCollection<T>
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[UnscopedRef]
|
||||||
|
public Enumerator GetEnumerator()
|
||||||
|
{
|
||||||
|
return new(ref this);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds an element to the top of the stack.
|
/// Adds an element to the top of the stack.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user