49 lines
1.4 KiB
C#
49 lines
1.4 KiB
C#
|
|
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;
|
||
|
|
}
|
||
|
|
|
||
|
|
public IEnumerator<Entity> GetEnumerator() => _order.GetEnumerator();
|
||
|
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||
|
|
}
|