mirror of
https://github.com/DCFApixels/DragonECS-Graphs.git
synced 2026-04-22 01:45:56 +08:00
stash/ not work
This commit is contained in:
parent
653a798af7
commit
5ee2f6a0a6
@ -169,9 +169,10 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
public void Del(int relEntityID)
|
||||
{
|
||||
var (startEntityID, _) = _source.GetRelationInfo(relEntityID);
|
||||
var (startEntityID, endEntityID) = _source.GetRelationInfo(relEntityID);
|
||||
ref RelNodesInfo relInfo = ref _relNodesMapping[relEntityID];
|
||||
_startBaskets.RemoveFromBasket(startEntityID, relInfo.startNodeIndex);
|
||||
_startBaskets.RemoveNextNodeFromBasket(startEntityID, relInfo.startNodeIndex);
|
||||
_endBaskets.RemoveNextNodeFromBasket(endEntityID, relInfo.endNodeIndex);
|
||||
}
|
||||
public void DelStart(int startEntityID)
|
||||
{
|
||||
@ -179,7 +180,7 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
var endEntityID = _source.GetRelEnd(relEntityID);
|
||||
ref RelNodesInfo relInfo = ref _relNodesMapping[relEntityID];
|
||||
_endBaskets.RemoveFromBasket(endEntityID, relInfo.startNodeIndex);
|
||||
_endBaskets.RemoveNextNodeFromBasket(endEntityID, relInfo.startNodeIndex);
|
||||
}
|
||||
_startBaskets.RemoveBasket(startEntityID);
|
||||
}
|
||||
@ -189,7 +190,7 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
var startEntityID = _source.GetRelStart(relEntityID);
|
||||
ref RelNodesInfo relInfo = ref _relNodesMapping[relEntityID];
|
||||
_startBaskets.RemoveFromBasket(startEntityID, relInfo.endNodeIndex);
|
||||
_startBaskets.RemoveNextNodeFromBasket(startEntityID, relInfo.endNodeIndex);
|
||||
}
|
||||
_endBaskets.RemoveBasket(endEntityID);
|
||||
}
|
||||
@ -198,7 +199,6 @@ namespace DCFApixels.DragonECS
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void DelStartAndDelRelEntities(int startEntityID, EcsArc arc)
|
||||
{
|
||||
|
||||
foreach (var relEntityID in _startBaskets.GetBasketIterator(startEntityID))
|
||||
{
|
||||
arc.ArcWorld.TryDelEntity(relEntityID);
|
||||
@ -214,25 +214,29 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
public struct FriendEcsArc
|
||||
{
|
||||
private EcsGraph _join;
|
||||
public readonly EcsGraph join;
|
||||
public FriendEcsArc(EcsArc arc, EcsGraph join)
|
||||
{
|
||||
if (arc.IsInit_Internal != false)
|
||||
{
|
||||
Throw.UndefinedException();
|
||||
}
|
||||
_join = join;
|
||||
if(join == null)
|
||||
{
|
||||
Throw.ArgumentNull();
|
||||
}
|
||||
this.join = join;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void DelStartAndDelRelEntities(int startEntityID, EcsArc arc)
|
||||
{
|
||||
_join.DelStartAndDelRelEntities(startEntityID, arc);
|
||||
join.DelStartAndDelRelEntities(startEntityID, arc);
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void DelEndAndDelRelEntities(int endEntityID, EcsArc arc)
|
||||
{
|
||||
_join.DelEndAndDelRelEntities(endEntityID, arc);
|
||||
join.DelEndAndDelRelEntities(endEntityID, arc);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@ -244,11 +248,11 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
public bool HasStart(int startEntityID)
|
||||
{
|
||||
return _startBaskets.GetBasketNodesCount(startEntityID) > 0;
|
||||
return _startBaskets.HasBasket(startEntityID);
|
||||
}
|
||||
public bool HasEnd(int endEntityID)
|
||||
{
|
||||
return _endBaskets.GetBasketNodesCount(endEntityID) > 0;
|
||||
return _endBaskets.HasBasket(endEntityID);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@ -104,17 +104,31 @@ namespace DCFApixels.DragonECS.Relations.Internal
|
||||
}
|
||||
internal static unsafe class UnmanagedArrayUtility
|
||||
{
|
||||
public static readonly int PtrSize = sizeof(IntPtr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T** NewPointersArray<T>(int capacity) where T : unmanaged
|
||||
{
|
||||
return (T**)Marshal.AllocHGlobal(capacity * PtrSize).ToPointer();
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T* New<T>(int capacity) where T : unmanaged
|
||||
{
|
||||
return (T*)Marshal.AllocHGlobal(Marshal.SizeOf<T>() * capacity).ToPointer();
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void New<T>(out T* ptr, int capacity) where T : unmanaged
|
||||
public static T** NewAndInitPointersArray<T>(int capacity) where T : unmanaged
|
||||
{
|
||||
ptr = (T*)Marshal.AllocHGlobal(Marshal.SizeOf<T>(default) * capacity).ToPointer();
|
||||
int newSize = PtrSize * capacity;
|
||||
T** newPointer = (T**)Marshal.AllocHGlobal(newSize).ToPointer();
|
||||
|
||||
for (int i = 0; i < newSize; i++)
|
||||
{
|
||||
*(newPointer + i) = null;
|
||||
}
|
||||
|
||||
return newPointer;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T* NewAndInit<T>(int capacity) where T : unmanaged
|
||||
{
|
||||
@ -122,21 +136,13 @@ namespace DCFApixels.DragonECS.Relations.Internal
|
||||
byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
|
||||
|
||||
for (int i = 0; i < newSize; i++)
|
||||
{
|
||||
*(newPointer + i) = 0;
|
||||
}
|
||||
|
||||
return (T*)newPointer;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void NewAndInit<T>(out T* ptr, int capacity) where T : unmanaged
|
||||
{
|
||||
int newSize = Marshal.SizeOf(typeof(T)) * capacity;
|
||||
byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
|
||||
|
||||
for (int i = 0; i < newSize; i++)
|
||||
*(newPointer + i) = 0;
|
||||
|
||||
ptr = (T*)newPointer;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Free(void* pointer)
|
||||
@ -144,6 +150,13 @@ namespace DCFApixels.DragonECS.Relations.Internal
|
||||
Marshal.FreeHGlobal(new IntPtr(pointer));
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void FreePointersArray<T>(ref T** pointer, ref int length) where T : unmanaged
|
||||
{
|
||||
Marshal.FreeHGlobal(new IntPtr(pointer));
|
||||
pointer = null;
|
||||
length = 0;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Free<T>(ref T* pointer, ref int length) where T : unmanaged
|
||||
{
|
||||
Marshal.FreeHGlobal(new IntPtr(pointer));
|
||||
@ -151,6 +164,16 @@ namespace DCFApixels.DragonECS.Relations.Internal
|
||||
length = 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T** ClonePointersArray<T>(T** sourcePtr, int length) where T : unmanaged
|
||||
{
|
||||
T** clone = NewPointersArray<T>(length);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
clone[i] = sourcePtr[i];
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T* Clone<T>(T* sourcePtr, int length) where T : unmanaged
|
||||
{
|
||||
@ -162,6 +185,13 @@ namespace DCFApixels.DragonECS.Relations.Internal
|
||||
return clone;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T** ResizePointersArray<T>(T** oldPointer, int newCount) where T : unmanaged
|
||||
{
|
||||
return (T**)Marshal.ReAllocHGlobal(
|
||||
new IntPtr(oldPointer),
|
||||
new IntPtr(PtrSize * newCount)).ToPointer();
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T* Resize<T>(void* oldPointer, int newCount) where T : unmanaged
|
||||
{
|
||||
@ -170,6 +200,30 @@ namespace DCFApixels.DragonECS.Relations.Internal
|
||||
new IntPtr(Marshal.SizeOf<T>(default) * newCount)).ToPointer();
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T** ResizeAndInitPointersArray<T>(T** oldPointer, int oldSize, int newSize) where T : unmanaged
|
||||
{
|
||||
int newByteSize = PtrSize * newSize;
|
||||
T** result = (T**)Marshal.ReAllocHGlobal((IntPtr)(oldPointer), newByteSize);
|
||||
|
||||
for (int i = oldSize; i < newSize; i++)
|
||||
{
|
||||
result[i] = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
//public static void* ResizeAndInitPointersArray(void* oldPointer, int oldSize, int newSize)
|
||||
//{
|
||||
// int newByteSize = PtrSize * newSize;
|
||||
// void** result = (void**)Marshal.ReAllocHGlobal((IntPtr)(oldPointer), newByteSize);
|
||||
//
|
||||
// for (int i = oldSize; i < newSize; i++)
|
||||
// {
|
||||
// result[i] = null;
|
||||
// }
|
||||
// return result;
|
||||
//}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T* ResizeAndInit<T>(void* oldPointer, int oldSize, int newSize) where T : unmanaged
|
||||
{
|
||||
int sizeT = Marshal.SizeOf<T>(default);
|
||||
@ -180,6 +234,8 @@ namespace DCFApixels.DragonECS.Relations.Internal
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void Init(byte* pointer, int startByteIndex, int endByteIndex)
|
||||
{
|
||||
|
||||
@ -1,21 +1,22 @@
|
||||
using System;
|
||||
using DCFApixels.DragonECS.Relations.Internal;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||
internal class BasketList
|
||||
internal unsafe 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 UnsafePointersArray<BasketNode> _basketNodePointers;
|
||||
private UnsafeArray<Node> _nodes;
|
||||
private int _recycledListHead = NULL;
|
||||
|
||||
#region Constructors
|
||||
public BasketList() : this(16) { }
|
||||
@ -32,18 +33,28 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
_nodes[i].next = 0;
|
||||
}
|
||||
for (int i = 0; i < _baskets.Length; i++)
|
||||
for (int i = 0; i < _basketNodePointers.Length; i++)
|
||||
{
|
||||
_baskets[i] = default;
|
||||
_basketNodePointers[i] = BasketNode.EmptyInstancePtr;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private void Resize(int newSize)
|
||||
private void ResizeNodes(int newSize)
|
||||
{
|
||||
int oldSize = _nodes.Length;
|
||||
Array.Resize(ref _nodes, newSize);
|
||||
int leftNode = newSize - 1;
|
||||
IntPtr offset = (IntPtr)_nodes.ptr;
|
||||
UnsafeArray.Resize(ref _nodes, newSize);
|
||||
offset = ((IntPtr)_nodes.ptr - offset) / 8;
|
||||
|
||||
for (int i = 0; i < _basketNodePointers.Length; i++)
|
||||
{
|
||||
if (_basketNodePointers[i] != BasketNode.EmptyInstancePtr)
|
||||
{
|
||||
_basketNodePointers.ptr[i] += offset;
|
||||
}
|
||||
}
|
||||
int leftNode = NULL;
|
||||
for (int i = oldSize; i < newSize; i++)
|
||||
{
|
||||
Link(i, leftNode);
|
||||
@ -54,8 +65,13 @@ namespace DCFApixels.DragonECS
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private void Initialize(int newSize)
|
||||
{
|
||||
_nodes = new Node[newSize];
|
||||
int leftNode = newSize - 1;
|
||||
_basketNodePointers = new UnsafePointersArray<BasketNode>(64);
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
_basketNodePointers[i] = BasketNode.EmptyInstancePtr;
|
||||
}
|
||||
_nodes = new UnsafeArray<Node>(newSize, true);
|
||||
int leftNode = NULL;
|
||||
for (int i = 1; i < newSize; i++)
|
||||
{
|
||||
Link(i, leftNode);
|
||||
@ -64,10 +80,14 @@ namespace DCFApixels.DragonECS
|
||||
LinkToRecycled(newSize - 1, 1);
|
||||
}
|
||||
|
||||
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
//public int GetBasketNodesCount(int basketIndex)
|
||||
//{
|
||||
//}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int GetBasketNodesCount(int basketIndex)
|
||||
public bool HasBasket(int basketIndex)
|
||||
{
|
||||
return _baskets[basketIndex].count;
|
||||
return _basketNodePointers[basketIndex] != BasketNode.EmptyInstancePtr;
|
||||
}
|
||||
|
||||
|
||||
@ -89,188 +109,210 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void RemoveFromBasket(int basketIndex, int nodeIndex)
|
||||
public void RemoveNextNodeFromBasket(int basketIndex, int prevNodeIndex) // +
|
||||
{
|
||||
#if DEBUG
|
||||
if (nodeIndex <= 0)
|
||||
if (prevNodeIndex <= 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)
|
||||
ref BasketNode* basketNode = ref _basketNodePointers[basketIndex];
|
||||
if (basketNode == BasketNode.EmptyInstancePtr)
|
||||
{
|
||||
basketInfo.nodeIndex = nextNode;
|
||||
//Поидее тут не должно быть пусто
|
||||
Throw.UndefinedException();
|
||||
}
|
||||
|
||||
int targetNodeIndex = _nodes[prevNodeIndex].next;
|
||||
int nextNodeIndex = _nodes[targetNodeIndex].next;
|
||||
|
||||
if(targetNodeIndex == 15)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Link(prevNodeIndex, nextNodeIndex);
|
||||
LinkToRecycled(targetNodeIndex);
|
||||
|
||||
if (basketNode->nodeIndex == targetNodeIndex)
|
||||
{
|
||||
basketNode->nodeIndex = nextNodeIndex;
|
||||
}
|
||||
if (--basketNode->count <= 0)
|
||||
{
|
||||
LinkToRecycled(prevNodeIndex);
|
||||
basketNode = BasketNode.EmptyInstancePtr;
|
||||
}
|
||||
basketInfo.count--;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int AddToBasket(int basketIndex, int value)
|
||||
private void CreateBasket(ref BasketNode* toPointer) // +
|
||||
{
|
||||
ref BasketInfo basketInfo = ref _baskets[basketIndex];
|
||||
toPointer = (BasketNode*)TakeRecycledNodePtr();
|
||||
*toPointer = BasketNode.Empty;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int AddToBasket(int basketIndex, int value) // +
|
||||
{
|
||||
ref BasketNode* basketNode = ref _basketNodePointers[basketIndex];
|
||||
int prevNodeIndex;
|
||||
int newNodeIndex = TakeRecycledNode();
|
||||
if (basketInfo.count == 0)
|
||||
if (basketNode == BasketNode.EmptyInstancePtr)
|
||||
{
|
||||
//_nodes[newNodeIndex].Set(value, 0, 0);
|
||||
CreateBasket(ref basketNode);
|
||||
prevNodeIndex = (int)((Node*)basketNode - _nodes.ptr);
|
||||
_nodes[newNodeIndex].value = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// int nextNodeIndex = basketInfo.nodeIndex;
|
||||
// //_nodes[newNodeIndex].Set(value, 0, nextNodeIndex);
|
||||
// _nodes[newNodeIndex].Set_Value_Next(value, nextNodeIndex);
|
||||
// //_nodes[nextNodeIndex].prev = newNodeIndex;
|
||||
_nodes[newNodeIndex].Set_Value_Next(value, basketInfo.nodeIndex);
|
||||
_nodes[newNodeIndex].Set(value, basketNode->nodeIndex);
|
||||
prevNodeIndex = basketNode->nodeIndex;
|
||||
}
|
||||
basketInfo.nodeIndex = newNodeIndex;
|
||||
basketInfo.count++;
|
||||
return newNodeIndex;
|
||||
basketNode->nodeIndex = newNodeIndex;
|
||||
basketNode->count++;
|
||||
return prevNodeIndex;
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private int TakeRecycledNode()
|
||||
private Node* TakeRecycledNodePtr() // +
|
||||
{
|
||||
if (_recycledListLast == -1)
|
||||
if (_recycledListHead == NULL)
|
||||
{
|
||||
Resize(_nodes.Length << 1);
|
||||
ResizeNodes(_nodes.Length << 1);
|
||||
}
|
||||
int resultNode = _recycledListLast;
|
||||
_recycledListLast = _nodes[resultNode].prev;
|
||||
Node* resultNode = _nodes.ptr + _recycledListHead;
|
||||
_recycledListHead = resultNode->next;
|
||||
resultNode->next = 0;
|
||||
return resultNode;
|
||||
}
|
||||
//[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)
|
||||
private int TakeRecycledNode() // +
|
||||
{
|
||||
if (_recycledListHead == NULL)
|
||||
{
|
||||
ResizeNodes(_nodes.Length << 1);
|
||||
}
|
||||
int resultNode = _recycledListHead;
|
||||
_recycledListHead = _nodes[resultNode].next;
|
||||
_nodes[resultNode].next = 0;
|
||||
return resultNode;
|
||||
}
|
||||
|
||||
[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)
|
||||
private void LinkToRecycled(int nodeIndex) // +
|
||||
{
|
||||
if (_recycledListLast <= -1)
|
||||
if(nodeIndex == 15)
|
||||
{
|
||||
_nodes[startNodeIndex].prev = RECYCLE;
|
||||
|
||||
}
|
||||
if (_recycledListHead >= 0)
|
||||
{
|
||||
_nodes[nodeIndex].next = _recycledListHead;
|
||||
}
|
||||
else
|
||||
{
|
||||
Link(_recycledListLast, startNodeIndex);
|
||||
_nodes[nodeIndex].next = 0;
|
||||
}
|
||||
_recycledListLast = endNodeIndex;
|
||||
_recycledListHead = nodeIndex;
|
||||
|
||||
int i = 0;
|
||||
int cureNodeIndex = _recycledListHead;
|
||||
while (cureNodeIndex != NULL)
|
||||
{
|
||||
int nextNodeIndex = _nodes[cureNodeIndex].next;
|
||||
if (i > _nodes.Length)
|
||||
{
|
||||
Console.WriteLine("WTF");
|
||||
}
|
||||
cureNodeIndex = nextNodeIndex;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void LinkToRecycled(int startNodeIndex, int endNodeIndex) // +
|
||||
{
|
||||
if (_recycledListHead >= 0)
|
||||
{
|
||||
_nodes[endNodeIndex].next = _recycledListHead;
|
||||
}
|
||||
_recycledListHead = startNodeIndex;
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void RemoveBasket(int basketIndex)
|
||||
public void RemoveBasket(int basketIndex) // +
|
||||
{
|
||||
ref BasketInfo basket = ref _baskets[basketIndex];
|
||||
ref BasketNode* basketNode = ref _basketNodePointers[basketIndex];
|
||||
if (basketNode == null) { Throw.UndefinedException(); }
|
||||
|
||||
int startNodeIndex = basket.nodeIndex;
|
||||
int endNodeIndex = startNodeIndex;
|
||||
ref Node startNode = ref _nodes[startNodeIndex];
|
||||
for (int i = 0, n = basket.count; i < n; i++)
|
||||
int startBasketNodeIndex = (int)(basketNode - (BasketNode*)_nodes.ptr);
|
||||
|
||||
int endNodeIndex = startBasketNodeIndex;
|
||||
for (int i = 0, n = basketNode->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;
|
||||
LinkToRecycled(startBasketNodeIndex, endNodeIndex);
|
||||
basketNode = BasketNode.EmptyInstancePtr;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public void UpBasketsSize(int minSize)
|
||||
{
|
||||
if (minSize > _baskets.Length)
|
||||
if (minSize > _basketNodePointers.Length)
|
||||
{
|
||||
int newSize = 1 << (GetHighBitNumber((uint)minSize - 1) + 1);
|
||||
Array.Resize(ref _baskets, newSize);
|
||||
}
|
||||
}
|
||||
private static int GetHighBitNumber(uint bits)
|
||||
int newSize = ArrayUtility.NormalizeSizeToPowerOfTwo(minSize);
|
||||
int oldSize = _basketNodePointers.Length;
|
||||
UnsafePointersArray.Resize(ref _basketNodePointers, newSize);
|
||||
for (int i = oldSize; i < newSize; i++)
|
||||
{
|
||||
if (bits == 0)
|
||||
{
|
||||
return -1;
|
||||
_basketNodePointers[i] = BasketNode.EmptyInstancePtr;
|
||||
}
|
||||
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
|
||||
[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;
|
||||
/// <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 Set_Value_Next(int value, int next)
|
||||
public void Set(int value, int next)
|
||||
{
|
||||
this.value = value;
|
||||
this.next = next;
|
||||
}
|
||||
public override string ToString() => $"node({prev}<>{next} v:{value})";
|
||||
public override string ToString() => $"node(>{next} v:{value})";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region BasketInfo
|
||||
private struct BasketInfo
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)]
|
||||
private struct BasketNode
|
||||
{
|
||||
public static readonly BasketInfo Empty = new BasketInfo() { nodeIndex = 0, count = 0, };
|
||||
public int nodeIndex;
|
||||
public static readonly BasketNode Empty = new BasketNode() { nodeIndex = 0, count = 0, };
|
||||
public static BasketNode* EmptyInstancePtr;
|
||||
static BasketNode()
|
||||
{
|
||||
void* ptr = (void*)Marshal.AllocHGlobal(Marshal.SizeOf<BasketNode>(default));
|
||||
EmptyInstancePtr = (BasketNode*)ptr;
|
||||
*EmptyInstancePtr = default;
|
||||
}
|
||||
public int count;
|
||||
public int nodeIndex;
|
||||
public override string ToString() => $"basket_info(i:{nodeIndex} c:{count})";
|
||||
|
||||
private static BasketNode* EmptyInstancePtr_Debug => EmptyInstancePtr;
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -291,7 +333,7 @@ namespace DCFApixels.DragonECS
|
||||
private readonly int _basketIndex;
|
||||
public int Count
|
||||
{
|
||||
get { return _basketList._baskets[_basketIndex].count; }
|
||||
get { return _basketList._basketNodePointers[_basketIndex]->count; }
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@ -307,18 +349,19 @@ 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;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Enumerator(BasketIterator iterator)
|
||||
{
|
||||
ref BasketInfo basketInfo = ref iterator._basketList._baskets[iterator._basketIndex];
|
||||
BasketNode* basketNode = iterator._basketList._basketNodePointers[iterator._basketIndex];
|
||||
|
||||
_nodes = iterator._basketList._nodes;
|
||||
_nodeIndex = -1;
|
||||
_nextNodeIndex = basketInfo.nodeIndex;
|
||||
_count = basketInfo.count;
|
||||
_nextNodeIndex = basketNode->nodeIndex;
|
||||
_count = basketNode->count;
|
||||
}
|
||||
public int Current
|
||||
{
|
||||
@ -351,33 +394,40 @@ namespace DCFApixels.DragonECS
|
||||
get
|
||||
{
|
||||
List<BasketIteratorDebbugerProxy> result = new List<BasketIteratorDebbugerProxy>();
|
||||
for (int i = 0; i < _basketList._baskets.Length; i++)
|
||||
for (int i = 0; i < _basketList._basketNodePointers.Length; i++)
|
||||
{
|
||||
if (_basketList._baskets[i].count > 0)
|
||||
if (_basketList._basketNodePointers[i] != BasketNode.EmptyInstancePtr)
|
||||
{
|
||||
result.Add(new BasketIteratorDebbugerProxy(_basketList[i]));
|
||||
result.Add(new BasketIteratorDebbugerProxy(i, _basketList[i]));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public int RecycledListHead => _basketList._recycledListHead;
|
||||
public IEnumerable<Node> Recycled
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Node> result = new List<Node>();
|
||||
Node curNode = new Node();
|
||||
curNode.index = _basketList._recycledListLast;
|
||||
curNode.index = _basketList._recycledListHead;
|
||||
|
||||
while (curNode.index != -1)
|
||||
int i = 0;
|
||||
while (curNode.index != NULL)
|
||||
{
|
||||
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;
|
||||
if (i++ > _basketList._nodes.Length)
|
||||
{
|
||||
result.Add(new Node(int.MinValue, int.MinValue, int.MinValue));
|
||||
break;
|
||||
}
|
||||
|
||||
curNode.index = curNode.next;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -390,51 +440,97 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
for (int i = 0; i < _basketList._nodes.Length; i++)
|
||||
{
|
||||
result.Add(new Node(_basketList._nodes[i].prev, i, _basketList._nodes[i].next));
|
||||
result.Add(new Node(i, _basketList._nodes[i].value, _basketList._nodes[i].next));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
public Node[][] Chains
|
||||
{
|
||||
get
|
||||
{
|
||||
//bool IsChainLoop(int checkedNodeIndex)
|
||||
//{
|
||||
// bool result = false;
|
||||
// int currentCheckedNodeIndex = checkedNodeIndex;
|
||||
// for (int i = 0; i <= _basketList._nodes.Length; i++)
|
||||
// {
|
||||
// if (currentCheckedNodeIndex == 0)
|
||||
// {
|
||||
// result = true;
|
||||
// }
|
||||
// currentCheckedNodeIndex = _basketList._nodes[currentCheckedNodeIndex].next;
|
||||
// }
|
||||
// return result;
|
||||
//}
|
||||
List<Stack<int>> chains = new List<Stack<int>>();
|
||||
for (int i = 1; i < _basketList._nodes.Length; i++)
|
||||
{
|
||||
if (_basketList._nodes[i].next == 0)
|
||||
{
|
||||
Stack<int> chain = new Stack<int>();
|
||||
int lastNext = i;
|
||||
chain.Push(lastNext);
|
||||
|
||||
for (int queueX = 1; queueX < _basketList._nodes.Length; queueX++)
|
||||
{
|
||||
for (int j = 1; j < _basketList._nodes.Length; j++)
|
||||
{
|
||||
var nodeJ = _basketList._nodes[j];
|
||||
if(nodeJ.next == lastNext)
|
||||
{
|
||||
lastNext = j;
|
||||
chain.Push(lastNext);
|
||||
}
|
||||
}
|
||||
}
|
||||
chains.Add(chain);
|
||||
}
|
||||
}
|
||||
var nodes = _basketList._nodes;
|
||||
return chains.Select(
|
||||
o => o.Select(o => new Node(o, nodes[o].value, nodes[o].next)).ToArray()
|
||||
).ToArray();
|
||||
}
|
||||
}
|
||||
public DebuggerProxy(BasketList basketList)
|
||||
{
|
||||
_basketList = basketList;
|
||||
}
|
||||
public struct Node
|
||||
{
|
||||
public int prev;
|
||||
public int index;
|
||||
public int value;
|
||||
public int next;
|
||||
public Node(int prev, int index, int next)
|
||||
public Node(int index, int value, int next)
|
||||
{
|
||||
this.prev = prev;
|
||||
this.index = index;
|
||||
this.value = value;
|
||||
this.next = next;
|
||||
}
|
||||
public override string ToString() => $"node({prev}< {index} >{next})";
|
||||
public override string ToString() => $"[{index}] {value} >{next}";
|
||||
}
|
||||
public struct BasketIteratorDebbugerProxy
|
||||
{
|
||||
public int index;
|
||||
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);
|
||||
}
|
||||
List<int> result = new List<int>(_iterrator);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
public BasketIteratorDebbugerProxy(BasketIterator iterrator)
|
||||
public BasketIteratorDebbugerProxy(int index, BasketIterator iterrator)
|
||||
{
|
||||
this.index = index;
|
||||
_iterrator = iterrator;
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return $"count: {_iterrator.Count}";
|
||||
return $"[{index}] count: {_iterrator.Count}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
|
||||
namespace DCFApixels.DragonECS.Relations.Internal
|
||||
{
|
||||
@ -32,19 +33,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 +76,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 +121,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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
118
src/Utils/UnsafePointersArray.cs
Normal file
118
src/Utils/UnsafePointersArray.cs
Normal file
@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DCFApixels.DragonECS.Relations.Internal
|
||||
{
|
||||
internal unsafe static class UnsafePointersArray
|
||||
{
|
||||
public static void Resize<T>(ref UnsafePointersArray<T> array, int newSize)
|
||||
where T : unmanaged
|
||||
{
|
||||
array.ptr = (T**)UnmanagedArrayUtility.Resize<IntPtr>(array.ptr, newSize);
|
||||
array.Length = newSize;
|
||||
}
|
||||
public static void ResizeAndInit<T>(ref UnsafePointersArray<T> array, int newSize)
|
||||
where T : unmanaged
|
||||
{
|
||||
array.ptr = (T**)UnmanagedArrayUtility.ResizeAndInit<IntPtr>(array.ptr, array.Length, newSize);
|
||||
array.Length = newSize;
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerTypeProxy(typeof(UnsafePointersArray<>.DebuggerProxy))]
|
||||
internal unsafe struct UnsafePointersArray<T> : IDisposable
|
||||
where T : unmanaged
|
||||
{
|
||||
internal T** ptr;
|
||||
internal int Length;
|
||||
|
||||
public ref T* this[int index]
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get
|
||||
{
|
||||
#if DEBUG
|
||||
if (index < 0 || index >= Length)
|
||||
Throw.ArgumentOutOfRange();
|
||||
#endif
|
||||
return ref ptr[index];
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public UnsafePointersArray(int length)
|
||||
{
|
||||
ptr = (T**)UnmanagedArrayUtility.New<IntPtr>(length);
|
||||
Length = length;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public UnsafePointersArray(int length, bool isInit)
|
||||
{
|
||||
ptr = (T**)UnmanagedArrayUtility.NewAndInit<IntPtr>(length);
|
||||
Length = length;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private UnsafePointersArray(T** ptr, int length)
|
||||
{
|
||||
this.ptr = ptr;
|
||||
Length = length;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public UnsafePointersArray<T> Clone()
|
||||
{
|
||||
return new UnsafePointersArray<T>(UnmanagedArrayUtility.ClonePointersArray(ptr, Length), Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Dispose()
|
||||
{
|
||||
UnmanagedArrayUtility.FreePointersArray(ref ptr, ref Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Enumerator GetEnumerator() => new Enumerator(ptr, Length);
|
||||
public struct Enumerator
|
||||
{
|
||||
private readonly T** _ptr;
|
||||
private readonly int _length;
|
||||
private int _index;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Enumerator(T** ptr, int length)
|
||||
{
|
||||
_ptr = ptr;
|
||||
_length = length;
|
||||
_index = -1;
|
||||
}
|
||||
public T* Current
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _ptr[_index];
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext() => ++_index < _length;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Reset() { }
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
internal class DebuggerProxy
|
||||
{
|
||||
public void* ptr;
|
||||
public T*[] elements;
|
||||
public int length;
|
||||
public DebuggerProxy(UnsafePointersArray<T> instance)
|
||||
{
|
||||
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