using System.Collections;
using System.Collections.Generic;
namespace AcDream.Core.Physics;
///
/// Ordered, deduped cell-id collection — a faithful model of retail's CELLARRAY
/// (CELLARRAY::add_cell @ acclient_2013_pseudo_c.txt:701036: linear
/// dedup by cell_id, append at the END, insertion order preserved). The order is
/// load-bearing for CObjCell::find_cell_list's current-cell-first,
/// interior-wins pick (pc:308742) — the current cell is added at index 0 and the
/// pick iterates in order, so the current cell wins a boundary straddle and the
/// membership does not ping-pong (the R1 flap fix). Replaces the unordered
/// the candidate build used to use.
///
/// Implements (so the candidate-building
/// helpers can take it where they used to take HashSet<uint>) and
/// (so it satisfies the
/// out IReadOnlyCollection<uint> on FindCellSet and the
/// CheckOtherCells / diagnostics consumers). Enumeration is always
/// insertion order.
///
public sealed class CellArray : ICollection, IReadOnlyCollection
{
private readonly List _order = new();
private readonly HashSet _seen = new();
public int Count => _order.Count;
public bool IsReadOnly => false;
/// Ordered cell ids; index 0 is the cell added first (the current cell).
public IReadOnlyList OrderedIds => _order;
/// Append iff not already present (retail add_cell dedup).
public void Add(uint id)
{
if (_seen.Add(id))
_order.Add(id);
}
public bool Contains(uint id) => _seen.Contains(id);
public void Clear() { _order.Clear(); _seen.Clear(); }
public bool Remove(uint id)
{
if (!_seen.Remove(id)) return false;
_order.Remove(id);
return true;
}
public void CopyTo(uint[] array, int arrayIndex) => _order.CopyTo(array, arrayIndex);
public IEnumerator GetEnumerator() => _order.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _order.GetEnumerator();
}