нормально работает на небольших мирах, до 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 #endregion
#region Add/Del #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) public void Add(int relEntityID)
{ {
var (startEntityID, endEntityID) = _source.GetRelationInfo(relEntityID); var (startEntityID, endEntityID) = _source.GetRelationInfo(relEntityID);
ref RelNodesInfo arcInfo = ref _relNodesMapping[relEntityID]; _relNodesMapping[relEntityID] = new RelNodesInfo(
_startBaskets.AddToBasket(startEntityID, relEntityID),
arcInfo.startNodeIndex = _startBaskets.AddToBasket(startEntityID, relEntityID); _endBaskets.AddToBasket(endEntityID, relEntityID));
arcInfo.endNodeIndex = _endBaskets.AddToBasket(endEntityID, relEntityID);
} }
public void Del(int relEntityID) public void Del(int relEntityID)
{ {
var (startEntityID, endEntityID) = _source.GetRelationInfo(relEntityID); var (startEntityID, endEntityID) = _source.GetRelationInfo(relEntityID);
ref RelNodesInfo relInfo = ref _relNodesMapping[relEntityID]; ref RelNodesInfo relInfo = ref _relNodesMapping[relEntityID];
_startBaskets.RemoveFromBasket(startEntityID, relInfo.startNodeIndex); _startBaskets.RemoveFromBasket(startEntityID, relInfo.startNodeIndex);
if (!_isLoop) _endBaskets.RemoveFromBasket(endEntityID, relInfo.endNodeIndex);
{
//_startBaskets.RemoveFromBasket(endEntityID, relInfo.endNodeIndex);
}
} }
public void DelStart(int startEntityID) public void DelStart(int startEntityID)
{ {
@ -320,7 +322,11 @@ namespace DCFApixels.DragonECS
public readonly static RelNodesInfo Empty = default; public readonly static RelNodesInfo Empty = default;
public int startNodeIndex; public int startNodeIndex;
public int endNodeIndex; public int endNodeIndex;
public RelNodesInfo(int startNodeIndex, int endNodeIndex)
{
this.startNodeIndex = startNodeIndex;
this.endNodeIndex = endNodeIndex;
}
#region Object #region Object
public override bool Equals(object obj) public override bool Equals(object obj)
{ {

View File

@ -134,7 +134,7 @@ namespace DCFApixels.DragonECS
_relEntityInfos[relEntity] = new RelEntityInfo(startEntityID, endEntityID); _relEntityInfos[relEntity] = new RelEntityInfo(startEntityID, endEntityID);
_relEntities.Add(relEntity); _relEntities.Add(relEntity);
_entitiesGraph.Add(relEntity); _entitiesGraph.Add(startEntityID, endEntityID, relEntity);
return relEntity; return relEntity;
} }
//public void DelRelation(int startEntityID, int endEntityID) //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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@ -10,21 +10,27 @@ namespace DCFApixels.DragonECS
[DebuggerTypeProxy(typeof(DebuggerProxy))] [DebuggerTypeProxy(typeof(DebuggerProxy))]
internal class BasketList internal class BasketList
{ {
public const int RECYCLE = -1; public const int NULL = 0;
public const int HEAD = 0;
private BasketInfo[] _baskets = new BasketInfo[64]; private UnsafeArray<BasketInfo> _baskets = new UnsafeArray<BasketInfo>(64, true);
private Node[] _nodes; private UnsafeArray<Node> _nodes;
private int _recycledListLast = -1; private int _recycledListHead = NULL;
#region Constructors #region Constructors/Destroy
public BasketList() : this(16) { } 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 #endregion
#region Clear
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear() public void Clear()
{ {
@ -37,40 +43,14 @@ namespace DCFApixels.DragonECS
_baskets[i] = default; _baskets[i] = default;
} }
} }
#endregion
[MethodImpl(MethodImplOptions.NoInlining)] #region Other
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);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetBasketNodesCount(int basketIndex) public int GetBasketNodesCount(int basketIndex)
{ {
return _baskets[basketIndex].count; return _baskets[basketIndex].count;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Set(int nodeIndex, int value) public void Set(int nodeIndex, int value)
{ {
@ -81,16 +61,52 @@ namespace DCFApixels.DragonECS
{ {
return _nodes[nodeIndex].value; return _nodes[nodeIndex].value;
} }
private Node GetNode(int nodeIndex) private Node GetNode(int nodeIndex)
{ {
return _nodes[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)] [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 DEBUG
if (nodeIndex <= 0) if (nodeIndex <= 0)
{ {
@ -112,68 +128,6 @@ namespace DCFApixels.DragonECS
basketInfo.count--; 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)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RemoveBasket(int basketIndex) public void RemoveBasket(int basketIndex)
{ {
@ -193,55 +147,86 @@ namespace DCFApixels.DragonECS
basket.count = 0; 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)] [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) public void UpBasketsSize(int minSize)
{ {
if (minSize > _baskets.Length) if (minSize > _baskets.Length)
{ {
int newSize = 1 << (GetHighBitNumber((uint)minSize - 1) + 1); int newSize = ArrayUtility.NormalizeSizeToPowerOfTwo(minSize);
Array.Resize(ref _baskets, newSize); UnsafeArray.ResizeAndInit(ref _baskets, newSize);
} }
} }
private static int GetHighBitNumber(uint bits) #endregion
{
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;
}
#region Node #region Node
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)] [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)]
public struct Node 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; public int value;
/// <summary>next node index</summary> /// <summary>next node index</summary>
public int next; public int next;
@ -254,6 +239,18 @@ namespace DCFApixels.DragonECS
this.next = next; this.next = next;
this.prev = prev; 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})"; public override string ToString() => $"node({prev}<>{next} v:{value})";
} }
#endregion #endregion
@ -301,7 +298,7 @@ namespace DCFApixels.DragonECS
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public struct Enumerator : IEnumerator<int> public struct Enumerator : IEnumerator<int>
{ {
private readonly Node[] _nodes; private readonly UnsafeArray<Node> _nodes;
private int _nodeIndex; private int _nodeIndex;
private int _nextNodeIndex; private int _nextNodeIndex;
private int _count; private int _count;
@ -361,17 +358,21 @@ namespace DCFApixels.DragonECS
{ {
List<Node> result = new List<Node>(); List<Node> result = new List<Node>();
Node curNode = new 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); BasketList.Node x = _basketList.GetNode(curNode.index);
curNode.prev = x.prev; curNode.prev = x.prev;
curNode.next = x.next; curNode.next = x.next;
result.Add(curNode); result.Add(curNode);
curNode = new Node();
curNode.index = curNode.prev; curNode.index = curNode.next;
} }
return result; return result;
} }

