From 22d873ed38d5aa7deea8b68b96296d17b81e6456 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Mon, 29 Jan 2024 17:40:38 +0800 Subject: [PATCH] Update --- src/Collections/EcsJoin.cs | 409 ++++++++++++++++++ src/EcsArc.cs | 209 +++++---- src/EcsJoinGroup_OLD.cs | 68 --- src/{WorldGraph.cs => EcsWorldGraph.cs} | 23 +- src/Utils/BasketList.cs | 135 +++--- src/Utils/EcsJoinGroup.cs | 242 ----------- src/Utils/IdsLinkedList.cs | 396 ----------------- src/Utils/IdsLinkedList.cs.meta | 11 - src/Utils/{Arc.cs => Rel.cs} | 31 +- .../{ArcEntityInfo.cs => RelEntityInfo.cs} | 14 +- src/Utils/SparseArray64.cs | 2 + 11 files changed, 653 insertions(+), 887 deletions(-) create mode 100644 src/Collections/EcsJoin.cs delete mode 100644 src/EcsJoinGroup_OLD.cs rename src/{WorldGraph.cs => EcsWorldGraph.cs} (88%) delete mode 100644 src/Utils/EcsJoinGroup.cs delete mode 100644 src/Utils/IdsLinkedList.cs delete mode 100644 src/Utils/IdsLinkedList.cs.meta rename src/Utils/{Arc.cs => Rel.cs} (56%) rename src/Utils/{ArcEntityInfo.cs => RelEntityInfo.cs} (77%) diff --git a/src/Collections/EcsJoin.cs b/src/Collections/EcsJoin.cs new file mode 100644 index 0000000..7ef68f7 --- /dev/null +++ b/src/Collections/EcsJoin.cs @@ -0,0 +1,409 @@ +using System; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using static DCFApixels.DragonECS.Relations.Utils.EcsJoin; + +namespace DCFApixels.DragonECS.Relations.Utils +{ + public readonly ref struct EcsReadonlyJoin + { + private readonly EcsJoin _source; + + #region Properties + public bool IsNull => _source == null; + public EcsArc Arc + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _source.Arc; } + } + public EcsWorld StartWorld + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _source.StartWorld; } + } + public EcsWorld EndWorld + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _source.EndWorld; } + } + public EcsArcWorld ArcWorld + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _source.ArcWorld; } + } + public int ArcWorldID + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _source.ArcWorldID; } + } + public bool IsLoopArc + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _source.IsLoopArc; } + } + public EnumerableArcEnd this[int startEntityID] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _source[startEntityID]; } + } + #endregion + + #region Constructors + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EcsReadonlyJoin(EcsJoin source) { _source = source; } + #endregion + + #region Methods + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Has(int relEntityID) { return _source.Has(relEntityID); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool HasStart(int startEntityID) { return _source.HasStart(startEntityID); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool HasEnd(int endEntityID) { return _source.HasEnd(endEntityID); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EnumerableArcEnd GetRelEnds(int startEntityID) { return _source.GetRelEnds(startEntityID); } + #endregion + + #region Internal + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal EcsJoin GetSource_Internal() => _source; + #endregion + + #region Other + public override string ToString() + { + return _source != null ? _source.ToString() : "NULL"; + } +#pragma warning disable CS0809 // Устаревший член переопределяет неустаревший член + [Obsolete("Equals() on EcsGroup will always throw an exception. Use the equality operator instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) => throw new NotSupportedException(); + [Obsolete("GetHashCode() on EcsGroup will always throw an exception.")] + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() => throw new NotSupportedException(); +#pragma warning restore CS0809 // Устаревший член переопределяет неустаревший член + #endregion + } + //[DebuggerTypeProxy(typeof(DebuggerProxy))] + public class EcsJoin + { + private readonly EcsArc _source; + private readonly bool _isLoop; + + private readonly BasketList _startBaskets; + private readonly BasketList _endBaskets; + private readonly RelInfo[] _relMapping; + + #region Properties + public EcsReadonlyJoin Readonly + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return new EcsReadonlyJoin(this); } + } + public EcsArc Arc + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _source; } + } + public EcsWorld StartWorld + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _source.StartWorld; } + } + public EcsWorld EndWorld + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _source.EndWorld; } + } + public EcsArcWorld ArcWorld + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _source.ArcWorld; } + } + public int ArcWorldID + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _source.ArcWorldID; } + } + public bool IsLoopArc + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _isLoop; } + } + + public EnumerableArcEnd this[int startEntityID] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return GetRelEnds(startEntityID); } + } + #endregion + + #region Constructors + public EcsJoin(EcsArc arc) + { + _source = arc; + _isLoop = arc.IsLoop; + + _startBaskets = new BasketList(); + if (_isLoop) + { + _endBaskets = _startBaskets; + } + else + { + _endBaskets = new BasketList(); + } + _relMapping = new RelInfo[arc.ArcWorld.Capacity]; + } + #endregion + + #region Add/Del + public void Add(int relEntityID) + { + var (startEntityID, endEntityID) = _source.GetRelInfo(relEntityID); + ref RelInfo arcInfo = ref _relMapping[relEntityID]; + + arcInfo.startNodeIndex = _startBaskets.AddToBasket(startEntityID, relEntityID); + if (_isLoop) + { + arcInfo.endNodeIndex = arcInfo.startNodeIndex; + } + else + { + arcInfo.endNodeIndex = _endBaskets.AddToBasket(endEntityID, relEntityID); + } + + //arcInfo.endNodeIndex = _endBaskets.AddToBasket(endEntityID, relEntityID); + //if (!_isLoop) + //{ + // arcInfo.startNodeIndex = _startBaskets.AddToBasket(startEntityID, relEntityID); + //} + //else + //{ + // arcInfo.startNodeIndex = arcInfo.endNodeIndex; + //} + } + public void Del(int relEntityID) + { + var (startEntityID, endEntityID) = _source.GetRelInfo(relEntityID); + ref RelInfo relInfo = ref _relMapping[relEntityID]; + _startBaskets.RemoveFromBasket(startEntityID, relInfo.startNodeIndex); + if (!_isLoop) + { + _startBaskets.RemoveFromBasket(endEntityID, relInfo.endNodeIndex); + } + } + public void DelStart(int startEntityID) + { + foreach (var relEntityID in _startBaskets.GetBasketIterator(startEntityID)) + { + var endEntityID = _source.GetRelEnd(relEntityID); + ref RelInfo relInfo = ref _relMapping[relEntityID]; + _endBaskets.RemoveFromBasket(endEntityID, relInfo.startNodeIndex); + } + _startBaskets.RemoveBasket(startEntityID); + } + public void DelEnd(int endEntityID) + { + foreach (var relEntityID in _endBaskets.GetBasketIterator(endEntityID)) + { + var startEntityID = _source.GetRelStart(relEntityID); + ref RelInfo relInfo = ref _relMapping[relEntityID]; + _startBaskets.RemoveFromBasket(startEntityID, relInfo.endNodeIndex); + } + _endBaskets.RemoveBasket(endEntityID); + } + #endregion + + #region Has + public bool Has(int relEntityID) + { + return _relMapping[relEntityID] != RelInfo.Empty; + } + public bool HasStart(int startEntityID) + { + return _startBaskets.GetBasketNodesCount(startEntityID) > 0; + } + public bool HasEnd(int endEntityID) + { + return _endBaskets.GetBasketNodesCount(endEntityID) > 0; + } + #endregion + + #region Clear + public void Clear() + { + _startBaskets.Clear(); + if (!_isLoop) + { + _endBaskets.Clear(); + } + } + #endregion + + #region GetRelEnds + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EnumerableArcEnd GetRelEnds(int startEntityID) + { + return new EnumerableArcEnd(_source, _startBaskets.GetBasketIterator(startEntityID).GetEnumerator()); + } + #endregion + + #region EnumerableArcEnd + public readonly ref struct EnumerableArcEnd //: IEnumerable + { + private readonly EcsArc _arc; + private readonly BasketList.BasketIterator.Enumerator _iterator; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal EnumerableArcEnd(EcsArc arc, BasketList.BasketIterator.Enumerator iterator) + { + _arc = arc; + _iterator = iterator; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Enumerator GetEnumerator() { return new Enumerator(_arc, _iterator); } + //IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + //IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + public ref struct Enumerator //: IEnumerator + { + private readonly EcsArc _arc; + private BasketList.BasketIterator.Enumerator _iterator; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(EcsArc arc, BasketList.BasketIterator.Enumerator iterator) + { + _arc = arc; + _iterator = iterator; + } + public RelEnd Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + int currentArc = _iterator.Current; + return new RelEnd(currentArc, _arc.GetRelEnd(currentArc)); + } + } + //object IEnumerator.Current => Current; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() { return _iterator.MoveNext(); } + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + //public void Reset() { } + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + //public void Dispose() { } + } + } + #endregion + + #region ArcInfo + private struct RelInfo : IEquatable + { + public readonly static RelInfo Empty = default; + public int startNodeIndex; + public int endNodeIndex; + + #region Object + public override bool Equals(object obj) + { + return obj is RelInfo && Equals((RelInfo)obj); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(RelInfo other) + { + return startNodeIndex == other.startNodeIndex && + endNodeIndex == other.endNodeIndex; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() + { + return ~startNodeIndex ^ endNodeIndex; + } + #endregion + + #region operators + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(RelInfo a, RelInfo b) => a.startNodeIndex == b.startNodeIndex && a.endNodeIndex == b.endNodeIndex; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(RelInfo a, RelInfo b) => a.startNodeIndex != b.startNodeIndex || a.endNodeIndex != b.endNodeIndex; + #endregion + } + #endregion + + #region Operators + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator EcsReadonlyJoin(EcsJoin a) => a.Readonly; + #endregion + + #region DebuggerProxy + //internal class DebuggerProxy + //{ + // private EcsJoinGroup _basket; + // + // public SpanDebugInfo[] HeadSpans => GetSpans(_basket._startList, _basket._startMapping); + // public SpanDebugInfo[] ValueSpans => GetSpans(_basket._endList, _basket._endMapping); + // + // private SpanDebugInfo[] GetSpans(IdsLinkedList list, SpanInfo[] mapping) + // { + // SpanDebugInfo[] result = new SpanDebugInfo[mapping.Length]; + // for (int i = 0; i < mapping.Length; i++) + // result[i] = new SpanDebugInfo(list, mapping[i].nodeIndex, mapping[i].count); + // return result; + // } + // public DebuggerProxy(EcsJoinGroup basket) + // { + // _basket = basket; + // } + // public struct SpanDebugInfo + // { + // private IdsLinkedList _list; + // public int index; + // public int count; + // public NodeDebugInfo[] Nodes + // { + // get + // { + // var result = new NodeDebugInfo[this.count]; + // var nodes = _list.Nodes; + // int index; + // int count = this.count; + // int next = this.index; + // int i = 0; + // while (true) + // { + // index = next; + // next = nodes[next].next; + // if (!(index > 0 && count-- > 0)) + // break; + // var node = nodes[index]; + // result[i] = new NodeDebugInfo(index, node.prev, node.next, node.value); + // i++; + // } + // return result; + // } + // } + // public SpanDebugInfo(IdsLinkedList list, int index, int count) + // { + // _list = list; + // this.index = index; + // this.count = count; + // } + // public override string ToString() => $"[{index}] {count}"; + // } + // public struct NodeDebugInfo + // { + // public int index; + // public int prev; + // public int next; + // public int value; + // public NodeDebugInfo(int index, int prev, int next, int value) + // { + // this.index = index; + // this.prev = prev; + // this.next = next; + // this.value = value; + // } + // public override string ToString() => $"[{index}] {prev}_{next} - {value}"; + // } + //} + #endregion + } +} diff --git a/src/EcsArc.cs b/src/EcsArc.cs index 3a3d9c4..a1206cf 100644 --- a/src/EcsArc.cs +++ b/src/EcsArc.cs @@ -1,12 +1,14 @@ using DCFApixels.DragonECS.Relations.Utils; +using Leopotam.EcsLite; using System; using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS { - //Edge world - //Relation entity - //Relation component + //Arc + //Arc world + //Rel entity + //Component public class EcsArc { private readonly EcsWorld _startWorld; @@ -19,15 +21,48 @@ namespace DCFApixels.DragonECS private readonly SparseArray64 _relationsMatrix = new SparseArray64(); - private EcsGroup _arcEntities; - private ArcEntityInfo[] _arkEntityInfos; //N * (N - 1) / 2 + private EcsJoin _joinEntities; + private EcsGroup _relEntities; + private RelEntityInfo[] _relEntityInfos; //N * (N - 1) / 2 + + private bool _isLoop; #region Properties - public EcsWorld StartWorld => _startWorld; - public EcsWorld EndWorld => _endWorld; - public EcsArcWorld ArcWorld => _arcWorld; - public EcsReadonlyGroup ArcEntities => _arcEntities.Readonly; - public bool IsLoop => _startWorld == _endWorld; + public EcsWorld StartWorld + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _startWorld; } + } + public EcsWorld EndWorld + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _endWorld; } + } + public EcsArcWorld ArcWorld + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _arcWorld; } + } + public int ArcWorldID + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _arcWorld.id; } + } + public EcsReadonlyGroup RelEntities + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _relEntities.Readonly; } + } + public EcsReadonlyJoin JoinEntities + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _joinEntities.Readonly; } + } + public bool IsLoop + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _isLoop; } + } #endregion #region Constructors @@ -37,44 +72,51 @@ namespace DCFApixels.DragonECS _endWorld = endWorld; _arcWorld = arcWorld; - _arkEntityInfos = new ArcEntityInfo[arcWorld.Capacity]; + _isLoop = startWorld == endWorld; - _startWorldHandler = new StartWorldHandler(this, _startWorld); + _relEntityInfos = new RelEntityInfo[arcWorld.Capacity]; + + _startWorldHandler = new StartWorldHandler(this); _arcWorldHandler = new ArcWorldHandler(this); - _endWorldHandler = new EndWorldHandler(this, _endWorld); + if (!_isLoop) + { + _endWorldHandler = new EndWorldHandler(this); + } - _startWorld.AddListener(worldEventListener: _startWorldHandler); - _startWorld.AddListener(entityEventListener: _startWorldHandler); - _arcWorld.AddListener(worldEventListener: _arcWorldHandler); - _arcWorld.AddListener(entityEventListener: _arcWorldHandler); - _endWorld.AddListener(worldEventListener: _endWorldHandler); - _endWorld.AddListener(entityEventListener: _endWorldHandler); + _relEntities = EcsGroup.New(_arcWorld); + _joinEntities = new EcsJoin(this); } #endregion #region New/Del - public int New(int startEntityID, int endEntityID) + public int NewRelation(int startEntityID, int endEntityID) { if (Has(startEntityID, endEntityID)) + { throw new EcsRelationException(); + } - int arcEntity = _arcWorld.NewEntity(); - _relationsMatrix.Add(startEntityID, endEntityID, arcEntity); + int relEntity = _arcWorld.NewEntity(); + _relationsMatrix.Add(startEntityID, endEntityID, relEntity); - _arkEntityInfos[arcEntity] = new ArcEntityInfo(startEntityID, endEntityID); - _arcEntities.Add(arcEntity); - return arcEntity; + _relEntityInfos[relEntity] = new RelEntityInfo(startEntityID, endEntityID); + _relEntities.Add(relEntity); + _joinEntities.Add(relEntity); + return relEntity; } - public void Del(int startEntityID, int endEntityID) + public void DelRelation(int startEntityID, int endEntityID) { - if (!_relationsMatrix.TryGetValue(startEntityID, endEntityID, out int arcEntity)) + if (!_relationsMatrix.TryGetValue(startEntityID, endEntityID, out int relEntity)) + { throw new EcsRelationException(); + } + _joinEntities.Del(relEntity); _relationsMatrix.Remove(startEntityID, endEntityID); - _arcWorld.DelEntity(arcEntity); + _arcWorld.DelEntity(relEntity); - _arkEntityInfos[arcEntity] = ArcEntityInfo.Empty; - _arcEntities.Remove(arcEntity); + _relEntityInfos[relEntity] = RelEntityInfo.Empty; + _relEntities.Remove(relEntity); } #endregion @@ -97,28 +139,28 @@ namespace DCFApixels.DragonECS #region ArcEntityInfo [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsArc(int arcEntityID) + public bool IsRel(int arcEntityID) { - if (arcEntityID <= 0 || arcEntityID >= _arkEntityInfos.Length) + if (arcEntityID <= 0 || arcEntityID >= _relEntityInfos.Length) return false; - return !_arkEntityInfos[arcEntityID].IsEmpty; + return !_relEntityInfos[arcEntityID].IsEmpty; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ArcEntityInfo GetArcInfo(int arcEntityID) + public RelEntityInfo GetRelInfo(int arcEntityID) { - if (arcEntityID <= 0 || arcEntityID >= _arkEntityInfos.Length) + if (arcEntityID <= 0 || arcEntityID >= _relEntityInfos.Length) throw new Exception(); - return _arkEntityInfos[arcEntityID]; + return _relEntityInfos[arcEntityID]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int GetArcStart(int arcEntityID) + public int GetRelStart(int arcEntityID) { - return GetArcInfo(arcEntityID).start; + return GetRelInfo(arcEntityID).start; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int GetArcEnd(int arcEntityID) + public int GetRelEnd(int arcEntityID) { - return GetArcInfo(arcEntityID).end; + return GetRelInfo(arcEntityID).end; } #endregion @@ -138,93 +180,84 @@ namespace DCFApixels.DragonECS private class ArcWorldHandler : IEcsWorldEventListener, IEcsEntityEventListener { private readonly EcsArc _arc; - public ArcWorldHandler(EcsArc arc) { _arc = arc; + EcsArcWorld arcWorld = arc.ArcWorld; + arcWorld.AddListener(worldEventListener: this); + arcWorld.AddListener(entityEventListener: this); } #region Callbacks - public void OnDelEntity(int entityID) - { - ref ArcEntityInfo rel = ref _arc._arkEntityInfos[entityID]; - if (_arc._relationsMatrix.Contains(rel.start, rel.end)) - { - _arc.Del(rel.start, rel.end); - } - } - public void OnNewEntity(int entityID) - { - } + public void OnDelEntity(int entityID) { } + public void OnNewEntity(int entityID) { } public void OnReleaseDelEntityBuffer(ReadOnlySpan buffer) { + foreach (var relEntityID in buffer) + { + ref RelEntityInfo rel = ref _arc._relEntityInfos[relEntityID]; + if (_arc._relationsMatrix.Contains(rel.start, rel.end)) + { + _arc.DelRelation(rel.start, rel.end); + } + } _arc._arcWorld.ReleaseDelEntityBuffer(buffer.Length); } - public void OnWorldDestroy() - { - } + public void OnWorldDestroy() { } public void OnWorldResize(int newSize) { - Array.Resize(ref _arc._arkEntityInfos, newSize); + Array.Resize(ref _arc._relEntityInfos, newSize); } #endregion } private class StartWorldHandler : IEcsWorldEventListener, IEcsEntityEventListener { private readonly EcsArc _arc; - private readonly EcsWorld _start; - - public StartWorldHandler(EcsArc arc, EcsWorld world) + public StartWorldHandler(EcsArc arc) { _arc = arc; - _start = world; + EcsWorld startWorld = arc.StartWorld; + startWorld.AddListener(worldEventListener: this); + startWorld.AddListener(entityEventListener: this); } #region Callbacks - public void OnDelEntity(int entityID) - { - } - public void OnNewEntity(int entityID) - { - } + public void OnDelEntity(int startEntityID) { } + public void OnNewEntity(int startEntityID) { } public void OnReleaseDelEntityBuffer(ReadOnlySpan buffer) { + foreach (var startEntityID in buffer) + { + _arc._joinEntities.DelStart(startEntityID); + } } - public void OnWorldDestroy() - { - } - public void OnWorldResize(int newSize) - { - } + public void OnWorldDestroy() { } + public void OnWorldResize(int newSize) { } #endregion } private class EndWorldHandler : IEcsWorldEventListener, IEcsEntityEventListener { private readonly EcsArc _arc; - private readonly EcsWorld _end; - - public EndWorldHandler(EcsArc arc, EcsWorld world) + public EndWorldHandler(EcsArc arc) { _arc = arc; - _end = world; + EcsWorld endWorld = arc.EndWorld; + endWorld.AddListener(worldEventListener: this); + endWorld.AddListener(entityEventListener: this); } #region Callbacks - public void OnDelEntity(int entityID) - { - } - public void OnNewEntity(int entityID) - { - } + public void OnDelEntity(int endEntityID) { } + public void OnNewEntity(int endEntityID) { } public void OnReleaseDelEntityBuffer(ReadOnlySpan buffer) { + foreach (var endEntityID in buffer) + { + _arc._joinEntities.DelEnd(endEntityID); + } } - public void OnWorldDestroy() - { - } - public void OnWorldResize(int newSize) - { - } + public void OnWorldDestroy() { } + public void OnWorldResize(int newSize) { } #endregion } #endregion diff --git a/src/EcsJoinGroup_OLD.cs b/src/EcsJoinGroup_OLD.cs deleted file mode 100644 index 930d54e..0000000 --- a/src/EcsJoinGroup_OLD.cs +++ /dev/null @@ -1,68 +0,0 @@ -using DCFApixels.DragonECS.Relations.Utils; - -namespace DCFApixels.DragonECS -{ - public class EcsJoinGroup_OLD - { - private EcsArc _source; - - private int[] _mapping; - private int[] _counts; - private IdsLinkedList _linkedList; - internal bool _isReleased = true; - - #region Properites - public EcsArc Edge => _source; - #endregion - - - #region Constrcutors/Dispose - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public static EcsJoinGroup New(EcsArcController edge) - //{ - // return edge.GetFreeGroup(); - //} - //internal EcsJoinGroup(EcsArcController edge, int denseCapacity = 64) - //{ - // _source = edge; - // _source.RegisterGroup(this); - // int capacity = edge.World.Capacity; - // - // _mapping = new int[capacity]; - // _counts = new int[capacity]; - //} - //public void Dispose() => _source.ReleaseGroup(this); - #endregion - - public void Add(int entityFrom, int entityTo) - { - ref int nodeIndex = ref _mapping[entityFrom]; - if (nodeIndex <= 0) - { - nodeIndex = _linkedList.Add(entityTo); - _counts[entityFrom] = 1; - } - else - { - _linkedList.InsertAfter(nodeIndex, entityTo); - _counts[entityFrom]++; - } - } - - public IdsLinkedList.Span GetEntitiesFor(int entity) - { - ref var nodeIndex = ref _mapping[entity]; - if (nodeIndex <= 0) - return _linkedList.EmptySpan(); - else - return _linkedList.GetSpan(nodeIndex, _counts[entity]); - } - - public void Clear() - { - _linkedList.Clear(); - for (int i = 0; i < _mapping.Length; i++) - _mapping[i] = 0; - } - } -} diff --git a/src/WorldGraph.cs b/src/EcsWorldGraph.cs similarity index 88% rename from src/WorldGraph.cs rename to src/EcsWorldGraph.cs index 2867a3b..1da01dc 100644 --- a/src/WorldGraph.cs +++ b/src/EcsWorldGraph.cs @@ -4,11 +4,12 @@ using System; namespace DCFApixels.DragonECS { - public static class WorldGraph + public static class EcsWorldGraph { private static readonly SparseArray64 _matrix = new SparseArray64(4); private static EcsArc[] _arcsMapping = new EcsArc[4]; + #region Register/Unregister private static EcsArc Register(EcsWorld startWorld, EcsWorld endWorld, EcsArcWorld arcWorld) { int startWorldID = startWorld.id; @@ -39,7 +40,19 @@ namespace DCFApixels.DragonECS _arcsMapping[arc.ArcWorld.id] = null; _matrix.Remove(startWorldID, endWorldID); } + #endregion + #region Get/Has +// private static EcsArc GetOrRigister(EcsWorld startWorld, EcsWorld otherWorld) +// { +//#if DEBUG +// if (!_matrix.Contains(startWorld.id, otherWorld.id)) +// { +// return Register(); +// } +//#endif +// return _matrix[startWorld.id, otherWorld.id]; +// } private static EcsArc Get(EcsWorld startWorld, EcsWorld otherWorld) { #if DEBUG @@ -52,9 +65,7 @@ namespace DCFApixels.DragonECS } private static bool Has(EcsWorld startWorld, EcsWorld endWorld) => Has(startWorld.id, endWorld.id); private static bool Has(int startWorldID, int endWorldID) => _matrix.Contains(startWorldID, endWorldID); - - - + #endregion #region Extension public static bool IsRegistered(this EcsArcWorld self) @@ -82,8 +93,8 @@ namespace DCFApixels.DragonECS - public static EcsArc SetLoopArc(this EcsWorld self) => SetArc(self, self); - public static EcsArc SetArc(this EcsWorld start, EcsWorld end) + public static EcsArc SetLoopArcAuto(this EcsWorld self) => SetArcAuto(self, self); + public static EcsArc SetArcAuto(this EcsWorld start, EcsWorld end) { if (start == null || end == null) { diff --git a/src/Utils/BasketList.cs b/src/Utils/BasketList.cs index 9915b3a..b9abbfa 100644 --- a/src/Utils/BasketList.cs +++ b/src/Utils/BasketList.cs @@ -1,13 +1,15 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Reflection; +using System.Diagnostics; +using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace DCFApixels.DragonECS { - public class BasketList + [DebuggerTypeProxy(typeof(DebuggerProxy))] + internal class BasketList { public const int RECYCLE = -1; public const int HEAD = 0; @@ -16,10 +18,6 @@ namespace DCFApixels.DragonECS private Node[] _nodes; private int _recycledListLast = -1; - private int _basketsCount = 0; - private int[] _recycledBuskets = new int[64]; - private int _recycledBusketsCount = 0; - #region Constructors public BasketList() : this(16) { } public BasketList(int capacity) @@ -86,6 +84,11 @@ namespace DCFApixels.DragonECS LinkToRecycled(newSize - 1, 1); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int GetBasketNodesCount(int basketIndex) + { + return _baskets[basketIndex].count; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -108,7 +111,7 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool RemoveFromBasketAt(int basketIndex, int nodeIndex) + public void RemoveFromBasket(int basketIndex, int nodeIndex) { #if DEBUG if (nodeIndex <= 0) @@ -126,11 +129,11 @@ namespace DCFApixels.DragonECS { basketInfo.nodeIndex = nextNode; } - return --basketInfo.count > 0; + basketInfo.count--; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int InsertToBasket(int basketIndex, int value) + public int AddToBasket(int basketIndex, int value) { ref BasketInfo basketInfo = ref _baskets[basketIndex]; int newNodeIndex = TakeRecycledNode(); @@ -273,6 +276,11 @@ namespace DCFApixels.DragonECS // return newBasketIndex; //} + public static void CreateCrossRef(int leftBasketIndex, int rightBasketIndex) + { + + } + #region Node [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)] @@ -306,86 +314,54 @@ namespace DCFApixels.DragonECS #endregion #region Basket - public Basket this[int basketIndex] + public BasketIterator this[int basketIndex] { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => GetBasket(basketIndex); + get => GetBasketIterator(basketIndex); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Basket GetBasket(int basketIndex) + public BasketIterator GetBasketIterator(int basketIndex) { if (_baskets.Length <= basketIndex) { int newSize = GetHighBitNumber((uint)basketIndex) << 1; Array.Resize(ref _baskets, newSize); } - return new Basket(this, basketIndex); + return new BasketIterator(this, basketIndex); } - public struct Basket : IEnumerable + public readonly struct BasketIterator : IEnumerable { private readonly BasketList _basketList; - public readonly int _basketIndex; - private int _count; - + private readonly int _basketIndex; public int Count { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _count; - } - public int BasketIndex - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _basketIndex; - } - public int StartNodeIndex - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _basketList._baskets[_basketIndex].nodeIndex; + get { return _basketList._baskets[_basketIndex].count; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Basket(BasketList basketList, int basketIndex) + public BasketIterator(BasketList basketList, int basketIndex) { _basketList = basketList; _basketIndex = basketIndex; - _count = _basketList._baskets[basketIndex].count; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int Add(int value) - { - _count++; - return _basketList.InsertToBasket(_basketIndex, value); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RemoveAt(int nodeIndex) - { -#if DEBUG - if (_count <= 0) - throw new Exception(); -#endif - _basketList.RemoveFromBasketAt(_basketIndex, nodeIndex); - _count--; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Enumerator GetEnumerator() => new Enumerator(this); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public struct Enumerator : IEnumerator { private readonly Node[] _nodes; private int _nodeIndex; - private int _nextNode; + private int _nextNodeIndex; private int _count; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Enumerator(Basket iterator) + public Enumerator(BasketIterator iterator) { ref BasketInfo basketInfo = ref iterator._basketList._baskets[iterator._basketIndex]; _nodes = iterator._basketList._nodes; _nodeIndex = -1; - _nextNode = basketInfo.nodeIndex; + _nextNodeIndex = basketInfo.nodeIndex; _count = basketInfo.count; } public int Current @@ -398,8 +374,8 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool MoveNext() { - _nodeIndex = _nextNode; - _nextNode = _nodes[_nextNode].next; + _nodeIndex = _nextNodeIndex; + _nextNodeIndex = _nodes[_nextNodeIndex].next; return _nodeIndex > 0 && _count-- > 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -409,5 +385,56 @@ namespace DCFApixels.DragonECS } } #endregion + + #region DebuggerProxy + private class DebuggerProxy + { + private BasketList _basketList; + public IEnumerable Baskets + { + get + { + List result = new List(); + for (int i = 0; i < _basketList._baskets.Length; i++) + { + if (_basketList._baskets[i].count > 0) + { + result.Add(new BasketIteratorDebbugerProxy(_basketList[i])); + } + } + return result; + } + } + public DebuggerProxy(BasketList basketList) + { + _basketList = basketList; + } + public struct BasketIteratorDebbugerProxy + { + private BasketIterator _iterrator; + public int Count => _iterrator.Count; + public IEnumerable RelEntities + { + get + { + List result = new List(); + foreach (var e in _iterrator) + { + result.Add(e); + } + return result; + } + } + public BasketIteratorDebbugerProxy(BasketIterator iterrator) + { + _iterrator = iterrator; + } + public override string ToString() + { + return $"count: {_iterrator.Count}"; + } + } + } + #endregion } } diff --git a/src/Utils/EcsJoinGroup.cs b/src/Utils/EcsJoinGroup.cs deleted file mode 100644 index b5468b8..0000000 --- a/src/Utils/EcsJoinGroup.cs +++ /dev/null @@ -1,242 +0,0 @@ -using System.Diagnostics; -using System.Runtime.CompilerServices; - -namespace DCFApixels.DragonECS.Relations.Utils -{ - [DebuggerTypeProxy(typeof(DebuggerProxy))] - internal class EcsJoinGroup - { - private EcsArc _arc; - private readonly bool _isLoop; - - private BasketList _startBaskets; - private BasketList _endBaskets; - private ArcInfo[] _arcMapping; - - public EcsJoinGroup(EcsArc arc) - { - _arc = arc; - _isLoop = arc.IsLoop; - - _startBaskets = new BasketList(); - if (_isLoop) - { - _endBaskets = _startBaskets; - } - else - { - _endBaskets = new BasketList(); - } - _arcMapping = new ArcInfo[arc.ArcWorld.Capacity]; - } - public void Clear() - { - _startBaskets.Clear(); - if (!_isLoop) - { - _endBaskets.Clear(); - } - } - public void Add(int arcEntityID) - { - var (startEntityID, endEntityID) = _arc.GetArcInfo(arcEntityID); - _startBaskets[startEntityID].Add(endEntityID); - _startBaskets[endEntityID].Add(startEntityID); - - - - - - - - - - - - - - var (startEntityID, endEntityID) = _arc.GetArcInfo(arcEntityID); - ArcInfo arcInfo = _arcMapping[arcEntityID]; - - ref var startSpan = ref _startMapping[startEntityID]; - if (startSpan.nodeIndex <= 0) - { - startSpan.nodeIndex = _startList.Add(endEntityID); - arcInfo.startNodeIndex = startSpan.nodeIndex; - } - else - { - arcInfo.startNodeIndex = _startList.InsertAfter(startSpan.nodeIndex, endEntityID); - } - startSpan.count++; - - ref var endSpan = ref _endMapping[endEntityID]; - if (endSpan.nodeIndex <= 0) - { - endSpan.nodeIndex = _endList.Add(startEntityID); - arcInfo.endNodeIndex = endSpan.nodeIndex; - } - else - { - arcInfo.endNodeIndex = _endList.InsertAfter(endSpan.nodeIndex, startEntityID); - } - endSpan.count++; - } - - public void Del(int arcEntityID) - { - var (startEntityID, endEntityID) = _arc.GetArcInfo(arcEntityID); - ref ArcInfo arcInfo = ref _arcMapping[arcEntityID]; - int nextIndex; - - ref var startSpan = ref _startMapping[startEntityID]; - nextIndex = _startList.RemoveIndexAndReturnNextIndex(arcInfo.startNodeIndex); - if (startSpan.nodeIndex == arcInfo.startNodeIndex) - { - startSpan.nodeIndex = nextIndex; - } - - if (!_isLoop) - { - ref var endSpan = ref _endMapping[endEntityID]; - nextIndex = _endList.RemoveIndexAndReturnNextIndex(arcInfo.endNodeIndex); ; - if (endSpan.nodeIndex == arcInfo.endNodeIndex) - { - endSpan.nodeIndex = nextIndex; - } - } - arcInfo = default; - } - public void DelEnd(int endEntityID) - { - DelPosInternal(_endMapping, _startList, _endList, endEntityID); - } - public void DelStart(int startEntityID) - { - DelPosInternal(_startMapping, _endList, _startList, startEntityID); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void DelPosInternal(SpanInfo[] endMapping, IdsLinkedList startList, IdsLinkedList endList, int posEntityID) - { - ref var endSpan = ref endMapping[posEntityID]; - if (endSpan.nodeIndex <= 0) - { - return; - } - foreach (var startNodeIndex in endList.GetSpan(endSpan.nodeIndex, endSpan.count)) - { - int indx = startList.RemoveIndexAndReturnNextIndex(startNodeIndex); - if (endSpan.nodeIndex == startNodeIndex) - { - endSpan.nodeIndex = indx; - } - } - endList.RemoveSpan(endSpan.nodeIndex, endSpan.count); - endSpan = SpanInfo.Empty; - } - - - public IdsLinkedList.Span GetSpanFor(int startEntityID) - { - ref var head = ref _startMapping[startEntityID]; - if (head.nodeIndex <= 0) - return _startList.EmptySpan(); - else - return _startList.GetSpan(head.nodeIndex, head.count); - } - public IdsLinkedList.LongSpan GetLongSpanFor(EcsWorld world, int startEntityID) - { - ref var head = ref _startMapping[startEntityID]; - if (head.nodeIndex <= 0) - return _startList.EmptyLongSpan(world); - else - return _startList.GetLongSpan(world, head.nodeIndex, head.count); - } - - private struct SpanInfo - { - public static readonly SpanInfo Empty = default; - public int nodeIndex; - public int count; - } - - private struct ArcInfo - { - public int startNodeIndex; - public int endNodeIndex; - } - - #region DebuggerProxy - internal class DebuggerProxy - { - private EcsJoinGroup _basket; - - public SpanDebugInfo[] HeadSpans => GetSpans(_basket._startList, _basket._startMapping); - public SpanDebugInfo[] ValueSpans => GetSpans(_basket._endList, _basket._endMapping); - - private SpanDebugInfo[] GetSpans(IdsLinkedList list, SpanInfo[] mapping) - { - SpanDebugInfo[] result = new SpanDebugInfo[mapping.Length]; - for (int i = 0; i < mapping.Length; i++) - result[i] = new SpanDebugInfo(list, mapping[i].nodeIndex, mapping[i].count); - return result; - } - public DebuggerProxy(EcsJoinGroup basket) - { - _basket = basket; - } - public struct SpanDebugInfo - { - private IdsLinkedList _list; - public int index; - public int count; - public NodeDebugInfo[] Nodes - { - get - { - var result = new NodeDebugInfo[this.count]; - var nodes = _list.Nodes; - int index; - int count = this.count; - int next = this.index; - int i = 0; - while (true) - { - index = next; - next = nodes[next].next; - if (!(index > 0 && count-- > 0)) - break; - var node = nodes[index]; - result[i] = new NodeDebugInfo(index, node.prev, node.next, node.value); - i++; - } - return result; - } - } - public SpanDebugInfo(IdsLinkedList list, int index, int count) - { - _list = list; - this.index = index; - this.count = count; - } - public override string ToString() => $"[{index}] {count}"; - } - public struct NodeDebugInfo - { - public int index; - public int prev; - public int next; - public int value; - public NodeDebugInfo(int index, int prev, int next, int value) - { - this.index = index; - this.prev = prev; - this.next = next; - this.value = value; - } - public override string ToString() => $"[{index}] {prev}_{next} - {value}"; - } - } - #endregion - } -} diff --git a/src/Utils/IdsLinkedList.cs b/src/Utils/IdsLinkedList.cs deleted file mode 100644 index 7c40095..0000000 --- a/src/Utils/IdsLinkedList.cs +++ /dev/null @@ -1,396 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace DCFApixels.DragonECS.Relations.Utils -{ - [DebuggerTypeProxy(typeof(DebuggerProxy))] - public class IdsLinkedList : IEnumerable - { - public const int Head = 0; - - private Node[] _nodes; - private int _count; - private int _lastNodeIndex; - - private int[] _recycledNodes = new int[4]; - private int _recycledNodesCount; - - #region Properties - public int Count - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _count; - } - public int Capacity - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _nodes.Length; - } - - public int Last - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _lastNodeIndex; - } - public ReadOnlySpan Nodes - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new ReadOnlySpan(_nodes); - } - #endregion - - #region Constructors - public IdsLinkedList(int capacity) - { - _nodes = new Node[capacity + 10]; - Clear(); - } - #endregion - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Clear() - { - for (int i = 0; i < _nodes.Length; i++) - _nodes[i].next = 0; - _lastNodeIndex = Head; - _count = 0; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Set(int nodeIndex, int value) - { - _nodes[nodeIndex].value = value; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int Get(int nodeIndex) - { - return _nodes[nodeIndex].value; - } - - /// Insert after - /// new node index - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int InsertAfter(int nodeIndex, int value) - { - if (++_count >= _nodes.Length) - { - Array.Resize(ref _nodes, _nodes.Length << 1); - } - int newNodeIndex = _recycledNodesCount > 0 ? _recycledNodes[--_recycledNodesCount] : _count; - - ref Node prevNode = ref _nodes[nodeIndex]; - ref Node nextNode = ref _nodes[prevNode.next]; - if (prevNode.next == 0) - { - _lastNodeIndex = newNodeIndex; - } - _nodes[newNodeIndex].Set(value, nextNode.prev, prevNode.next); - prevNode.next = newNodeIndex; - nextNode.prev = newNodeIndex; - - return newNodeIndex; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int InsertBefore(int nodeIndex, int value) - { - if (++_count >= _nodes.Length) - Array.Resize(ref _nodes, _nodes.Length << 1); - int newNodeIndex = _recycledNodesCount > 0 ? _recycledNodes[--_recycledNodesCount] : _count; - - ref Node nextNode = ref _nodes[nodeIndex]; - ref Node prevNode = ref _nodes[nextNode.prev]; - _nodes[newNodeIndex].Set(value, nextNode.prev, prevNode.next); - prevNode.next = newNodeIndex; - nextNode.prev = newNodeIndex; - - return newNodeIndex; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RemoveIndex(int nodeIndex) - { - if (nodeIndex <= 0) - throw new ArgumentOutOfRangeException(); - - ref var node = ref _nodes[nodeIndex]; - _nodes[node.next].prev = node.prev; - _nodes[node.prev].next = node.next; - - if (_recycledNodesCount >= _recycledNodes.Length) - Array.Resize(ref _recycledNodes, _recycledNodes.Length << 1); - _recycledNodes[_recycledNodesCount++] = nodeIndex; - _count--; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int RemoveIndexAndReturnNextIndex(int nodeIndex) - { - if (nodeIndex <= 0) - throw new ArgumentOutOfRangeException(); - - ref var node = ref _nodes[nodeIndex]; - int nextNode = node.next; - _nodes[node.next].prev = node.prev; - _nodes[node.prev].next = nextNode; - - if (_recycledNodesCount >= _recycledNodes.Length) - Array.Resize(ref _recycledNodes, _recycledNodes.Length << 1); - _recycledNodes[_recycledNodesCount++] = nodeIndex; - _count--; - - return nextNode; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RemoveSpan(int startNodeIndex, int count) - { - if (count <= 0) - return; - - int endNodeIndex = startNodeIndex; - - if (_recycledNodesCount >= _recycledNodes.Length) - Array.Resize(ref _recycledNodes, _recycledNodes.Length << 1); - _recycledNodes[_recycledNodesCount++] = startNodeIndex; - - for (int i = 1; i < count; i++) - { - endNodeIndex = _nodes[endNodeIndex].next; - if (endNodeIndex == 0) - throw new ArgumentOutOfRangeException(); - - if (_recycledNodesCount >= _recycledNodes.Length) - Array.Resize(ref _recycledNodes, _recycledNodes.Length << 1); - _recycledNodes[_recycledNodesCount++] = endNodeIndex; - } - - ref var startNode = ref _nodes[startNodeIndex]; - ref var endNode = ref _nodes[endNodeIndex]; - - _nodes[endNode.next].prev = startNode.prev; - _nodes[startNode.prev].next = endNode.next; - - _count -= count; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int Add(int id) - { - return InsertAfter(_lastNodeIndex, id); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref readonly Node GetNode(int nodeIndex) - { - return ref _nodes[nodeIndex]; - } - - #region Span/Enumerator - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public SpanEnumerator GetEnumerator() => new SpanEnumerator(_nodes, _nodes[Head].next, _count); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span GetSpan(int startNodeIndex, int count) => new Span(this, startNodeIndex, count); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span EmptySpan() => new Span(this, 0, 0); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public LongSpan GetLongs(EcsWorld world) => new LongSpan(world, this, _nodes[Head].next, _count); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public LongSpan GetLongSpan(EcsWorld world, int startNodeIndex, int count) => new LongSpan(world, this, startNodeIndex, count); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public LongSpan EmptyLongSpan(EcsWorld world) => new LongSpan(world, this, 0, 0); - - public readonly ref struct Span - { - private readonly IdsLinkedList _source; - private readonly int _startNodeIndex; - private readonly int _count; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span(IdsLinkedList source, int startNodeIndex, int count) - { - _source = source; - _startNodeIndex = startNodeIndex; - _count = count; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public SpanEnumerator GetEnumerator() => new SpanEnumerator(_source._nodes, _startNodeIndex, _count); - } - public struct SpanEnumerator : IEnumerator - { - private readonly Node[] _nodes; - private int _count; - private int _index; - private int _next; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public SpanEnumerator(Node[] nodes, int startIndex, int count) - { - _nodes = nodes; - _index = -1; - _count = count; - _next = startIndex; - } - public int Current - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return _nodes[_index].value; - } - } - - object IEnumerator.Current => Current; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() - { - _index = _next; - _next = _nodes[_next].next; - return _index > 0 && _count-- > 0; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - void IDisposable.Dispose() { } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - void IEnumerator.Reset() - { - _index = -1; - _next = Head; - } - } - public readonly ref struct LongSpan - { - private readonly EcsWorld _world; - private readonly IdsLinkedList _source; - private readonly int _startNodeIndex; - private readonly int _count; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public LongSpan(EcsWorld world, IdsLinkedList source, int startNodeIndex, int count) - { - _world = world; - _source = source; - _startNodeIndex = startNodeIndex; - _count = count; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public LongSpanEnumerator GetEnumerator() => new LongSpanEnumerator(_world, _source._nodes, _startNodeIndex, _count); - } - public struct LongSpanEnumerator : IEnumerator - { - private EcsWorld _world; - private readonly Node[] _nodes; - private int _count; - private int _index; - private int _next; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public LongSpanEnumerator(EcsWorld world, Node[] nodes, int startIndex, int count) - { - _world = world; - _nodes = nodes; - _index = -1; - _count = count; - _next = startIndex; - } - public entlong Current - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return _world.GetEntityLong(_nodes[_index].value); - } - } - - object IEnumerator.Current => Current; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() - { - _index = _next; - _next = _nodes[_next].next; - return _index > 0 && _count-- > 0; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - void IDisposable.Dispose() { } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - void IEnumerator.Reset() - { - _index = -1; - _next = Head; - } - } - #endregion - - #region Node - [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)] - public struct Node - { - public static readonly Node Empty = new Node() { value = 0, next = -1 }; - public int value; - /// next node index - public int next; - /// prev node index - public int prev; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Set(int value, int prev, int next) - { - this.value = value; - this.next = next; - this.prev = prev; - } - public override string ToString() => $"node({prev}<>{next} v:{value})"; - } - #endregion - - #region Debug - internal class DebuggerProxy - { - private IdsLinkedList list; - public NodeInfo[] Nodes - { - get - { - var result = new NodeInfo[list.Count]; - - Node[] nodes = list._nodes; - int index = -1; - int count = list._count; - int next = list._nodes[Head].next; - - int i = 0; - while (true) - { - index = next; - next = nodes[next].next; - if (!(index > 0 && count-- > 0)) - break; - ref var node = ref nodes[index]; - result[i] = new NodeInfo(index, node.prev, node.next, node.value); - i++; - } - return result; - } - } - public DebuggerProxy(IdsLinkedList list) - { - this.list = list; - } - - public struct NodeInfo - { - public int index; - public int prev; - public int next; - public int value; - public NodeInfo(int index, int prev, int next, int value) - { - this.index = index; - this.prev = prev; - this.next = next; - this.value = value; - } - public override string ToString() => $"[{index}] {prev}_{next} - {value}"; - } - } - #endregion - } -} diff --git a/src/Utils/IdsLinkedList.cs.meta b/src/Utils/IdsLinkedList.cs.meta deleted file mode 100644 index 62609f6..0000000 --- a/src/Utils/IdsLinkedList.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9d852affe1595eb4b9d8eb8dc6f28720 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/src/Utils/Arc.cs b/src/Utils/Rel.cs similarity index 56% rename from src/Utils/Arc.cs rename to src/Utils/Rel.cs index 321d04b..ae3e094 100644 --- a/src/Utils/Arc.cs +++ b/src/Utils/Rel.cs @@ -1,46 +1,47 @@ -using System.Runtime.CompilerServices; +using System; +using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS { - public readonly struct StartArcEnd + public readonly ref struct StartRelEnd { /// Start vertex entity ID. public readonly int start; - /// Arc entity ID. - public readonly int arc; + /// Relation entity ID. + public readonly int rel; /// End vertex entity ID. public readonly int end; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public StartArcEnd(int start, int arc, int end) + public StartRelEnd(int start, int rel, int end) { this.start = start; - this.arc = arc; + this.rel = rel; this.end = end; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Deconstruct(out int start, out int arc, out int end) + public void Deconstruct(out int start, out int rel, out int end) { start = this.start; - arc = this.arc; + rel = this.rel; end = this.end; } } - public readonly struct ArcEnd + public readonly ref struct RelEnd { - /// Arc entity ID. - public readonly int arc; + /// Relation entity ID. + public readonly int rel; /// End vertex entity ID. public readonly int end; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ArcEnd(int arc, int end) + public RelEnd(int rel, int end) { - this.arc = arc; + this.rel = rel; this.end = end; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Deconstruct(out int arc, out int end) + public void Deconstruct(out int rel, out int end) { - arc = this.arc; + rel = this.rel; end = this.end; } } diff --git a/src/Utils/ArcEntityInfo.cs b/src/Utils/RelEntityInfo.cs similarity index 77% rename from src/Utils/ArcEntityInfo.cs rename to src/Utils/RelEntityInfo.cs index 9b17b83..8cc3e68 100644 --- a/src/Utils/ArcEntityInfo.cs +++ b/src/Utils/RelEntityInfo.cs @@ -6,9 +6,9 @@ namespace DCFApixels.DragonECS { [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)] [Serializable] - public readonly struct ArcEntityInfo : IEquatable + public readonly struct RelEntityInfo : IEquatable { - public static readonly ArcEntityInfo Empty = new ArcEntityInfo(); + public static readonly RelEntityInfo Empty = new RelEntityInfo(); /// Start vertex entity ID. public readonly int start; @@ -24,7 +24,7 @@ namespace DCFApixels.DragonECS #endregion [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ArcEntityInfo(int startEntity, int endEntity) + internal RelEntityInfo(int startEntity, int endEntity) { start = startEntity; end = endEntity; @@ -38,15 +38,15 @@ namespace DCFApixels.DragonECS #region operators [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(ArcEntityInfo a, ArcEntityInfo b) => a.start == b.start && a.end == b.end; + public static bool operator ==(RelEntityInfo a, RelEntityInfo b) => a.start == b.start && a.end == b.end; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(ArcEntityInfo a, ArcEntityInfo b) => a.start != b.start || a.end != b.end; + public static bool operator !=(RelEntityInfo a, RelEntityInfo b) => a.start != b.start || a.end != b.end; #endregion #region Other - public override bool Equals(object obj) => obj is ArcEntityInfo targets && targets == this; + public override bool Equals(object obj) => obj is RelEntityInfo targets && targets == this; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(ArcEntityInfo other) => this == other; + public bool Equals(RelEntityInfo other) => this == other; [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() => ~start ^ end; public override string ToString() => $"arc({start} -> {end})"; diff --git a/src/Utils/SparseArray64.cs b/src/Utils/SparseArray64.cs index 72baae1..f0b6a4e 100644 --- a/src/Utils/SparseArray64.cs +++ b/src/Utils/SparseArray64.cs @@ -2,6 +2,7 @@ //Benchmark result of indexer.get speed test with 300 elements: //[Dictinary: 6.705us] [SparseArray64: 2.512us]. using System; +using System.Diagnostics; using System.Diagnostics.Contracts; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -225,6 +226,7 @@ namespace DCFApixels.DragonECS.Relations.Utils #region Utils [StructLayout(LayoutKind.Sequential, Pack = 4)] + [DebuggerDisplay("next{next} hashKey{hashKey} value{value}")] private struct Entry { public int next; // Index of next entry, -1 if last