mirror of
https://github.com/DCFApixels/DragonECS-Graphs.git
synced 2025-09-17 19:24:36 +08:00
Update
This commit is contained in:
parent
0e5e1ac1a4
commit
22d873ed38
409
src/Collections/EcsJoin.cs
Normal file
409
src/Collections/EcsJoin.cs
Normal file
@ -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<RelEnd>
|
||||
{
|
||||
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<RelEnd> IEnumerable<RelEnd>.GetEnumerator() { return GetEnumerator(); }
|
||||
//IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
public ref struct Enumerator //: IEnumerator<RelEnd>
|
||||
{
|
||||
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<RelInfo>
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
209
src/EcsArc.cs
209
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<int> _relationsMatrix = new SparseArray64<int>();
|
||||
|
||||
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<int> 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<int> 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<int> 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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -4,11 +4,12 @@ using System;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public static class WorldGraph
|
||||
public static class EcsWorldGraph
|
||||
{
|
||||
private static readonly SparseArray64<EcsArc> _matrix = new SparseArray64<EcsArc>(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)
|
||||
{
|
@ -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<int>
|
||||
public readonly struct BasketIterator : IEnumerable<int>
|
||||
{
|
||||
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<int> IEnumerable<int>.GetEnumerator() => GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
public struct Enumerator : IEnumerator<int>
|
||||
{
|
||||
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<BasketIteratorDebbugerProxy> Baskets
|
||||
{
|
||||
get
|
||||
{
|
||||
List<BasketIteratorDebbugerProxy> result = new List<BasketIteratorDebbugerProxy>();
|
||||
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<int> RelEntities
|
||||
{
|
||||
get
|
||||
{
|
||||
List<int> result = new List<int>();
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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<int>
|
||||
{
|
||||
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<Node> Nodes
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => new ReadOnlySpan<Node>(_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;
|
||||
}
|
||||
|
||||
/// <summary> Insert after</summary>
|
||||
/// <returns> new node index</returns>
|
||||
[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<int> IEnumerable<int>.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<int>
|
||||
{
|
||||
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<entlong>
|
||||
{
|
||||
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;
|
||||
/// <summary>next node index</summary>
|
||||
public int next;
|
||||
/// <summary>prev node index</summary>
|
||||
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
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d852affe1595eb4b9d8eb8dc6f28720
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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
|
||||
{
|
||||
/// <summary>Start vertex entity ID.</summary>
|
||||
public readonly int start;
|
||||
/// <summary>Arc entity ID.</summary>
|
||||
public readonly int arc;
|
||||
/// <summary>Relation entity ID.</summary>
|
||||
public readonly int rel;
|
||||
/// <summary>End vertex entity ID.</summary>
|
||||
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
|
||||
{
|
||||
/// <summary>Arc entity ID.</summary>
|
||||
public readonly int arc;
|
||||
/// <summary>Relation entity ID.</summary>
|
||||
public readonly int rel;
|
||||
/// <summary>End vertex entity ID.</summary>
|
||||
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;
|
||||
}
|
||||
}
|
@ -6,9 +6,9 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)]
|
||||
[Serializable]
|
||||
public readonly struct ArcEntityInfo : IEquatable<ArcEntityInfo>
|
||||
public readonly struct RelEntityInfo : IEquatable<RelEntityInfo>
|
||||
{
|
||||
public static readonly ArcEntityInfo Empty = new ArcEntityInfo();
|
||||
public static readonly RelEntityInfo Empty = new RelEntityInfo();
|
||||
|
||||
/// <summary>Start vertex entity ID.</summary>
|
||||
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})";
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user