without matrix

This commit is contained in:
Mikhail 2024-02-22 17:12:28 +08:00
parent f865989c2d
commit d6c0a22221
5 changed files with 5 additions and 1000 deletions

View File

@ -1,450 +0,0 @@
using DCFApixels.DragonECS.Relations.Internal;
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using static DCFApixels.DragonECS.EcsGraph;
namespace DCFApixels.DragonECS
{
public readonly ref struct EcsReadonlyGraph
{
private readonly EcsGraph _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 EnumerableRelEnd this[int startEntityID]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _source[startEntityID]; }
}
#endregion
#region Constructors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsReadonlyGraph(EcsGraph 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 EnumerableRelEnd GetRelEnds(int startEntityID) { return _source.GetRelEnds(startEntityID); }
#endregion
#region Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal EcsGraph 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 EcsGraph
{
private readonly EcsArc _source;
private readonly bool _isLoop;
private readonly BasketList _startBaskets;
private readonly BasketList _endBaskets;
private RelNodesInfo[] _relNodesMapping;
#region Properties
public EcsReadonlyGraph Readonly
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return new EcsReadonlyGraph(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 EnumerableRelEnd this[int startEntityID]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return GetRelEnds(startEntityID); }
}
#endregion
#region Constructors
public EcsGraph(EcsArc arc)
{
_source = arc;
_isLoop = arc.IsLoop;
_startBaskets = new BasketList();
_endBaskets = new BasketList();
_relNodesMapping = new RelNodesInfo[arc.ArcWorld.Capacity];
}
#endregion
#region Add/Del
public void Add(int startEntityID, int endEntityID, int relEntityID)
{
_relNodesMapping[relEntityID] = new RelNodesInfo(
_startBaskets.AddToBasket(startEntityID, relEntityID),
_endBaskets.AddToBasket(endEntityID, relEntityID));
}
public void Add(int relEntityID)
{
var (startEntityID, endEntityID) = _source.GetRelationInfo(relEntityID);
_relNodesMapping[relEntityID] = new RelNodesInfo(
_startBaskets.AddToBasket(startEntityID, relEntityID),
_endBaskets.AddToBasket(endEntityID, relEntityID));
}
public void Del(int relEntityID)
{
var (startEntityID, endEntityID) = _source.GetRelationInfo(relEntityID);
ref RelNodesInfo relInfo = ref _relNodesMapping[relEntityID];
_startBaskets.RemoveFromBasket(startEntityID, relInfo.startNodeIndex);
_endBaskets.RemoveFromBasket(endEntityID, relInfo.endNodeIndex);
}
public void DelStart(int startEntityID)
{
foreach (var relEntityID in _startBaskets.GetBasketIterator(startEntityID))
{
var endEntityID = _source.GetRelEnd(relEntityID);
ref RelNodesInfo relInfo = ref _relNodesMapping[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 RelNodesInfo relInfo = ref _relNodesMapping[relEntityID];
_startBaskets.RemoveFromBasket(startEntityID, relInfo.endNodeIndex);
}
_endBaskets.RemoveBasket(endEntityID);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DelStartAndDelRelEntities(int startEntityID, EcsArc arc)
{
foreach (var relEntityID in _startBaskets.GetBasketIterator(startEntityID))
{
arc.ArcWorld.TryDelEntity(relEntityID);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DelEndAndDelRelEntities(int endEntityID, EcsArc arc)
{
foreach (var relEntityID in _endBaskets.GetBasketIterator(endEntityID))
{
arc.ArcWorld.TryDelEntity(relEntityID);
}
}
public struct FriendEcsArc
{
private EcsGraph _join;
public FriendEcsArc(EcsArc arc, EcsGraph join)
{
if (arc.IsInit_Internal != false)
{
Throw.UndefinedException();
}
_join = join;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void DelStartAndDelRelEntities(int startEntityID, EcsArc arc)
{
_join.DelStartAndDelRelEntities(startEntityID, arc);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void DelEndAndDelRelEntities(int endEntityID, EcsArc arc)
{
_join.DelEndAndDelRelEntities(endEntityID, arc);
}
}
#endregion
#region Has
public bool Has(int relEntityID)
{
return _relNodesMapping[relEntityID] != RelNodesInfo.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 EnumerableRelEnd GetRelEnds(int startEntityID)
{
return new EnumerableRelEnd(_source, _startBaskets.GetBasketIterator(startEntityID).GetEnumerator());
}
#endregion
#region EnumerableArcEnd
public readonly ref struct EnumerableRelEnd //: IEnumerable<RelEnd>
{
private readonly EcsArc _arc;
private readonly BasketList.BasketIterator.Enumerator _iterator;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal EnumerableRelEnd(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 RelNodesInfo : IEquatable<RelNodesInfo>
{
public readonly static RelNodesInfo Empty = default;
public int startNodeIndex;
public int endNodeIndex;
public RelNodesInfo(int startNodeIndex, int endNodeIndex)
{
this.startNodeIndex = startNodeIndex;
this.endNodeIndex = endNodeIndex;
}
#region Object
public override bool Equals(object obj)
{
return obj is RelNodesInfo && Equals((RelNodesInfo)obj);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(RelNodesInfo 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 ==(RelNodesInfo a, RelNodesInfo b) => a.startNodeIndex == b.startNodeIndex && a.endNodeIndex == b.endNodeIndex;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(RelNodesInfo a, RelNodesInfo b) => a.startNodeIndex != b.startNodeIndex || a.endNodeIndex != b.endNodeIndex;
#endregion
}
#endregion
#region Operators
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator EcsReadonlyGraph(EcsGraph a) => a.Readonly;
#endregion
#region UpSize
public void UpArcSize(int minSize)
{
Array.Resize(ref _relNodesMapping, minSize);
}
public void UpStartSize(int minSize)
{
_startBaskets.UpBasketsSize(minSize);
}
public void UpEndSize(int minSize)
{
_endBaskets.UpBasketsSize(minSize);
}
#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
}
}

View File

@ -1,8 +1,6 @@
using DCFApixels.DragonECS.Relations.Internal;
using DCFApixels.DragonECS.Relations.Utils;
using System;
using System.Runtime.CompilerServices;
using System.Xml;
namespace DCFApixels.DragonECS
{
@ -21,11 +19,6 @@ namespace DCFApixels.DragonECS
private readonly EndWorldHandler _endWorldHandler;
private readonly LoopWorldHandler _loopWorldHandler;
//private readonly SparseArray64<int> _relationsMatrix = new SparseArray64<int>();
private EcsGraph _entitiesGraph;
private EcsGraph.FriendEcsArc _entitiesGraphFriend;
private EcsGroup _relEntities;
private RelEntityInfo[] _relEntityInfos; //N * (N - 1) / 2
@ -63,11 +56,6 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _relEntities.Readonly; }
}
public EcsReadonlyGraph EntitiesGraph
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _entitiesGraph.Readonly; }
}
public bool IsLoop
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -88,9 +76,6 @@ namespace DCFApixels.DragonECS
_relEntities = EcsGroup.New(_arcWorld);
_entitiesGraph = new EcsGraph(this);
_entitiesGraphFriend = new EcsGraph.FriendEcsArc(this, _entitiesGraph);
_arcWorldHandler = new ArcWorldHandler(this);
if (_isLoop)
@ -124,30 +109,11 @@ namespace DCFApixels.DragonECS
#region New/Del
public int NewRelation(int startEntityID, int endEntityID)
{
//if (HasRelation(startEntityID, endEntityID))
//{
// Throw.RelationAlreadyExists();
//}
int relEntity = _arcWorld.NewEntity();
//_relationsMatrix.Add(startEntityID, endEntityID, relEntity);
_relEntityInfos[relEntity] = new RelEntityInfo(startEntityID, endEntityID);
_relEntities.Add(relEntity);
_entitiesGraph.Add(startEntityID, endEntityID, relEntity);
return relEntity;
}
//public void DelRelation(int startEntityID, int endEntityID)
//{
// if (_relationsMatrix.TryGetValue(startEntityID, endEntityID, out int relEntityID))
// {
// _arcWorld.DelEntity(relEntityID);
// }
// else
// {
// Throw.UndefinedRelationException();
// }
//}
public void DelRelation(int relEntityID)
{
@ -157,39 +123,8 @@ namespace DCFApixels.DragonECS
public void ClearRelation_Internal(int relEntityID)
{
_relEntities.Remove(relEntityID);
_entitiesGraph.Del(relEntityID);
_relEntityInfos[relEntityID] = RelEntityInfo.Empty;
}
//private void ClearRelation_Internal(int startEntityID, int endEntityID)
//{
// if (_relationsMatrix.TryGetValue(startEntityID, endEntityID, out int relEntityID))
// {
// _relEntities.Remove(relEntityID);
// _entitiesGraph.Del(relEntityID);
// _relationsMatrix.Remove(startEntityID, endEntityID);
// _relEntityInfos[relEntityID] = RelEntityInfo.Empty;
// }
//}
#endregion
#region GetRelation/HasRelation
//public bool HasRelation(int startEntityID, int endEntityID)
//{
// return _relationsMatrix.Contains(startEntityID, endEntityID);
//}
//public int GetRelation(int startEntityID, int endEntityID)
//{
// if (!_relationsMatrix.TryGetValue(startEntityID, endEntityID, out int relEntityID))
// {
// Throw.UndefinedRelationException();
// }
// return relEntityID;
//}
//public bool TryGetRelation(int startEntityID, int endEntityID, out int relEntityID)
//{
// return _relationsMatrix.TryGetValue(startEntityID, endEntityID, out relEntityID);
//}
#endregion
#region ArcEntityInfo
@ -221,19 +156,6 @@ namespace DCFApixels.DragonECS
{
return GetRelationInfo(relEntityID).end;
}
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
//public int GetInversedRelation(int relEntityID)
//{
// var (startEntityID, endEntityID) = GetRelationInfo(relEntityID);
// return GetRelation(endEntityID, startEntityID);
//}
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
//public bool TryGetInversedRelation(int relEntityID, out int inversedRelEntityID)
//{
// var (startEntityID, endEntityID) = GetRelationInfo(relEntityID);
// return TryGetRelation(endEntityID, startEntityID, out inversedRelEntityID);
//}
#endregion
#region Other
@ -275,7 +197,6 @@ namespace DCFApixels.DragonECS
public void OnWorldResize(int arcWorldNewSize)
{
Array.Resize(ref _arc._relEntityInfos, arcWorldNewSize);
_arc._entitiesGraph.UpArcSize(arcWorldNewSize);
}
#endregion
}
@ -295,17 +216,10 @@ namespace DCFApixels.DragonECS
#region Callbacks
public void OnReleaseDelEntityBuffer(ReadOnlySpan<int> startEntityBuffer)
{
foreach (var startEntityID in startEntityBuffer)
{
_arc._entitiesGraphFriend.DelStartAndDelRelEntities(startEntityID, _arc);
}
_arc._arcWorld.ReleaseDelEntityBufferAll();
}
public void OnWorldDestroy() { }
public void OnWorldResize(int startWorldNewSize)
{
_arc._entitiesGraph.UpStartSize(startWorldNewSize);
}
public void OnWorldResize(int startWorldNewSize) { }
#endregion
}
private class EndWorldHandler : IEcsWorldEventListener
@ -324,17 +238,10 @@ namespace DCFApixels.DragonECS
#region Callbacks
public void OnReleaseDelEntityBuffer(ReadOnlySpan<int> endEntityBuffer)
{
foreach (var endEntityID in endEntityBuffer)
{
_arc._entitiesGraphFriend.DelEndAndDelRelEntities(endEntityID, _arc);
}
_arc._arcWorld.ReleaseDelEntityBufferAll();
}
public void OnWorldDestroy() { }
public void OnWorldResize(int endWorldNewSize)
{
_arc._entitiesGraph.UpEndSize(endWorldNewSize);
}
public void OnWorldResize(int endWorldNewSize) { }
#endregion
}
private class LoopWorldHandler : IEcsWorldEventListener
@ -353,19 +260,10 @@ namespace DCFApixels.DragonECS
#region Callbacks
public void OnReleaseDelEntityBuffer(ReadOnlySpan<int> startEntityBuffer)
{
foreach (var startEntityID in startEntityBuffer)
{
_arc._entitiesGraphFriend.DelStartAndDelRelEntities(startEntityID, _arc);
_arc._entitiesGraphFriend.DelEndAndDelRelEntities(startEntityID, _arc);
}
_arc._arcWorld.ReleaseDelEntityBufferAll();
}
public void OnWorldDestroy() { }
public void OnWorldResize(int startWorldNewSize)
{
_arc._entitiesGraph.UpStartSize(startWorldNewSize);
_arc._entitiesGraph.UpEndSize(startWorldNewSize);
}
public void OnWorldResize(int startWorldNewSize) { }
#endregion
}
#endregion

View File

@ -1,10 +1,7 @@
using System;
using System.Collections.Generic;
namespace DCFApixels.DragonECS
namespace DCFApixels.DragonECS
{
public static class EcsWorldConfigRelationsExtensions
{
}
}

View File

@ -1,438 +0,0 @@
using DCFApixels.DragonECS.Relations.Internal;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS
{
[DebuggerTypeProxy(typeof(DebuggerProxy))]
internal class BasketList
{
public const int NULL = 0;
private UnsafeArray<BasketInfo> _baskets = new UnsafeArray<BasketInfo>(64, true);
private UnsafeArray<Node> _nodes;
private int _recycledListHead = NULL;
#region Constructors/Destroy
public BasketList() : this(16) { }
public BasketList(int minCapacity)
{
Initialize(ArrayUtility.NormalizeSizeToPowerOfTwo(minCapacity));
}
//Dispose //GC.SuppressFinalize
~BasketList()
{
_baskets.Dispose();
_nodes.Dispose();
}
#endregion
#region Clear
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()
{
for (int i = 0; i < _nodes.Length; i++)
{
_nodes[i].next = 0;
}
for (int i = 0; i < _baskets.Length; i++)
{
_baskets[i] = default;
}
}
#endregion
#region Other
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetBasketNodesCount(int basketIndex)
{
return _baskets[basketIndex].count;
}
[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;
}
private Node GetNode(int nodeIndex)
{
return _nodes[nodeIndex];
}
#endregion
#region AddToBasket/TakeRecycledNode
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int TakeRecycledNode()
{
if (_recycledListHead == NULL)
{
ResizeNodes(_nodes.Length << 1);
}
int node = _recycledListHead;
_recycledListHead = _nodes[node].next;
return node;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int AddToBasket(int basketIndex, int value)
{
ref BasketInfo basketInfo = ref _baskets[basketIndex];
int newNodeIndex = TakeRecycledNode();
if (basketInfo.count == 0)
{
_nodes[newNodeIndex].SetValue_Prev(value, 0);
}
else
{
int nodeIndex = basketInfo.nodeIndex;
ref int nextNode_Prev = ref _nodes[nodeIndex].prev;
_nodes[newNodeIndex].Set(value, nextNode_Prev, nodeIndex);
nextNode_Prev = newNodeIndex;
}
basketInfo.nodeIndex = newNodeIndex;
basketInfo.count++;
return newNodeIndex;
}
#endregion
#region RemoveFromBasket/RemoveBasket
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RemoveFromBasket(int basketIndex, int nodeIndex)
{//нужно добавить ограничение на удаление повторяющейся ноды, иначе recycled ноды зацикливаются
#if DEBUG
if (nodeIndex <= 0)
{
//Throw.ArgumentOutOfRange();
return;
}
#endif
ref BasketInfo basketInfo = ref _baskets[basketIndex];
ref var node = ref _nodes[nodeIndex];
int nextNode = node.next;
Link(node.prev, nextNode);
LinkToRecycled(nodeIndex, nodeIndex);
if (basketInfo.nodeIndex == nodeIndex)
{
basketInfo.nodeIndex = nextNode;
}
basketInfo.count--;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RemoveBasket(int basketIndex)
{
ref BasketInfo basket = ref _baskets[basketIndex];
int startNodeIndex = basket.nodeIndex;
int endNodeIndex = startNodeIndex;
ref Node startNode = ref _nodes[startNodeIndex];
for (int i = 0, n = basket.count; i < n; i++)
{
endNodeIndex = _nodes[endNodeIndex].next;
}
ref Node endNode = ref _nodes[endNodeIndex];
LinkToRecycled(startNodeIndex, endNodeIndex);
Link(startNode.prev, endNode.next);
basket.count = 0;
}
#endregion
#region Links
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
//private void Separate(int leftNodeIndex, int rightNodeIndex)
//{
// _nodes[rightNodeIndex].prev = 0;
// _nodes[leftNodeIndex].next = 0;
//}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Link(int leftNodeIndex, int rightNodeIndex)
{
_nodes[rightNodeIndex].prev = leftNodeIndex;
_nodes[leftNodeIndex].next = rightNodeIndex;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void LinkToRecycled(int startNodeIndex, int endNodeIndex)
{
if (_recycledListHead <= NULL)
{
_nodes[endNodeIndex].next = NULL;
}
else
{
Link(startNodeIndex, _recycledListHead);
}
_recycledListHead = startNodeIndex;
}
#endregion
#region UpSize/Resize/Initialize
[MethodImpl(MethodImplOptions.NoInlining)]
private void ResizeNodes(int newSize)
{
int oldSize = _nodes.Length;
UnsafeArray.Resize(ref _nodes, newSize);
InitNewNodes(oldSize, newSize);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private void Initialize(int newSize)
{
_nodes = new UnsafeArray<Node>(newSize);
_nodes[0] = Node.Empty;
InitNewNodes(1, newSize);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private void InitNewNodes(int oldSize, int newSize)
{
int leftNode = NULL;
for (int i = oldSize; i < newSize; i++)
{
Link(leftNode, i);
leftNode = i;
}
LinkToRecycled(oldSize, newSize - 1);
}
public void UpNodesSize(int minSize)
{
if (minSize > _nodes.Length)
{
int newSize = ArrayUtility.NormalizeSizeToPowerOfTwo(minSize);
ResizeNodes(newSize);
}
}
public void UpBasketsSize(int minSize)
{
if (minSize > _baskets.Length)
{
int newSize = ArrayUtility.NormalizeSizeToPowerOfTwo(minSize);
UnsafeArray.ResizeAndInit(ref _baskets, newSize);
}
}
#endregion
#region Node
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)]
public struct Node
{
public static readonly Node Empty = new Node() { value = 0, next = NULL };
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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetValue_Prev(int value, int prev)
{
this.value = value;
this.prev = prev;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetPrev_Next(int prev, int next)
{
this.next = next;
this.prev = prev;
}
public override string ToString() => $"node({prev}<>{next} v:{value})";
}
#endregion
#region BasketInfo
private struct BasketInfo
{
public static readonly BasketInfo Empty = new BasketInfo() { nodeIndex = 0, count = 0, };
public int nodeIndex;
public int count;
public override string ToString() => $"basket_info(i:{nodeIndex} c:{count})";
}
#endregion
#region Basket
public BasketIterator this[int basketIndex]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => GetBasketIterator(basketIndex);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BasketIterator GetBasketIterator(int basketIndex)
{
return new BasketIterator(this, basketIndex);
}
public readonly struct BasketIterator : IEnumerable<int>
{
private readonly BasketList _basketList;
private readonly int _basketIndex;
public int Count
{
get { return _basketList._baskets[_basketIndex].count; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BasketIterator(BasketList basketList, int basketIndex)
{
_basketList = basketList;
_basketIndex = basketIndex;
}
[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 UnsafeArray<Node> _nodes;
private int _nodeIndex;
private int _nextNodeIndex;
private int _count;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator(BasketIterator iterator)
{
ref BasketInfo basketInfo = ref iterator._basketList._baskets[iterator._basketIndex];
_nodes = iterator._basketList._nodes;
_nodeIndex = -1;
_nextNodeIndex = basketInfo.nodeIndex;
_count = basketInfo.count;
}
public int Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _nodes[_nodeIndex].value;
}
object IEnumerator.Current => Current;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
_nodeIndex = _nextNodeIndex;
_nextNodeIndex = _nodes[_nextNodeIndex].next;
return _nodeIndex > 0 && _count-- > 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset() { }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose() { }
}
}
#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 IEnumerable<Node> Recycled
{
get
{
List<Node> result = new List<Node>();
Node curNode = new Node();
curNode.index = _basketList._recycledListHead;
for (int i = 0; i < _basketList._nodes.Length; i++)
{
if (curNode.index == NULL)
{
break;
}
BasketList.Node x = _basketList.GetNode(curNode.index);
curNode.prev = x.prev;
curNode.next = x.next;
result.Add(curNode);
curNode.index = curNode.next;
}
return result;
}
}
public IEnumerable<Node> AllNodes
{
get
{
List<Node> result = new List<Node>();
for (int i = 0; i < _basketList._nodes.Length; i++)
{
result.Add(new Node(_basketList._nodes[i].prev, i, _basketList._nodes[i].next));
}
return result;
}
}
public DebuggerProxy(BasketList basketList)
{
_basketList = basketList;
}
public struct Node
{
public int prev;
public int index;
public int next;
public Node(int prev, int index, int next)
{
this.prev = prev;
this.index = index;
this.next = next;
}
public override string ToString() => $"node({prev}< {index} >{next})";
}
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
}
}

View File

@ -1,6 +1,5 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
namespace DCFApixels.DragonECS.Relations.Internal
{
@ -42,6 +41,5 @@ namespace DCFApixels.DragonECS
public EcsRelationException() { }
public EcsRelationException(string message) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message) { }
public EcsRelationException(string message, Exception inner) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message, inner) { }
protected EcsRelationException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
}