namespace Theater_ECS.Internal.Containers; using System; using System.Collections; class PagedSparseSet { public const uint32 PageSize = 4096; private List> _sparse = new .()~ DeleteContainerAndItems!(_); private List _packed = new .() ~ delete _; private UList _packedEntities ~ delete _; private function void(void* data) _deallocationFunction = null; public this(int_cosize size) { _packedEntities = new .(size); } public bool Contains(Entity e) { return _sparse[e.Index/PageSize][e.Index % PageSize] != Entity.Null; } public void Add(Entity e, void* toAdd) { EnsureLoadedPage(e.Index/PageSize); _packed.Add(e); _packedEntities.Add(toAdd); _sparse[e.Index/PageSize][e.Index % PageSize] = (.)_packed.Count-1; } public bool Remove(Entity e, bool cleanup = false) { EnsurePage(e.Index/PageSize); if(_sparse[e.Index/PageSize] == null) return false; if(_deallocationFunction != null && !cleanup) _deallocationFunction(_packedEntities[(.)(_sparse[e.Index/PageSize][e.Index % PageSize].Index)]); let toRm = _packed[_sparse[e.Index/PageSize][e.Index % PageSize].Index]; let b = _packed.Back; _packed[_sparse[e.Index/PageSize][e.Index % PageSize].Index] = b; _packed.Back = toRm; _sparse[b.Index/PageSize][b.Index % PageSize] = Entity(e.Index, b.Version); _sparse[e.Index/PageSize][e.Index % PageSize] = Entity.Null; _packed.PopBack(); return true; } [Inline, Unchecked] public void* Get(Entity e) { return _packedEntities[(.)(_sparse[e.Index/PageSize][e.Index % PageSize].Index)]; } public Span GetAll() { return _packed; } public int_cosize Count() => (.)_packed.Count; ///Ensure that a page exist and is loaded public void EnsureLoadedPage(uint32 page) { EnsurePage(page); if(_sparse[page] == null) { _sparse[page] = new List(PageSize); _sparse[page].[Friend]Count = 4096; _sparse[page].SetAll(Entity.Null); } } ///Ensure that a page exists, it might be null though private void EnsurePage(uint32 page) { while(_sparse.Count < page+1) _sparse.Add(null); } }