mirror of
https://github.com/DCFApixels/DragonECS-Graphs.git
synced 2025-09-17 11:04:34 +08:00
fixes
нормально работает на небольших мирах, до 250 ентитей, разница с желаемым результатом в 10 раз. но в мирах на 1000 разница с желаемым результатом аж 100
This commit is contained in:
parent
2473c5dc78
commit
f865989c2d
@ -153,23 +153,25 @@ namespace DCFApixels.DragonECS
|
||||
#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);
|
||||
ref RelNodesInfo arcInfo = ref _relNodesMapping[relEntityID];
|
||||
|
||||
arcInfo.startNodeIndex = _startBaskets.AddToBasket(startEntityID, relEntityID);
|
||||
arcInfo.endNodeIndex = _endBaskets.AddToBasket(endEntityID, 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);
|
||||
if (!_isLoop)
|
||||
{
|
||||
//_startBaskets.RemoveFromBasket(endEntityID, relInfo.endNodeIndex);
|
||||
}
|
||||
_endBaskets.RemoveFromBasket(endEntityID, relInfo.endNodeIndex);
|
||||
}
|
||||
public void DelStart(int startEntityID)
|
||||
{
|
||||
@ -320,7 +322,11 @@ namespace DCFApixels.DragonECS
|
||||
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)
|
||||
{
|
||||
|
@ -134,7 +134,7 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
_relEntityInfos[relEntity] = new RelEntityInfo(startEntityID, endEntityID);
|
||||
_relEntities.Add(relEntity);
|
||||
_entitiesGraph.Add(relEntity);
|
||||
_entitiesGraph.Add(startEntityID, endEntityID, relEntity);
|
||||
return relEntity;
|
||||
}
|
||||
//public void DelRelation(int startEntityID, int endEntityID)
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using DCFApixels.DragonECS.Relations.Internal;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@ -10,21 +10,27 @@ namespace DCFApixels.DragonECS
|
||||
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||
internal class BasketList
|
||||
{
|
||||
public const int RECYCLE = -1;
|
||||
public const int HEAD = 0;
|
||||
public const int NULL = 0;
|
||||
|
||||
private BasketInfo[] _baskets = new BasketInfo[64];
|
||||
private Node[] _nodes;
|
||||
private int _recycledListLast = -1;
|
||||
private UnsafeArray<BasketInfo> _baskets = new UnsafeArray<BasketInfo>(64, true);
|
||||
private UnsafeArray<Node> _nodes;
|
||||
private int _recycledListHead = NULL;
|
||||
|
||||
#region Constructors
|
||||
#region Constructors/Destroy
|
||||
public BasketList() : this(16) { }
|
||||
public BasketList(int capacity)
|
||||
public BasketList(int minCapacity)
|
||||
{
|
||||
Initialize(capacity);
|
||||
Initialize(ArrayUtility.NormalizeSizeToPowerOfTwo(minCapacity));
|
||||
}
|
||||
//Dispose //GC.SuppressFinalize
|
||||
~BasketList()
|
||||
{
|
||||
_baskets.Dispose();
|
||||
_nodes.Dispose();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Clear
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Clear()
|
||||
{
|
||||
@ -37,40 +43,14 @@ namespace DCFApixels.DragonECS
|
||||
_baskets[i] = default;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private void Resize(int newSize)
|
||||
{
|
||||
int oldSize = _nodes.Length;
|
||||
Array.Resize(ref _nodes, newSize);
|
||||
int leftNode = newSize - 1;
|
||||
for (int i = oldSize; i < newSize; i++)
|
||||
{
|
||||
Link(i, leftNode);
|
||||
leftNode = i;
|
||||
}
|
||||
LinkToRecycled(newSize - 1, oldSize);
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private void Initialize(int newSize)
|
||||
{
|
||||
_nodes = new Node[newSize];
|
||||
int leftNode = newSize - 1;
|
||||
for (int i = 1; i < newSize; i++)
|
||||
{
|
||||
Link(i, leftNode);
|
||||
leftNode = i;
|
||||
}
|
||||
LinkToRecycled(newSize - 1, 1);
|
||||
}
|
||||
|
||||
#region Other
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int GetBasketNodesCount(int basketIndex)
|
||||
{
|
||||
return _baskets[basketIndex].count;
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Set(int nodeIndex, int value)
|
||||
{
|
||||
@ -81,16 +61,52 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
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 void RemoveFromBasket(int basketIndex, int nodeIndex)
|
||||
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)
|
||||
{
|
||||
@ -112,68 +128,6 @@ namespace DCFApixels.DragonECS
|
||||
basketInfo.count--;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int AddToBasket(int basketIndex, int value)
|
||||
{
|
||||
ref BasketInfo basketInfo = ref _baskets[basketIndex];
|
||||
int newNodeIndex = TakeRecycledNode();
|
||||
if (basketInfo.count == 0)
|
||||
{
|
||||
basketInfo.nodeIndex = newNodeIndex;
|
||||
_nodes[newNodeIndex].Set(value, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int nodeIndex = basketInfo.nodeIndex;
|
||||
ref Node nextNode = ref _nodes[nodeIndex];
|
||||
|
||||
_nodes[newNodeIndex].Set(value, nextNode.prev, nodeIndex);
|
||||
basketInfo.nodeIndex = newNodeIndex;
|
||||
nextNode.prev = newNodeIndex;
|
||||
}
|
||||
basketInfo.count++;
|
||||
return newNodeIndex;
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private int TakeRecycledNode()
|
||||
{
|
||||
if (_recycledListLast == -1)
|
||||
{
|
||||
Resize(_nodes.Length << 1);
|
||||
}
|
||||
int node = _recycledListLast;
|
||||
_recycledListLast = _nodes[node].prev;
|
||||
return node;
|
||||
}
|
||||
//[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 (_recycledListLast <= -1)
|
||||
{
|
||||
_nodes[startNodeIndex].prev = RECYCLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
Link(_recycledListLast, startNodeIndex);
|
||||
}
|
||||
_recycledListLast = endNodeIndex;
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void RemoveBasket(int basketIndex)
|
||||
{
|
||||
@ -193,55 +147,86 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
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 = 1 << (GetHighBitNumber((uint)minSize - 1) + 1);
|
||||
Array.Resize(ref _baskets, newSize);
|
||||
int newSize = ArrayUtility.NormalizeSizeToPowerOfTwo(minSize);
|
||||
UnsafeArray.ResizeAndInit(ref _baskets, newSize);
|
||||
}
|
||||
}
|
||||
private static int GetHighBitNumber(uint bits)
|
||||
{
|
||||
if (bits == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
int bit = 0;
|
||||
if ((bits & 0xFFFF0000) != 0)
|
||||
{
|
||||
bits >>= 16;
|
||||
bit |= 16;
|
||||
}
|
||||
if ((bits & 0xFF00) != 0)
|
||||
{
|
||||
bits >>= 8;
|
||||
bit |= 8;
|
||||
}
|
||||
if ((bits & 0xF0) != 0)
|
||||
{
|
||||
bits >>= 4;
|
||||
bit |= 4;
|
||||
}
|
||||
if ((bits & 0xC) != 0)
|
||||
{
|
||||
bits >>= 2;
|
||||
bit |= 2;
|
||||
}
|
||||
if ((bits & 0x2) != 0)
|
||||
{
|
||||
bit |= 1;
|
||||
}
|
||||
return bit;
|
||||
}
|
||||
#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 static readonly Node Empty = new Node() { value = 0, next = NULL };
|
||||
public int value;
|
||||
/// <summary>next node index</summary>
|
||||
public int next;
|
||||
@ -254,6 +239,18 @@ namespace DCFApixels.DragonECS
|
||||
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
|
||||
@ -301,7 +298,7 @@ namespace DCFApixels.DragonECS
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public struct Enumerator : IEnumerator<int>
|
||||
{
|
||||
private readonly Node[] _nodes;
|
||||
private readonly UnsafeArray<Node> _nodes;
|
||||
private int _nodeIndex;
|
||||
private int _nextNodeIndex;
|
||||
private int _count;
|
||||
@ -361,17 +358,21 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
List<Node> result = new List<Node>();
|
||||
Node curNode = new Node();
|
||||
curNode.index = _basketList._recycledListLast;
|
||||
curNode.index = _basketList._recycledListHead;
|
||||
|
||||
while (curNode.index != -1)
|
||||
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 = new Node();
|
||||
curNode.index = curNode.prev;
|
||||
|
||||
curNode.index = curNode.next;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
using DCFApixels.DragonECS.Utils;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@ -32,19 +31,27 @@ namespace DCFApixels.DragonECS.Relations.Internal
|
||||
|
||||
public ref T this[int index]
|
||||
{
|
||||
get { return ref ptr[index]; }
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get
|
||||
{
|
||||
#if DEBUG
|
||||
if (index < 0 || index >= Length)
|
||||
Throw.ArgumentOutOfRange();
|
||||
#endif
|
||||
return ref ptr[index];
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public UnsafeArray(int length)
|
||||
{
|
||||
UnmanagedArrayUtility.New(out ptr, length);
|
||||
ptr = UnmanagedArrayUtility.New<T>(length);
|
||||
Length = length;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public UnsafeArray(int length, bool isInit)
|
||||
{
|
||||
UnmanagedArrayUtility.NewAndInit(out ptr, length);
|
||||
ptr = UnmanagedArrayUtility.NewAndInit<T>(length);
|
||||
Length = length;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@ -67,8 +74,7 @@ namespace DCFApixels.DragonECS.Relations.Internal
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
T* ptr = this.ptr;
|
||||
return CollectionUtility.AutoToString(EnumerableInt.Range(0, Length).Select(i => ptr[i]), "ua");
|
||||
return $"ua({Length}) ({string.Join(", ", this.ToArray())})";
|
||||
}
|
||||
|
||||
public static void Resize(ref UnsafeArray<T> array, int newSize)
|
||||
@ -113,12 +119,18 @@ namespace DCFApixels.DragonECS.Relations.Internal
|
||||
|
||||
internal class DebuggerProxy
|
||||
{
|
||||
public void* ptr;
|
||||
public T[] elements;
|
||||
public int length;
|
||||
public DebuggerProxy(UnsafeArray<T> instance)
|
||||
{
|
||||
elements = EnumerableInt.Range(0, instance.Length).Select(i => instance.ptr[i]).ToArray();
|
||||
ptr = instance.ptr;
|
||||
length = instance.Length;
|
||||
elements = new T[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
elements[i] = instance[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user