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)
|
public void Del(int relEntityID)
|
||||||
{
|
{
|
||||||
var (startEntityID, _) = _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.RemoveNextNodeFromBasket(startEntityID, relInfo.startNodeIndex);
|
||||||
|
_endBaskets.RemoveNextNodeFromBasket(endEntityID, relInfo.endNodeIndex);
|
||||||
}
|
}
|
||||||
public void DelStart(int startEntityID)
|
public void DelStart(int startEntityID)
|
||||||
{
|
{
|
||||||
@ -179,7 +180,7 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
var endEntityID = _source.GetRelEnd(relEntityID);
|
var endEntityID = _source.GetRelEnd(relEntityID);
|
||||||
ref RelNodesInfo relInfo = ref _relNodesMapping[relEntityID];
|
ref RelNodesInfo relInfo = ref _relNodesMapping[relEntityID];
|
||||||
_endBaskets.RemoveFromBasket(endEntityID, relInfo.startNodeIndex);
|
_endBaskets.RemoveNextNodeFromBasket(endEntityID, relInfo.startNodeIndex);
|
||||||
}
|
}
|
||||||
_startBaskets.RemoveBasket(startEntityID);
|
_startBaskets.RemoveBasket(startEntityID);
|
||||||
}
|
}
|
||||||
@ -189,7 +190,7 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
var startEntityID = _source.GetRelStart(relEntityID);
|
var startEntityID = _source.GetRelStart(relEntityID);
|
||||||
ref RelNodesInfo relInfo = ref _relNodesMapping[relEntityID];
|
ref RelNodesInfo relInfo = ref _relNodesMapping[relEntityID];
|
||||||
_startBaskets.RemoveFromBasket(startEntityID, relInfo.endNodeIndex);
|
_startBaskets.RemoveNextNodeFromBasket(startEntityID, relInfo.endNodeIndex);
|
||||||
}
|
}
|
||||||
_endBaskets.RemoveBasket(endEntityID);
|
_endBaskets.RemoveBasket(endEntityID);
|
||||||
}
|
}
|
||||||
@ -198,7 +199,6 @@ namespace DCFApixels.DragonECS
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void DelStartAndDelRelEntities(int startEntityID, EcsArc arc)
|
private void DelStartAndDelRelEntities(int startEntityID, EcsArc arc)
|
||||||
{
|
{
|
||||||
|
|
||||||
foreach (var relEntityID in _startBaskets.GetBasketIterator(startEntityID))
|
foreach (var relEntityID in _startBaskets.GetBasketIterator(startEntityID))
|
||||||
{
|
{
|
||||||
arc.ArcWorld.TryDelEntity(relEntityID);
|
arc.ArcWorld.TryDelEntity(relEntityID);
|
||||||
@ -214,25 +214,29 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
public struct FriendEcsArc
|
public struct FriendEcsArc
|
||||||
{
|
{
|
||||||
private EcsGraph _join;
|
public readonly EcsGraph join;
|
||||||
public FriendEcsArc(EcsArc arc, EcsGraph join)
|
public FriendEcsArc(EcsArc arc, EcsGraph join)
|
||||||
{
|
{
|
||||||
if (arc.IsInit_Internal != false)
|
if (arc.IsInit_Internal != false)
|
||||||
{
|
{
|
||||||
Throw.UndefinedException();
|
Throw.UndefinedException();
|
||||||
}
|
}
|
||||||
_join = join;
|
if(join == null)
|
||||||
|
{
|
||||||
|
Throw.ArgumentNull();
|
||||||
|
}
|
||||||
|
this.join = join;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void DelStartAndDelRelEntities(int startEntityID, EcsArc arc)
|
public void DelStartAndDelRelEntities(int startEntityID, EcsArc arc)
|
||||||
{
|
{
|
||||||
_join.DelStartAndDelRelEntities(startEntityID, arc);
|
join.DelStartAndDelRelEntities(startEntityID, arc);
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void DelEndAndDelRelEntities(int endEntityID, EcsArc arc)
|
public void DelEndAndDelRelEntities(int endEntityID, EcsArc arc)
|
||||||
{
|
{
|
||||||
_join.DelEndAndDelRelEntities(endEntityID, arc);
|
join.DelEndAndDelRelEntities(endEntityID, arc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@ -244,11 +248,11 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
public bool HasStart(int startEntityID)
|
public bool HasStart(int startEntityID)
|
||||||
{
|
{
|
||||||
return _startBaskets.GetBasketNodesCount(startEntityID) > 0;
|
return _startBaskets.HasBasket(startEntityID);
|
||||||
}
|
}
|
||||||
public bool HasEnd(int endEntityID)
|
public bool HasEnd(int endEntityID)
|
||||||
{
|
{
|
||||||
return _endBaskets.GetBasketNodesCount(endEntityID) > 0;
|
return _endBaskets.HasBasket(endEntityID);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|||||||
@ -104,17 +104,31 @@ namespace DCFApixels.DragonECS.Relations.Internal
|
|||||||
}
|
}
|
||||||
internal static unsafe class UnmanagedArrayUtility
|
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)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static T* New<T>(int capacity) where T : unmanaged
|
public static T* New<T>(int capacity) where T : unmanaged
|
||||||
{
|
{
|
||||||
return (T*)Marshal.AllocHGlobal(Marshal.SizeOf<T>() * capacity).ToPointer();
|
return (T*)Marshal.AllocHGlobal(Marshal.SizeOf<T>() * capacity).ToPointer();
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[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)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static T* NewAndInit<T>(int capacity) where T : unmanaged
|
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();
|
byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
|
||||||
|
|
||||||
for (int i = 0; i < newSize; i++)
|
for (int i = 0; i < newSize; i++)
|
||||||
|
{
|
||||||
*(newPointer + i) = 0;
|
*(newPointer + i) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return (T*)newPointer;
|
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)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void Free(void* pointer)
|
public static void Free(void* pointer)
|
||||||
@ -144,6 +150,13 @@ namespace DCFApixels.DragonECS.Relations.Internal
|
|||||||
Marshal.FreeHGlobal(new IntPtr(pointer));
|
Marshal.FreeHGlobal(new IntPtr(pointer));
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[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
|
public static void Free<T>(ref T* pointer, ref int length) where T : unmanaged
|
||||||
{
|
{
|
||||||
Marshal.FreeHGlobal(new IntPtr(pointer));
|
Marshal.FreeHGlobal(new IntPtr(pointer));
|
||||||
@ -151,6 +164,16 @@ namespace DCFApixels.DragonECS.Relations.Internal
|
|||||||
length = 0;
|
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)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static T* Clone<T>(T* sourcePtr, int length) where T : unmanaged
|
public static T* Clone<T>(T* sourcePtr, int length) where T : unmanaged
|
||||||
{
|
{
|
||||||
@ -162,6 +185,13 @@ namespace DCFApixels.DragonECS.Relations.Internal
|
|||||||
return clone;
|
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)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static T* Resize<T>(void* oldPointer, int newCount) where T : unmanaged
|
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();
|
new IntPtr(Marshal.SizeOf<T>(default) * newCount)).ToPointer();
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[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
|
public static T* ResizeAndInit<T>(void* oldPointer, int oldSize, int newSize) where T : unmanaged
|
||||||
{
|
{
|
||||||
int sizeT = Marshal.SizeOf<T>(default);
|
int sizeT = Marshal.SizeOf<T>(default);
|
||||||
@ -180,6 +234,8 @@ namespace DCFApixels.DragonECS.Relations.Internal
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static void Init(byte* pointer, int startByteIndex, int endByteIndex)
|
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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||||
internal class BasketList
|
internal unsafe class BasketList
|
||||||
{
|
{
|
||||||
public const int RECYCLE = -1;
|
public const int NULL = 0;
|
||||||
public const int HEAD = 0;
|
|
||||||
|
|
||||||
private BasketInfo[] _baskets = new BasketInfo[64];
|
private UnsafePointersArray<BasketNode> _basketNodePointers;
|
||||||
private Node[] _nodes;
|
private UnsafeArray<Node> _nodes;
|
||||||
private int _recycledListLast = -1;
|
private int _recycledListHead = NULL;
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
public BasketList() : this(16) { }
|
public BasketList() : this(16) { }
|
||||||
@ -32,18 +33,28 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
_nodes[i].next = 0;
|
_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)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
private void Resize(int newSize)
|
private void ResizeNodes(int newSize)
|
||||||
{
|
{
|
||||||
int oldSize = _nodes.Length;
|
int oldSize = _nodes.Length;
|
||||||
Array.Resize(ref _nodes, newSize);
|
IntPtr offset = (IntPtr)_nodes.ptr;
|
||||||
int leftNode = newSize - 1;
|
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++)
|
for (int i = oldSize; i < newSize; i++)
|
||||||
{
|
{
|
||||||
Link(i, leftNode);
|
Link(i, leftNode);
|
||||||
@ -54,8 +65,13 @@ namespace DCFApixels.DragonECS
|
|||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
private void Initialize(int newSize)
|
private void Initialize(int newSize)
|
||||||
{
|
{
|
||||||
_nodes = new Node[newSize];
|
_basketNodePointers = new UnsafePointersArray<BasketNode>(64);
|
||||||
int leftNode = newSize - 1;
|
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++)
|
for (int i = 1; i < newSize; i++)
|
||||||
{
|
{
|
||||||
Link(i, leftNode);
|
Link(i, leftNode);
|
||||||
@ -64,10 +80,14 @@ namespace DCFApixels.DragonECS
|
|||||||
LinkToRecycled(newSize - 1, 1);
|
LinkToRecycled(newSize - 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
//public int GetBasketNodesCount(int basketIndex)
|
||||||
|
//{
|
||||||
|
//}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[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)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void RemoveFromBasket(int basketIndex, int nodeIndex)
|
public void RemoveNextNodeFromBasket(int basketIndex, int prevNodeIndex) // +
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (nodeIndex <= 0)
|
if (prevNodeIndex <= 0)
|
||||||
{
|
{
|
||||||
//Throw.ArgumentOutOfRange();
|
//Throw.ArgumentOutOfRange();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
ref BasketInfo basketInfo = ref _baskets[basketIndex];
|
ref BasketNode* basketNode = ref _basketNodePointers[basketIndex];
|
||||||
|
if (basketNode == BasketNode.EmptyInstancePtr)
|
||||||
ref var node = ref _nodes[nodeIndex];
|
|
||||||
int nextNode = node.next;
|
|
||||||
|
|
||||||
Link(node.prev, nextNode);
|
|
||||||
LinkToRecycled(nodeIndex, nodeIndex);
|
|
||||||
if (basketInfo.nodeIndex == nodeIndex)
|
|
||||||
{
|
{
|
||||||
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)]
|
[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();
|
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;
|
_nodes[newNodeIndex].value = value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// int nextNodeIndex = basketInfo.nodeIndex;
|
_nodes[newNodeIndex].Set(value, basketNode->nodeIndex);
|
||||||
// //_nodes[newNodeIndex].Set(value, 0, nextNodeIndex);
|
prevNodeIndex = basketNode->nodeIndex;
|
||||||
// _nodes[newNodeIndex].Set_Value_Next(value, nextNodeIndex);
|
|
||||||
// //_nodes[nextNodeIndex].prev = newNodeIndex;
|
|
||||||
_nodes[newNodeIndex].Set_Value_Next(value, basketInfo.nodeIndex);
|
|
||||||
}
|
}
|
||||||
basketInfo.nodeIndex = newNodeIndex;
|
basketNode->nodeIndex = newNodeIndex;
|
||||||
basketInfo.count++;
|
basketNode->count++;
|
||||||
return newNodeIndex;
|
return prevNodeIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[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;
|
Node* resultNode = _nodes.ptr + _recycledListHead;
|
||||||
_recycledListLast = _nodes[resultNode].prev;
|
_recycledListHead = resultNode->next;
|
||||||
|
resultNode->next = 0;
|
||||||
return resultNode;
|
return resultNode;
|
||||||
}
|
}
|
||||||
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
//private void Separate(int leftNodeIndex, int rightNodeIndex)
|
|
||||||
//{
|
|
||||||
// _nodes[rightNodeIndex].prev = 0;
|
|
||||||
// _nodes[leftNodeIndex].next = 0;
|
|
||||||
//}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[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;
|
_nodes[leftNodeIndex].next = rightNodeIndex;
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[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
|
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)]
|
[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 startBasketNodeIndex = (int)(basketNode - (BasketNode*)_nodes.ptr);
|
||||||
int endNodeIndex = startNodeIndex;
|
|
||||||
ref Node startNode = ref _nodes[startNodeIndex];
|
int endNodeIndex = startBasketNodeIndex;
|
||||||
for (int i = 0, n = basket.count; i < n; i++)
|
for (int i = 0, n = basketNode->count; i < n; i++)
|
||||||
{
|
{
|
||||||
endNodeIndex = _nodes[endNodeIndex].next;
|
endNodeIndex = _nodes[endNodeIndex].next;
|
||||||
}
|
}
|
||||||
ref Node endNode = ref _nodes[endNodeIndex];
|
LinkToRecycled(startBasketNodeIndex, endNodeIndex);
|
||||||
|
basketNode = BasketNode.EmptyInstancePtr;
|
||||||
LinkToRecycled(startNodeIndex, endNodeIndex);
|
|
||||||
Link(startNode.prev, endNode.next);
|
|
||||||
|
|
||||||
basket.count = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public void UpBasketsSize(int minSize)
|
public void UpBasketsSize(int minSize)
|
||||||
{
|
{
|
||||||
if (minSize > _baskets.Length)
|
if (minSize > _basketNodePointers.Length)
|
||||||
{
|
{
|
||||||
int newSize = 1 << (GetHighBitNumber((uint)minSize - 1) + 1);
|
int newSize = ArrayUtility.NormalizeSizeToPowerOfTwo(minSize);
|
||||||
Array.Resize(ref _baskets, newSize);
|
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
|
#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;
|
||||||
/// <summary>prev node index</summary>
|
|
||||||
public int prev;
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Set(int value, int prev, int next)
|
public void Set(int value, int next)
|
||||||
{
|
|
||||||
this.value = value;
|
|
||||||
this.next = next;
|
|
||||||
this.prev = prev;
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Set_Value_Next(int value, int next)
|
|
||||||
{
|
{
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.next = next;
|
this.next = next;
|
||||||
}
|
}
|
||||||
public override string ToString() => $"node({prev}<>{next} v:{value})";
|
public override string ToString() => $"node(>{next} v:{value})";
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region BasketInfo
|
#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 static readonly BasketNode Empty = new BasketNode() { nodeIndex = 0, count = 0, };
|
||||||
public int nodeIndex;
|
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 count;
|
||||||
|
public int nodeIndex;
|
||||||
public override string ToString() => $"basket_info(i:{nodeIndex} c:{count})";
|
public override string ToString() => $"basket_info(i:{nodeIndex} c:{count})";
|
||||||
|
|
||||||
|
private static BasketNode* EmptyInstancePtr_Debug => EmptyInstancePtr;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -291,7 +333,7 @@ namespace DCFApixels.DragonECS
|
|||||||
private readonly int _basketIndex;
|
private readonly int _basketIndex;
|
||||||
public int Count
|
public int Count
|
||||||
{
|
{
|
||||||
get { return _basketList._baskets[_basketIndex].count; }
|
get { return _basketList._basketNodePointers[_basketIndex]->count; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@ -307,18 +349,19 @@ 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;
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Enumerator(BasketIterator iterator)
|
public Enumerator(BasketIterator iterator)
|
||||||
{
|
{
|
||||||
ref BasketInfo basketInfo = ref iterator._basketList._baskets[iterator._basketIndex];
|
BasketNode* basketNode = iterator._basketList._basketNodePointers[iterator._basketIndex];
|
||||||
|
|
||||||
_nodes = iterator._basketList._nodes;
|
_nodes = iterator._basketList._nodes;
|
||||||
_nodeIndex = -1;
|
_nodeIndex = -1;
|
||||||
_nextNodeIndex = basketInfo.nodeIndex;
|
_nextNodeIndex = basketNode->nodeIndex;
|
||||||
_count = basketInfo.count;
|
_count = basketNode->count;
|
||||||
}
|
}
|
||||||
public int Current
|
public int Current
|
||||||
{
|
{
|
||||||
@ -351,33 +394,40 @@ namespace DCFApixels.DragonECS
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
List<BasketIteratorDebbugerProxy> result = new List<BasketIteratorDebbugerProxy>();
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int RecycledListHead => _basketList._recycledListHead;
|
||||||
public IEnumerable<Node> Recycled
|
public IEnumerable<Node> Recycled
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
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)
|
int i = 0;
|
||||||
|
while (curNode.index != NULL)
|
||||||
{
|
{
|
||||||
BasketList.Node x = _basketList.GetNode(curNode.index);
|
BasketList.Node x = _basketList.GetNode(curNode.index);
|
||||||
curNode.prev = x.prev;
|
|
||||||
curNode.next = x.next;
|
curNode.next = x.next;
|
||||||
|
|
||||||
result.Add(curNode);
|
result.Add(curNode);
|
||||||
curNode = new Node();
|
if (i++ > _basketList._nodes.Length)
|
||||||
curNode.index = curNode.prev;
|
{
|
||||||
|
result.Add(new Node(int.MinValue, int.MinValue, int.MinValue));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
curNode.index = curNode.next;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -390,51 +440,97 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
for (int i = 0; i < _basketList._nodes.Length; i++)
|
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;
|
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)
|
public DebuggerProxy(BasketList basketList)
|
||||||
{
|
{
|
||||||
_basketList = basketList;
|
_basketList = basketList;
|
||||||
}
|
}
|
||||||
public struct Node
|
public struct Node
|
||||||
{
|
{
|
||||||
public int prev;
|
|
||||||
public int index;
|
public int index;
|
||||||
|
public int value;
|
||||||
public int next;
|
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.index = index;
|
||||||
|
this.value = value;
|
||||||
this.next = next;
|
this.next = next;
|
||||||
}
|
}
|
||||||
public override string ToString() => $"node({prev}< {index} >{next})";
|
public override string ToString() => $"[{index}] {value} >{next}";
|
||||||
}
|
}
|
||||||
public struct BasketIteratorDebbugerProxy
|
public struct BasketIteratorDebbugerProxy
|
||||||
{
|
{
|
||||||
|
public int index;
|
||||||
private BasketIterator _iterrator;
|
private BasketIterator _iterrator;
|
||||||
public int Count => _iterrator.Count;
|
public int Count => _iterrator.Count;
|
||||||
public IEnumerable<int> RelEntities
|
public IEnumerable<int> RelEntities
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
List<int> result = new List<int>();
|
List<int> result = new List<int>(_iterrator);
|
||||||
foreach (var e in _iterrator)
|
|
||||||
{
|
|
||||||
result.Add(e);
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public BasketIteratorDebbugerProxy(BasketIterator iterrator)
|
public BasketIteratorDebbugerProxy(int index, BasketIterator iterrator)
|
||||||
{
|
{
|
||||||
|
this.index = index;
|
||||||
_iterrator = iterrator;
|
_iterrator = iterrator;
|
||||||
}
|
}
|
||||||
public override string ToString()
|
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.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS.Relations.Internal
|
namespace DCFApixels.DragonECS.Relations.Internal
|
||||||
{
|
{
|
||||||
@ -32,19 +33,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 +76,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 +121,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];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
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