From 5ee2f6a0a69918a32efe10b182fce7a1c413b429 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Mon, 5 Feb 2024 18:32:20 +0800 Subject: [PATCH] stash/ not work --- src/Collections/EcsGraph.cs | 26 +- src/Utils/ArrayUtility.cs | 82 ++++++- src/Utils/BasketList.cs | 392 +++++++++++++++++++------------ src/Utils/UnsafeArray.cs | 26 +- src/Utils/UnsafePointersArray.cs | 118 ++++++++++ 5 files changed, 466 insertions(+), 178 deletions(-) create mode 100644 src/Utils/UnsafePointersArray.cs diff --git a/src/Collections/EcsGraph.cs b/src/Collections/EcsGraph.cs index 21c4227..22371cb 100644 --- a/src/Collections/EcsGraph.cs +++ b/src/Collections/EcsGraph.cs @@ -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 diff --git a/src/Utils/ArrayUtility.cs b/src/Utils/ArrayUtility.cs index fee8b84..18f57d4 100644 --- a/src/Utils/ArrayUtility.cs +++ b/src/Utils/ArrayUtility.cs @@ -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(int capacity) where T : unmanaged + { + return (T**)Marshal.AllocHGlobal(capacity * PtrSize).ToPointer(); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T* New(int capacity) where T : unmanaged { return (T*)Marshal.AllocHGlobal(Marshal.SizeOf() * capacity).ToPointer(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void New(out T* ptr, int capacity) where T : unmanaged + public static T** NewAndInitPointersArray(int capacity) where T : unmanaged { - ptr = (T*)Marshal.AllocHGlobal(Marshal.SizeOf(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(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(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(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(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** sourcePtr, int length) where T : unmanaged + { + T** clone = NewPointersArray(length); + for (int i = 0; i < length; i++) + { + clone[i] = sourcePtr[i]; + } + return clone; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T* Clone(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** 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(void* oldPointer, int newCount) where T : unmanaged { @@ -170,6 +200,30 @@ namespace DCFApixels.DragonECS.Relations.Internal new IntPtr(Marshal.SizeOf(default) * newCount)).ToPointer(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T** ResizeAndInitPointersArray(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(void* oldPointer, int oldSize, int newSize) where T : unmanaged { int sizeT = Marshal.SizeOf(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) { diff --git a/src/Utils/BasketList.cs b/src/Utils/BasketList.cs index 4b80652..25a3df4 100644 --- a/src/Utils/BasketList.cs +++ b/src/Utils/BasketList.cs @@ -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 _basketNodePointers; + private UnsafeArray _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(64); + for (int i = 0; i < 64; i++) + { + _basketNodePointers[i] = BasketNode.EmptyInstancePtr; + } + _nodes = new UnsafeArray(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); + int newSize = ArrayUtility.NormalizeSizeToPowerOfTwo(minSize); + int oldSize = _basketNodePointers.Length; + UnsafePointersArray.Resize(ref _basketNodePointers, newSize); + for (int i = oldSize; i < newSize; i++) + { + _basketNodePointers[i] = BasketNode.EmptyInstancePtr; + } } } - 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; - } + #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; /// next node index public int next; - /// prev node index - 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(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 { - private readonly Node[] _nodes; + private readonly UnsafeArray _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 result = new List(); - 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 Recycled { get { List result = new List(); 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> chains = new List>(); + for (int i = 1; i < _basketList._nodes.Length; i++) + { + if (_basketList._nodes[i].next == 0) + { + Stack chain = new Stack(); + 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 RelEntities { get { - List result = new List(); - foreach (var e in _iterrator) - { - result.Add(e); - } + List result = new List(_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}"; } } } diff --git a/src/Utils/UnsafeArray.cs b/src/Utils/UnsafeArray.cs index 5339824..d2631db 100644 --- a/src/Utils/UnsafeArray.cs +++ b/src/Utils/UnsafeArray.cs @@ -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(length); Length = length; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public UnsafeArray(int length, bool isInit) { - UnmanagedArrayUtility.NewAndInit(out ptr, length); + ptr = UnmanagedArrayUtility.NewAndInit(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 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 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]; + } } } } diff --git a/src/Utils/UnsafePointersArray.cs b/src/Utils/UnsafePointersArray.cs new file mode 100644 index 0000000..dbdfa45 --- /dev/null +++ b/src/Utils/UnsafePointersArray.cs @@ -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(ref UnsafePointersArray array, int newSize) + where T : unmanaged + { + array.ptr = (T**)UnmanagedArrayUtility.Resize(array.ptr, newSize); + array.Length = newSize; + } + public static void ResizeAndInit(ref UnsafePointersArray array, int newSize) + where T : unmanaged + { + array.ptr = (T**)UnmanagedArrayUtility.ResizeAndInit(array.ptr, array.Length, newSize); + array.Length = newSize; + } + } + + [DebuggerTypeProxy(typeof(UnsafePointersArray<>.DebuggerProxy))] + internal unsafe struct UnsafePointersArray : 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(length); + Length = length; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public UnsafePointersArray(int length, bool isInit) + { + ptr = (T**)UnmanagedArrayUtility.NewAndInit(length); + Length = length; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private UnsafePointersArray(T** ptr, int length) + { + this.ptr = ptr; + Length = length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public UnsafePointersArray Clone() + { + return new UnsafePointersArray(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 instance) + { + ptr = instance.ptr; + length = instance.Length; + elements = new T*[length]; + for (int i = 0; i < length; i++) + { + elements[i] = instance[i]; + } + } + } + } +}