нормально работает на небольших мирах, до 250 ентитей, разница с желаемым результатом в 10 раз. но в мирах на 1000 разница с желаемым результатом аж 100
This commit is contained in:
Mikhail 2024-02-06 01:59:18 +08:00
parent 2473c5dc78
commit f865989c2d
4 changed files with 179 additions and 160 deletions

View File

@ -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)
{

View File

@ -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)

View File

@ -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;
}

View File

@ -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];
}
}
}
}