oecs-sharp/OECS/OrderedEntitySet.cs

64 lines
1.8 KiB
C#
Raw Normal View History

using System.Collections;
namespace OECS;
/// <summary>
/// An insertion-ordered set of entities that supports O(1) Add, Remove, and Contains
/// while iterating in insertion order. Drop-in for cases where both
/// stable ordering and fast membership checks are needed.
///
/// Not thread-safe.
/// </summary>
internal sealed class OrderedEntitySet : IReadOnlyCollection<Entity>
{
// Entities are stored in a packed list; a secondary dictionary maps
// each entity to its index for O(1) removal via swap-with-last.
private readonly List<Entity> _order = new();
private readonly Dictionary<Entity, int> _index = new();
public int Count => _order.Count;
public bool Add(Entity entity)
{
if (_index.ContainsKey(entity))
return false;
_index[entity] = _order.Count;
_order.Add(entity);
return true;
}
public bool Remove(Entity entity)
{
if (!_index.Remove(entity, out var idx))
return false;
int lastIdx = _order.Count - 1;
if (idx < lastIdx)
{
var last = _order[lastIdx];
_order[idx] = last;
_index[last] = idx;
}
_order.RemoveAt(lastIdx);
return true;
}
/// <summary>
/// Reorders the set to match the given entity order.
/// The provided list must contain exactly the same entities as the set.
/// </summary>
public void Reorder(IReadOnlyList<Entity> ordered)
{
_order.Clear();
_index.Clear();
for (int i = 0; i < ordered.Count; i++)
{
_order.Add(ordered[i]);
_index[ordered[i]] = i;
}
}
public IEnumerator<Entity> GetEnumerator() => _order.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}