From 61845d752a00c1fdd10b1b1cc34d9f4d266ef475 Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Sun, 22 Mar 2020 17:03:18 -0700 Subject: [PATCH] contiguous component storage --- .../Collections/TypedComponentStore.cs | 61 +++++++++++++------ 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/encompass-cs/Collections/TypedComponentStore.cs b/encompass-cs/Collections/TypedComponentStore.cs index 536b536..9cb2788 100644 --- a/encompass-cs/Collections/TypedComponentStore.cs +++ b/encompass-cs/Collections/TypedComponentStore.cs @@ -15,17 +15,18 @@ namespace Encompass internal class TypedComponentStore : TypedComponentStore where TComponent : struct { - private readonly Dictionary _indices = new Dictionary(512); - private readonly Dictionary _priorities = new Dictionary(512); - private readonly TComponent[] _components = new TComponent[512]; // TODO: allow specify size - private readonly IDManager _idManager = new IDManager(); + private int _nextID = 0; + private readonly Dictionary _entityIDToStorageIndex = new Dictionary(128); + private readonly Dictionary _storageIndexToEntityID = new Dictionary(128); + private readonly Dictionary _priorities = new Dictionary(128); + private TComponent[] _components = new TComponent[128]; - public override int Count { get => _indices.Count; } + public override int Count { get => _entityIDToStorageIndex.Count; } public ref TComponent Get(int entityID) { - if (!_indices.ContainsKey(entityID)) { throw new Exceptions.NoComponentOfTypeOnEntityException("No component of type {0} exists on Entity with ID {1}", typeof(TComponent), entityID); } - return ref _components[_indices[entityID]]; + if (!_entityIDToStorageIndex.ContainsKey(entityID)) { throw new Exceptions.NoComponentOfTypeOnEntityException("No component of type {0} exists on Entity with ID {1}", typeof(TComponent), entityID); } + return ref _components[_entityIDToStorageIndex[entityID]]; } public void Set(int entityID, in TComponent component) @@ -47,12 +48,18 @@ namespace Encompass private void InternalSet(int entityID, in TComponent component) { - if (!_indices.ContainsKey(entityID)) + if (!_entityIDToStorageIndex.ContainsKey(entityID)) { - _indices[entityID] = _idManager.NextID(); + var index = _nextID++; + if (index >= _components.Length) + { + System.Array.Resize(ref _components, _components.Length * 2); + } + _entityIDToStorageIndex[entityID] = index; + _storageIndexToEntityID[index] = entityID; } - _components[_indices[entityID]] = component; + _components[_entityIDToStorageIndex[entityID]] = component; } public override bool Remove(int entityID, int priority) @@ -69,26 +76,40 @@ namespace Encompass public override void ForceRemove(int entityID) { - if (_indices.ContainsKey(entityID)) + if (_entityIDToStorageIndex.ContainsKey(entityID)) { - _idManager.Free(_indices[entityID]); - _indices.Remove(entityID); + var storageIndex = _entityIDToStorageIndex[entityID]; + _entityIDToStorageIndex.Remove(entityID); + _storageIndexToEntityID.Remove(storageIndex); _priorities.Remove(entityID); + + // move a component into the hole to maintain contiguous memory + if (_nextID > 1 && storageIndex != _nextID - 1) + { + var lastStorageIndex = _nextID - 1; + var lastEntityID = _storageIndexToEntityID[lastStorageIndex]; + _storageIndexToEntityID.Remove(lastStorageIndex); + + _entityIDToStorageIndex[lastEntityID] = storageIndex; + _storageIndexToEntityID[storageIndex] = lastEntityID; + _components[storageIndex] = _components[lastStorageIndex]; + + } + + _nextID--; } } public override bool Has(int entityID) { - return _indices.ContainsKey(entityID); + return _entityIDToStorageIndex.ContainsKey(entityID); } public override void Clear() { - foreach (var mappedID in _indices.Values) - { - _idManager.Free(mappedID); - } - _indices.Clear(); + _nextID = 0; + _entityIDToStorageIndex.Clear(); + _storageIndexToEntityID.Clear(); _priorities.Clear(); } @@ -99,7 +120,7 @@ namespace Encompass public IEnumerable<(TComponent, int)> All() { - foreach (var kvp in _indices) + foreach (var kvp in _entityIDToStorageIndex) { yield return (_components[kvp.Value], kvp.Key); }