using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace MoonTools.ECS.Collections; public unsafe class IndexableSet : IDisposable where T : unmanaged { private Dictionary Indices; private T* Array; public int Count { get; private set; } private int Capacity; private bool IsDisposed; public Span AsSpan() => new Span(Array, Count); public ReverseSpanEnumerator GetEnumerator() => new ReverseSpanEnumerator(new Span(Array, Count)); public IndexableSet(int capacity = 32) { this.Capacity = capacity; Count = 0; Indices = new Dictionary(capacity); Array = (T*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf())); } public T this[int i] => Array[i]; public bool Contains(T element) { return Indices.ContainsKey(element); } public bool Add(T element) { if (!Contains(element)) { Indices.Add(element, Count); if (Count >= Capacity) { Capacity *= 2; Array = (T*) NativeMemory.Realloc(Array, (nuint) (Capacity * Unsafe.SizeOf())); } Array[Count] = element; Count += 1; return true; } return false; } public bool Remove(T element) { if (!Contains(element)) { return false; } var index = Indices[element]; for (var i = index; i < Count - 1; i += 1) { Array[i] = Array[i + 1]; Indices[Array[i]] = i; } Indices.Remove(element); Count -= 1; return true; } public void Clear() { Indices.Clear(); Count = 0; } protected virtual void Dispose(bool disposing) { if (!IsDisposed) { NativeMemory.Free(Array); Array = null; IsDisposed = true; } } ~IndexableSet() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method Dispose(disposing: false); } public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method Dispose(disposing: true); GC.SuppressFinalize(this); } }