View File

@ -1,5 +1,4 @@
using DCFApixels.DragonECS.Utils; using System;
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@ -32,19 +31,27 @@ namespace DCFApixels.DragonECS.Relations.Internal
public ref T this[int index] 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)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public UnsafeArray(int length) public UnsafeArray(int length)
{ {
UnmanagedArrayUtility.New(out ptr, length); ptr = UnmanagedArrayUtility.New<T>(length);
Length = length; Length = length;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public UnsafeArray(int length, bool isInit) public UnsafeArray(int length, bool isInit)
{ {
UnmanagedArrayUtility.NewAndInit(out ptr, length); ptr = UnmanagedArrayUtility.NewAndInit<T>(length);
Length = length; Length = length;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -67,8 +74,7 @@ namespace DCFApixels.DragonECS.Relations.Internal
} }
public override string ToString() public override string ToString()
{ {
T* ptr = this.ptr; return $"ua({Length}) ({string.Join(", ", this.ToArray())})";
return CollectionUtility.AutoToString(EnumerableInt.Range(0, Length).Select(i => ptr[i]), "ua");
} }
public static void Resize(ref UnsafeArray<T> array, int newSize) public static void Resize(ref UnsafeArray<T> array, int newSize)
@ -113,12 +119,18 @@ namespace DCFApixels.DragonECS.Relations.Internal
internal class DebuggerProxy internal class DebuggerProxy
{ {
public void* ptr;
public T[] elements; public T[] elements;
public int length; public int length;
public DebuggerProxy(UnsafeArray<T> instance) public DebuggerProxy(UnsafeArray<T> instance)
{ {
elements = EnumerableInt.Range(0, instance.Length).Select(i => instance.ptr[i]).ToArray(); ptr = instance.ptr;
length = instance.Length; length = instance.Length;
elements = new T[length];
for (int i = 0; i < length; i++)
{
elements[i] = instance[i];
}
} }
} }
} }