mirror of
https://github.com/DCFApixels/DragonECS-Graphs.git
synced 2025-09-18 03:34:35 +08:00
stash
This commit is contained in:
parent
7c85a69ab0
commit
0e5e1ac1a4
111
src/EcsArc.cs
111
src/EcsArc.cs
@ -7,13 +7,15 @@ namespace DCFApixels.DragonECS
|
|||||||
//Edge world
|
//Edge world
|
||||||
//Relation entity
|
//Relation entity
|
||||||
//Relation component
|
//Relation component
|
||||||
public class EcsArc : IEcsWorldEventListener, IEcsEntityEventListener
|
public class EcsArc
|
||||||
{
|
{
|
||||||
private readonly EcsWorld _startWorld;
|
private readonly EcsWorld _startWorld;
|
||||||
private readonly EcsWorld _endWorld;
|
private readonly EcsWorld _endWorld;
|
||||||
private readonly EcsArcWorld _arcWorld;
|
private readonly EcsArcWorld _arcWorld;
|
||||||
|
|
||||||
private readonly VertexWorldHandler _startWorldHandler;
|
private readonly StartWorldHandler _startWorldHandler;
|
||||||
|
private readonly ArcWorldHandler _arcWorldHandler;
|
||||||
|
private readonly EndWorldHandler _endWorldHandler;
|
||||||
|
|
||||||
private readonly SparseArray64<int> _relationsMatrix = new SparseArray64<int>();
|
private readonly SparseArray64<int> _relationsMatrix = new SparseArray64<int>();
|
||||||
|
|
||||||
@ -37,13 +39,16 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
_arkEntityInfos = new ArcEntityInfo[arcWorld.Capacity];
|
_arkEntityInfos = new ArcEntityInfo[arcWorld.Capacity];
|
||||||
|
|
||||||
_startWorldHandler = new VertexWorldHandler(this, _startWorld);
|
_startWorldHandler = new StartWorldHandler(this, _startWorld);
|
||||||
|
_arcWorldHandler = new ArcWorldHandler(this);
|
||||||
|
_endWorldHandler = new EndWorldHandler(this, _endWorld);
|
||||||
|
|
||||||
_startWorld.AddListener(worldEventListener: _startWorldHandler);
|
_startWorld.AddListener(worldEventListener: _startWorldHandler);
|
||||||
_startWorld.AddListener(entityEventListener: _startWorldHandler);
|
_startWorld.AddListener(entityEventListener: _startWorldHandler);
|
||||||
|
_arcWorld.AddListener(worldEventListener: _arcWorldHandler);
|
||||||
_arcWorld.AddListener(worldEventListener: this);
|
_arcWorld.AddListener(entityEventListener: _arcWorldHandler);
|
||||||
_arcWorld.AddListener(entityEventListener: this);
|
_endWorld.AddListener(worldEventListener: _endWorldHandler);
|
||||||
|
_endWorld.AddListener(entityEventListener: _endWorldHandler);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -128,36 +133,80 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Callbacks
|
|
||||||
void IEcsWorldEventListener.OnWorldResize(int newSize)
|
|
||||||
{
|
|
||||||
Array.Resize(ref _arkEntityInfos, newSize);
|
|
||||||
}
|
|
||||||
void IEcsWorldEventListener.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer)
|
|
||||||
{
|
|
||||||
_arcWorld.ReleaseDelEntityBuffer(buffer.Length);
|
|
||||||
}
|
|
||||||
void IEcsWorldEventListener.OnWorldDestroy() { }
|
|
||||||
|
|
||||||
void IEcsEntityEventListener.OnNewEntity(int entityID) { }
|
|
||||||
void IEcsEntityEventListener.OnDelEntity(int entityID)
|
|
||||||
{
|
|
||||||
ref ArcEntityInfo rel = ref _arkEntityInfos[entityID];
|
|
||||||
if (_relationsMatrix.Contains(rel.start, rel.end))
|
|
||||||
Del(rel.start, rel.end);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region VertexWorldHandler
|
#region VertexWorldHandler
|
||||||
private class VertexWorldHandler : IEcsWorldEventListener, IEcsEntityEventListener
|
private class ArcWorldHandler : IEcsWorldEventListener, IEcsEntityEventListener
|
||||||
{
|
{
|
||||||
private readonly EcsArc _source;
|
private readonly EcsArc _arc;
|
||||||
private readonly EcsWorld _world;
|
|
||||||
|
|
||||||
public VertexWorldHandler(EcsArc source, EcsWorld world)
|
public ArcWorldHandler(EcsArc arc)
|
||||||
{
|
{
|
||||||
_source = source;
|
_arc = arc;
|
||||||
_world = world;
|
}
|
||||||
|
|
||||||
|
#region Callbacks
|
||||||
|
public void OnDelEntity(int entityID)
|
||||||
|
{
|
||||||
|
ref ArcEntityInfo rel = ref _arc._arkEntityInfos[entityID];
|
||||||
|
if (_arc._relationsMatrix.Contains(rel.start, rel.end))
|
||||||
|
{
|
||||||
|
_arc.Del(rel.start, rel.end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void OnNewEntity(int entityID)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public void OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer)
|
||||||
|
{
|
||||||
|
_arc._arcWorld.ReleaseDelEntityBuffer(buffer.Length);
|
||||||
|
}
|
||||||
|
public void OnWorldDestroy()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public void OnWorldResize(int newSize)
|
||||||
|
{
|
||||||
|
Array.Resize(ref _arc._arkEntityInfos, newSize);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
private class StartWorldHandler : IEcsWorldEventListener, IEcsEntityEventListener
|
||||||
|
{
|
||||||
|
private readonly EcsArc _arc;
|
||||||
|
private readonly EcsWorld _start;
|
||||||
|
|
||||||
|
public StartWorldHandler(EcsArc arc, EcsWorld world)
|
||||||
|
{
|
||||||
|
_arc = arc;
|
||||||
|
_start = world;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Callbacks
|
||||||
|
public void OnDelEntity(int entityID)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public void OnNewEntity(int entityID)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public void OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public void OnWorldDestroy()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public void OnWorldResize(int newSize)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
private class EndWorldHandler : IEcsWorldEventListener, IEcsEntityEventListener
|
||||||
|
{
|
||||||
|
private readonly EcsArc _arc;
|
||||||
|
private readonly EcsWorld _end;
|
||||||
|
|
||||||
|
public EndWorldHandler(EcsArc arc, EcsWorld world)
|
||||||
|
{
|
||||||
|
_arc = arc;
|
||||||
|
_end = world;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Callbacks
|
#region Callbacks
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
public class EcsJoinGroup
|
public class EcsJoinGroup_OLD
|
||||||
{
|
{
|
||||||
private EcsArc _source;
|
private EcsArc _source;
|
||||||
|
|
@ -29,6 +29,12 @@ namespace DCFApixels.DragonECS
|
|||||||
start = startEntity;
|
start = startEntity;
|
||||||
end = endEntity;
|
end = endEntity;
|
||||||
}
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Deconstruct(out int start, out int end)
|
||||||
|
{
|
||||||
|
start = this.start;
|
||||||
|
end = this.end;
|
||||||
|
}
|
||||||
|
|
||||||
#region operators
|
#region operators
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
413
src/Utils/BasketList.cs
Normal file
413
src/Utils/BasketList.cs
Normal file
@ -0,0 +1,413 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS
|
||||||
|
{
|
||||||
|
public class BasketList
|
||||||
|
{
|
||||||
|
public const int RECYCLE = -1;
|
||||||
|
public const int HEAD = 0;
|
||||||
|
|
||||||
|
private BasketInfo[] _baskets = new BasketInfo[64];
|
||||||
|
private Node[] _nodes;
|
||||||
|
private int _recycledListLast = -1;
|
||||||
|
|
||||||
|
private int _basketsCount = 0;
|
||||||
|
private int[] _recycledBuskets = new int[64];
|
||||||
|
private int _recycledBusketsCount = 0;
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public BasketList() : this(16) { }
|
||||||
|
public BasketList(int capacity)
|
||||||
|
{
|
||||||
|
Initialize(capacity);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _nodes.Length; i++)
|
||||||
|
{
|
||||||
|
_nodes[i].next = 0;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < _baskets.Length; i++)
|
||||||
|
{
|
||||||
|
_baskets[i] = default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
|
private void Resize(int newSize)
|
||||||
|
{
|
||||||
|
//int oldSize = _nodes.Length;
|
||||||
|
//Array.Resize(ref _nodes, newSize);
|
||||||
|
//int leftNode = newSize - 1;
|
||||||
|
//for (int i = newSize - 1, n = oldSize; i >= n; i--)
|
||||||
|
//{
|
||||||
|
// Link(i, leftNode);
|
||||||
|
// leftNode = i;
|
||||||
|
//}
|
||||||
|
//LinkToRecycled(newSize - 1, oldSize);
|
||||||
|
|
||||||
|
int oldSize = _nodes.Length;
|
||||||
|
Array.Resize(ref _nodes, newSize);
|
||||||
|
int leftNode = newSize - 1;
|
||||||
|
for (int i = oldSize; i < newSize; i++)
|
||||||
|
{
|
||||||
|
Link(i, leftNode);
|
||||||
|
leftNode = i;
|
||||||
|
}
|
||||||
|
LinkToRecycled(newSize - 1, oldSize);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
|
private void Initialize(int newSize)
|
||||||
|
{
|
||||||
|
//_nodes = new Node[newSize];
|
||||||
|
//int leftNode = newSize - 1;
|
||||||
|
//for (int i = newSize - 1, n = 1; i >= n; i--)
|
||||||
|
//{
|
||||||
|
// Link(i, leftNode);
|
||||||
|
// leftNode = i;
|
||||||
|
//}
|
||||||
|
//LinkToRecycled(newSize - 1, 1);
|
||||||
|
|
||||||
|
_nodes = new Node[newSize];
|
||||||
|
int leftNode = newSize - 1;
|
||||||
|
for (int i = 1; i < newSize; i++)
|
||||||
|
{
|
||||||
|
Link(i, leftNode);
|
||||||
|
leftNode = i;
|
||||||
|
}
|
||||||
|
LinkToRecycled(newSize - 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Set(int nodeIndex, int value)
|
||||||
|
{
|
||||||
|
_nodes[nodeIndex].value = value;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public int Get(int nodeIndex)
|
||||||
|
{
|
||||||
|
return _nodes[nodeIndex].value;
|
||||||
|
}
|
||||||
|
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
//public ref readonly Node GetNode(int nodeIndex)
|
||||||
|
//{
|
||||||
|
// return ref _nodes[nodeIndex];
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private bool RemoveFromBasketAt(int basketIndex, int nodeIndex)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
if (nodeIndex <= 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
basketInfo.nodeIndex = nextNode;
|
||||||
|
}
|
||||||
|
return --basketInfo.count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private int InsertToBasket(int basketIndex, int value)
|
||||||
|
{
|
||||||
|
ref BasketInfo basketInfo = ref _baskets[basketIndex];
|
||||||
|
int newNodeIndex = TakeRecycledNode();
|
||||||
|
if (basketInfo.count == 0)
|
||||||
|
{
|
||||||
|
basketInfo.nodeIndex = newNodeIndex;
|
||||||
|
_nodes[newNodeIndex].Set(value, 0, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int nodeIndex = basketInfo.nodeIndex;
|
||||||
|
ref Node nextNode = ref _nodes[nodeIndex];
|
||||||
|
|
||||||
|
_nodes[newNodeIndex].Set(value, nextNode.prev, nodeIndex);
|
||||||
|
basketInfo.nodeIndex = newNodeIndex;
|
||||||
|
nextNode.prev = newNodeIndex;
|
||||||
|
}
|
||||||
|
basketInfo.count++;
|
||||||
|
return newNodeIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private int TakeRecycledNode()
|
||||||
|
{
|
||||||
|
if (_recycledListLast == -1)
|
||||||
|
{
|
||||||
|
Resize(_nodes.Length << 1);
|
||||||
|
}
|
||||||
|
int node = _recycledListLast;
|
||||||
|
_recycledListLast = _nodes[node].prev;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
//private void Separate(int leftNodeIndex, int rightNodeIndex)
|
||||||
|
//{
|
||||||
|
// _nodes[rightNodeIndex].prev = 0;
|
||||||
|
// _nodes[leftNodeIndex].next = 0;
|
||||||
|
//}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private void Link(int leftNodeIndex, int rightNodeIndex)
|
||||||
|
{
|
||||||
|
_nodes[rightNodeIndex].prev = leftNodeIndex;
|
||||||
|
_nodes[leftNodeIndex].next = rightNodeIndex;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private void LinkToRecycled(int startNodeIndex, int endNodeIndex)
|
||||||
|
{
|
||||||
|
if (_recycledListLast <= -1)
|
||||||
|
{
|
||||||
|
_nodes[startNodeIndex].prev = RECYCLE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Link(_recycledListLast, startNodeIndex);
|
||||||
|
}
|
||||||
|
_recycledListLast = endNodeIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void RemoveBasket(int basketIndex)
|
||||||
|
{
|
||||||
|
ref BasketInfo basket = ref _baskets[basketIndex];
|
||||||
|
|
||||||
|
int startNodeIndex = basket.nodeIndex;
|
||||||
|
int endNodeIndex = startNodeIndex;
|
||||||
|
ref Node startNode = ref _nodes[startNodeIndex];
|
||||||
|
for (int i = 0, n = basket.count; i < n; i++)
|
||||||
|
{
|
||||||
|
endNodeIndex = _nodes[endNodeIndex].next;
|
||||||
|
}
|
||||||
|
ref Node endNode = ref _nodes[endNodeIndex];
|
||||||
|
|
||||||
|
if (_recycledListLast != -1)
|
||||||
|
{
|
||||||
|
//_nodes[_recycledListLast].next = startNodeIndex; //link recycled nodes;
|
||||||
|
//startNode.prev = _recycledListLast;
|
||||||
|
//_recycledListLast = endNodeIndex;
|
||||||
|
Link(_recycledListLast, startNodeIndex);
|
||||||
|
}
|
||||||
|
_recycledListLast = endNodeIndex;
|
||||||
|
|
||||||
|
Link(startNode.prev, endNode.next);
|
||||||
|
|
||||||
|
basket.count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//public int NewBasket()
|
||||||
|
//{
|
||||||
|
// int newBasketIndex;
|
||||||
|
// if(_recycledBusketsCount > 0)
|
||||||
|
// {
|
||||||
|
// newBasketIndex = _recycledBuskets[--_recycledBusketsCount];
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// newBasketIndex = _basketsCount;
|
||||||
|
// if(_basketsCount >= _baskets.Length)
|
||||||
|
// {
|
||||||
|
// Array.Resize(ref _baskets, _baskets.Length << 1);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// _basketsCount++;
|
||||||
|
// _baskets[newBasketIndex] = BasketInfo.Empty;
|
||||||
|
// return newBasketIndex;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
#region Node
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 8)]
|
||||||
|
public struct Node
|
||||||
|
{
|
||||||
|
public static readonly Node Empty = new Node() { value = 0, next = -1 };
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
public override string ToString() => $"node({prev}<>{next} v:{value})";
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region BasketInfo
|
||||||
|
private struct BasketInfo
|
||||||
|
{
|
||||||
|
public static readonly BasketInfo Empty = new BasketInfo() { nodeIndex = 0, count = 0, };
|
||||||
|
public int nodeIndex;
|
||||||
|
public int count;
|
||||||
|
public override string ToString() => $"basket_info(i:{nodeIndex} c:{count})";
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Basket
|
||||||
|
public Basket this[int basketIndex]
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => GetBasket(basketIndex);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Basket GetBasket(int basketIndex)
|
||||||
|
{
|
||||||
|
if (_baskets.Length <= basketIndex)
|
||||||
|
{
|
||||||
|
int newSize = GetHighBitNumber((uint)basketIndex) << 1;
|
||||||
|
Array.Resize(ref _baskets, newSize);
|
||||||
|
}
|
||||||
|
return new Basket(this, basketIndex);
|
||||||
|
}
|
||||||
|
public struct Basket : IEnumerable<int>
|
||||||
|
{
|
||||||
|
private readonly BasketList _basketList;
|
||||||
|
public readonly int _basketIndex;
|
||||||
|
private int _count;
|
||||||
|
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => _count;
|
||||||
|
}
|
||||||
|
public int BasketIndex
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => _basketIndex;
|
||||||
|
}
|
||||||
|
public int StartNodeIndex
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => _basketList._baskets[_basketIndex].nodeIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Basket(BasketList basketList, int basketIndex)
|
||||||
|
{
|
||||||
|
_basketList = basketList;
|
||||||
|
_basketIndex = basketIndex;
|
||||||
|
_count = _basketList._baskets[basketIndex].count;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public int Add(int value)
|
||||||
|
{
|
||||||
|
_count++;
|
||||||
|
return _basketList.InsertToBasket(_basketIndex, value);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void RemoveAt(int nodeIndex)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
if (_count <= 0)
|
||||||
|
throw new Exception();
|
||||||
|
#endif
|
||||||
|
_basketList.RemoveFromBasketAt(_basketIndex, nodeIndex);
|
||||||
|
_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Enumerator GetEnumerator() => new Enumerator(this);
|
||||||
|
IEnumerator<int> IEnumerable<int>.GetEnumerator() => GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
|
public struct Enumerator : IEnumerator<int>
|
||||||
|
{
|
||||||
|
private readonly Node[] _nodes;
|
||||||
|
private int _nodeIndex;
|
||||||
|
private int _nextNode;
|
||||||
|
private int _count;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Enumerator(Basket iterator)
|
||||||
|
{
|
||||||
|
ref BasketInfo basketInfo = ref iterator._basketList._baskets[iterator._basketIndex];
|
||||||
|
_nodes = iterator._basketList._nodes;
|
||||||
|
_nodeIndex = -1;
|
||||||
|
_nextNode = basketInfo.nodeIndex;
|
||||||
|
_count = basketInfo.count;
|
||||||
|
}
|
||||||
|
public int Current
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => _nodes[_nodeIndex].value;
|
||||||
|
}
|
||||||
|
object IEnumerator.Current => Current;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
_nodeIndex = _nextNode;
|
||||||
|
_nextNode = _nodes[_nextNode].next;
|
||||||
|
return _nodeIndex > 0 && _count-- > 0;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Reset() { }
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Dispose() { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
242
src/Utils/EcsJoinGroup.cs
Normal file
242
src/Utils/EcsJoinGroup.cs
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS.Relations.Utils
|
||||||
|
{
|
||||||
|
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||||
|
internal class EcsJoinGroup
|
||||||
|
{
|
||||||
|
private EcsArc _arc;
|
||||||
|
private readonly bool _isLoop;
|
||||||
|
|
||||||
|
private BasketList _startBaskets;
|
||||||
|
private BasketList _endBaskets;
|
||||||
|
private ArcInfo[] _arcMapping;
|
||||||
|
|
||||||
|
public EcsJoinGroup(EcsArc arc)
|
||||||
|
{
|
||||||
|
_arc = arc;
|
||||||
|
_isLoop = arc.IsLoop;
|
||||||
|
|
||||||
|
_startBaskets = new BasketList();
|
||||||
|
if (_isLoop)
|
||||||
|
{
|
||||||
|
_endBaskets = _startBaskets;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_endBaskets = new BasketList();
|
||||||
|
}
|
||||||
|
_arcMapping = new ArcInfo[arc.ArcWorld.Capacity];
|
||||||
|
}
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_startBaskets.Clear();
|
||||||
|
if (!_isLoop)
|
||||||
|
{
|
||||||
|
_endBaskets.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void Add(int arcEntityID)
|
||||||
|
{
|
||||||
|
var (startEntityID, endEntityID) = _arc.GetArcInfo(arcEntityID);
|
||||||
|
_startBaskets[startEntityID].Add(endEntityID);
|
||||||
|
_startBaskets[endEntityID].Add(startEntityID);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var (startEntityID, endEntityID) = _arc.GetArcInfo(arcEntityID);
|
||||||
|
ArcInfo arcInfo = _arcMapping[arcEntityID];
|
||||||
|
|
||||||
|
ref var startSpan = ref _startMapping[startEntityID];
|
||||||
|
if (startSpan.nodeIndex <= 0)
|
||||||
|
{
|
||||||
|
startSpan.nodeIndex = _startList.Add(endEntityID);
|
||||||
|
arcInfo.startNodeIndex = startSpan.nodeIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arcInfo.startNodeIndex = _startList.InsertAfter(startSpan.nodeIndex, endEntityID);
|
||||||
|
}
|
||||||
|
startSpan.count++;
|
||||||
|
|
||||||
|
ref var endSpan = ref _endMapping[endEntityID];
|
||||||
|
if (endSpan.nodeIndex <= 0)
|
||||||
|
{
|
||||||
|
endSpan.nodeIndex = _endList.Add(startEntityID);
|
||||||
|
arcInfo.endNodeIndex = endSpan.nodeIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arcInfo.endNodeIndex = _endList.InsertAfter(endSpan.nodeIndex, startEntityID);
|
||||||
|
}
|
||||||
|
endSpan.count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Del(int arcEntityID)
|
||||||
|
{
|
||||||
|
var (startEntityID, endEntityID) = _arc.GetArcInfo(arcEntityID);
|
||||||
|
ref ArcInfo arcInfo = ref _arcMapping[arcEntityID];
|
||||||
|
int nextIndex;
|
||||||
|
|
||||||
|
ref var startSpan = ref _startMapping[startEntityID];
|
||||||
|
nextIndex = _startList.RemoveIndexAndReturnNextIndex(arcInfo.startNodeIndex);
|
||||||
|
if (startSpan.nodeIndex == arcInfo.startNodeIndex)
|
||||||
|
{
|
||||||
|
startSpan.nodeIndex = nextIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_isLoop)
|
||||||
|
{
|
||||||
|
ref var endSpan = ref _endMapping[endEntityID];
|
||||||
|
nextIndex = _endList.RemoveIndexAndReturnNextIndex(arcInfo.endNodeIndex); ;
|
||||||
|
if (endSpan.nodeIndex == arcInfo.endNodeIndex)
|
||||||
|
{
|
||||||
|
endSpan.nodeIndex = nextIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arcInfo = default;
|
||||||
|
}
|
||||||
|
public void DelEnd(int endEntityID)
|
||||||
|
{
|
||||||
|
DelPosInternal(_endMapping, _startList, _endList, endEntityID);
|
||||||
|
}
|
||||||
|
public void DelStart(int startEntityID)
|
||||||
|
{
|
||||||
|
DelPosInternal(_startMapping, _endList, _startList, startEntityID);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private void DelPosInternal(SpanInfo[] endMapping, IdsLinkedList startList, IdsLinkedList endList, int posEntityID)
|
||||||
|
{
|
||||||
|
ref var endSpan = ref endMapping[posEntityID];
|
||||||
|
if (endSpan.nodeIndex <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach (var startNodeIndex in endList.GetSpan(endSpan.nodeIndex, endSpan.count))
|
||||||
|
{
|
||||||
|
int indx = startList.RemoveIndexAndReturnNextIndex(startNodeIndex);
|
||||||
|
if (endSpan.nodeIndex == startNodeIndex)
|
||||||
|
{
|
||||||
|
endSpan.nodeIndex = indx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endList.RemoveSpan(endSpan.nodeIndex, endSpan.count);
|
||||||
|
endSpan = SpanInfo.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public IdsLinkedList.Span GetSpanFor(int startEntityID)
|
||||||
|
{
|
||||||
|
ref var head = ref _startMapping[startEntityID];
|
||||||
|
if (head.nodeIndex <= 0)
|
||||||
|
return _startList.EmptySpan();
|
||||||
|
else
|
||||||
|
return _startList.GetSpan(head.nodeIndex, head.count);
|
||||||
|
}
|
||||||
|
public IdsLinkedList.LongSpan GetLongSpanFor(EcsWorld world, int startEntityID)
|
||||||
|
{
|
||||||
|
ref var head = ref _startMapping[startEntityID];
|
||||||
|
if (head.nodeIndex <= 0)
|
||||||
|
return _startList.EmptyLongSpan(world);
|
||||||
|
else
|
||||||
|
return _startList.GetLongSpan(world, head.nodeIndex, head.count);
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct SpanInfo
|
||||||
|
{
|
||||||
|
public static readonly SpanInfo Empty = default;
|
||||||
|
public int nodeIndex;
|
||||||
|
public int count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct ArcInfo
|
||||||
|
{
|
||||||
|
public int startNodeIndex;
|
||||||
|
public int endNodeIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region DebuggerProxy
|
||||||
|
internal class DebuggerProxy
|
||||||
|
{
|
||||||
|
private EcsJoinGroup _basket;
|
||||||
|
|
||||||
|
public SpanDebugInfo[] HeadSpans => GetSpans(_basket._startList, _basket._startMapping);
|
||||||
|
public SpanDebugInfo[] ValueSpans => GetSpans(_basket._endList, _basket._endMapping);
|
||||||
|
|
||||||
|
private SpanDebugInfo[] GetSpans(IdsLinkedList list, SpanInfo[] mapping)
|
||||||
|
{
|
||||||
|
SpanDebugInfo[] result = new SpanDebugInfo[mapping.Length];
|
||||||
|
for (int i = 0; i < mapping.Length; i++)
|
||||||
|
result[i] = new SpanDebugInfo(list, mapping[i].nodeIndex, mapping[i].count);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public DebuggerProxy(EcsJoinGroup basket)
|
||||||
|
{
|
||||||
|
_basket = basket;
|
||||||
|
}
|
||||||
|
public struct SpanDebugInfo
|
||||||
|
{
|
||||||
|
private IdsLinkedList _list;
|
||||||
|
public int index;
|
||||||
|
public int count;
|
||||||
|
public NodeDebugInfo[] Nodes
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var result = new NodeDebugInfo[this.count];
|
||||||
|
var nodes = _list.Nodes;
|
||||||
|
int index;
|
||||||
|
int count = this.count;
|
||||||
|
int next = this.index;
|
||||||
|
int i = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
index = next;
|
||||||
|
next = nodes[next].next;
|
||||||
|
if (!(index > 0 && count-- > 0))
|
||||||
|
break;
|
||||||
|
var node = nodes[index];
|
||||||
|
result[i] = new NodeDebugInfo(index, node.prev, node.next, node.value);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public SpanDebugInfo(IdsLinkedList list, int index, int count)
|
||||||
|
{
|
||||||
|
_list = list;
|
||||||
|
this.index = index;
|
||||||
|
this.count = count;
|
||||||
|
}
|
||||||
|
public override string ToString() => $"[{index}] {count}";
|
||||||
|
}
|
||||||
|
public struct NodeDebugInfo
|
||||||
|
{
|
||||||
|
public int index;
|
||||||
|
public int prev;
|
||||||
|
public int next;
|
||||||
|
public int value;
|
||||||
|
public NodeDebugInfo(int index, int prev, int next, int value)
|
||||||
|
{
|
||||||
|
this.index = index;
|
||||||
|
this.prev = prev;
|
||||||
|
this.next = next;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
public override string ToString() => $"[{index}] {prev}_{next} - {value}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -1,175 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS.Relations.Utils
|
|
||||||
{
|
|
||||||
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
|
||||||
internal class IdsBasket
|
|
||||||
{
|
|
||||||
private IdsLinkedList _headList = new IdsLinkedList(4);
|
|
||||||
private IdsLinkedList _valueList = new IdsLinkedList(4);
|
|
||||||
private SpanInfo[] _headMapping;
|
|
||||||
private SpanInfo[] _valueMapping;
|
|
||||||
private int _size;
|
|
||||||
|
|
||||||
public IdsBasket(int size)
|
|
||||||
{
|
|
||||||
_headMapping = new SpanInfo[size];
|
|
||||||
_valueMapping = new SpanInfo[size];
|
|
||||||
_size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Resize(int newSize)
|
|
||||||
{
|
|
||||||
Array.Resize(ref _headMapping, newSize);
|
|
||||||
Array.Resize(ref _valueMapping, newSize);
|
|
||||||
_size = newSize;
|
|
||||||
}
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
_headList.Clear();
|
|
||||||
_valueList.Clear();
|
|
||||||
ArrayUtility.Fill(_headMapping, SpanInfo.Empty);
|
|
||||||
ArrayUtility.Fill(_valueMapping, SpanInfo.Empty);
|
|
||||||
_size = 0;
|
|
||||||
}
|
|
||||||
public void AddToHead(int headID, int id)
|
|
||||||
{
|
|
||||||
int _savedNode;
|
|
||||||
ref var headSpan = ref _headMapping[headID];
|
|
||||||
if (headSpan.startNodeIndex <= 0)
|
|
||||||
{
|
|
||||||
_savedNode = _headList.Add(id);
|
|
||||||
headSpan.startNodeIndex = _savedNode;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_savedNode = _headList.InsertAfter(headSpan.startNodeIndex, id);
|
|
||||||
}
|
|
||||||
headSpan.count++;
|
|
||||||
|
|
||||||
ref var valueSpan = ref _valueMapping[id];
|
|
||||||
if (valueSpan.startNodeIndex <= 0)
|
|
||||||
valueSpan.startNodeIndex = _valueList.Add(_savedNode);
|
|
||||||
else
|
|
||||||
_valueList.InsertAfter(valueSpan.startNodeIndex, _savedNode);
|
|
||||||
valueSpan.count++;
|
|
||||||
}
|
|
||||||
public void Del(int id)
|
|
||||||
{
|
|
||||||
ref var valueSpan = ref _valueMapping[id];
|
|
||||||
ref var headSpan = ref _headMapping[id];
|
|
||||||
if (valueSpan.startNodeIndex <= 0)
|
|
||||||
return;
|
|
||||||
foreach (var nodeIndex in _valueList.GetSpan(valueSpan.startNodeIndex, valueSpan.count))
|
|
||||||
_headList.Remove(nodeIndex);
|
|
||||||
_valueList.RemoveSpan(valueSpan.startNodeIndex, valueSpan.count);
|
|
||||||
valueSpan = SpanInfo.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DelHead(int headID)
|
|
||||||
{
|
|
||||||
ref var headSpan = ref _headMapping[headID];
|
|
||||||
_valueList.RemoveSpan(headSpan.startNodeIndex, headSpan.count);
|
|
||||||
headSpan = SpanInfo.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IdsLinkedList.Span GetSpanFor(int value)
|
|
||||||
{
|
|
||||||
ref var head = ref _headMapping[value];
|
|
||||||
if (head.startNodeIndex <= 0)
|
|
||||||
return _headList.EmptySpan();
|
|
||||||
else
|
|
||||||
return _headList.GetSpan(head.startNodeIndex, head.count);
|
|
||||||
}
|
|
||||||
public IdsLinkedList.LongSpan GetLongSpanFor(EcsWorld world, int value)
|
|
||||||
{
|
|
||||||
ref var head = ref _headMapping[value];
|
|
||||||
if (head.startNodeIndex <= 0)
|
|
||||||
return _headList.EmptyLongSpan(world);
|
|
||||||
else
|
|
||||||
return _headList.GetLongSpan(world, head.startNodeIndex, head.count);
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct SpanInfo
|
|
||||||
{
|
|
||||||
public readonly static SpanInfo Empty = default;
|
|
||||||
public int startNodeIndex;
|
|
||||||
public int count;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region DebuggerProxy
|
|
||||||
internal class DebuggerProxy
|
|
||||||
{
|
|
||||||
private IdsBasket _basket;
|
|
||||||
|
|
||||||
public SpanDebugInfo[] HeadSpans => GetSpans(_basket._headList, _basket._headMapping);
|
|
||||||
public SpanDebugInfo[] ValueSpans => GetSpans(_basket._valueList, _basket._valueMapping);
|
|
||||||
|
|
||||||
private SpanDebugInfo[] GetSpans(IdsLinkedList list, SpanInfo[] mapping)
|
|
||||||
{
|
|
||||||
SpanDebugInfo[] result = new SpanDebugInfo[mapping.Length];
|
|
||||||
for (int i = 0; i < mapping.Length; i++)
|
|
||||||
result[i] = new SpanDebugInfo(list, mapping[i].startNodeIndex, mapping[i].count);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
public DebuggerProxy(IdsBasket basket)
|
|
||||||
{
|
|
||||||
_basket = basket;
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct SpanDebugInfo
|
|
||||||
{
|
|
||||||
private IdsLinkedList _list;
|
|
||||||
public int index;
|
|
||||||
public int count;
|
|
||||||
public NodeDebugInfo[] Nodes
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var result = new NodeDebugInfo[this.count];
|
|
||||||
var nodes = _list.Nodes;
|
|
||||||
int index;
|
|
||||||
int count = this.count;
|
|
||||||
int next = this.index;
|
|
||||||
int i = 0;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
index = next;
|
|
||||||
next = nodes[next].next;
|
|
||||||
if (!(index > 0 && count-- > 0))
|
|
||||||
break;
|
|
||||||
var node = nodes[index];
|
|
||||||
result[i] = new NodeDebugInfo(index, node.prev, node.next, node.value);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public SpanDebugInfo(IdsLinkedList list, int index, int count)
|
|
||||||
{
|
|
||||||
_list = list;
|
|
||||||
this.index = index;
|
|
||||||
this.count = count;
|
|
||||||
}
|
|
||||||
public override string ToString() => $"[{index}] {count}";
|
|
||||||
}
|
|
||||||
public struct NodeDebugInfo
|
|
||||||
{
|
|
||||||
public int index;
|
|
||||||
public int prev;
|
|
||||||
public int next;
|
|
||||||
public int value;
|
|
||||||
public NodeDebugInfo(int index, int prev, int next, int value)
|
|
||||||
{
|
|
||||||
this.index = index;
|
|
||||||
this.prev = prev;
|
|
||||||
this.next = next;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
public override string ToString() => $"[{index}] {prev}_{next} - {value}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,6 +2,7 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS.Relations.Utils
|
namespace DCFApixels.DragonECS.Relations.Utils
|
||||||
@ -19,10 +20,27 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
|||||||
private int _recycledNodesCount;
|
private int _recycledNodesCount;
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
public int Count => _count;
|
public int Count
|
||||||
public int Capacity => _nodes.Length;
|
{
|
||||||
public int Last => _lastNodeIndex;
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public ReadOnlySpan<Node> Nodes => new ReadOnlySpan<Node>(_nodes);
|
get => _count;
|
||||||
|
}
|
||||||
|
public int Capacity
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => _nodes.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Last
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => _lastNodeIndex;
|
||||||
|
}
|
||||||
|
public ReadOnlySpan<Node> Nodes
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => new ReadOnlySpan<Node>(_nodes);
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
@ -33,11 +51,7 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public void Resize(int newCapacity)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
{
|
|
||||||
Array.Resize(ref _nodes, newCapacity + 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _nodes.Length; i++)
|
for (int i = 0; i < _nodes.Length; i++)
|
||||||
@ -46,27 +60,41 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
|||||||
_count = 0;
|
_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Set(int nodeIndex, int value) => _nodes[nodeIndex].value = value;
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public int Get(int nodeIndex) => _nodes[nodeIndex].value;
|
public void Set(int nodeIndex, int value)
|
||||||
|
{
|
||||||
|
_nodes[nodeIndex].value = value;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public int Get(int nodeIndex)
|
||||||
|
{
|
||||||
|
return _nodes[nodeIndex].value;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Insert after</summary>
|
/// <summary> Insert after</summary>
|
||||||
/// <returns> new node index</returns>
|
/// <returns> new node index</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public int InsertAfter(int nodeIndex, int value)
|
public int InsertAfter(int nodeIndex, int value)
|
||||||
{
|
{
|
||||||
if (++_count >= _nodes.Length)
|
if (++_count >= _nodes.Length)
|
||||||
|
{
|
||||||
Array.Resize(ref _nodes, _nodes.Length << 1);
|
Array.Resize(ref _nodes, _nodes.Length << 1);
|
||||||
|
}
|
||||||
int newNodeIndex = _recycledNodesCount > 0 ? _recycledNodes[--_recycledNodesCount] : _count;
|
int newNodeIndex = _recycledNodesCount > 0 ? _recycledNodes[--_recycledNodesCount] : _count;
|
||||||
|
|
||||||
ref Node prevNode = ref _nodes[nodeIndex];
|
ref Node prevNode = ref _nodes[nodeIndex];
|
||||||
ref Node nextNode = ref _nodes[prevNode.next];
|
ref Node nextNode = ref _nodes[prevNode.next];
|
||||||
if (prevNode.next == 0)
|
if (prevNode.next == 0)
|
||||||
|
{
|
||||||
_lastNodeIndex = newNodeIndex;
|
_lastNodeIndex = newNodeIndex;
|
||||||
|
}
|
||||||
_nodes[newNodeIndex].Set(value, nextNode.prev, prevNode.next);
|
_nodes[newNodeIndex].Set(value, nextNode.prev, prevNode.next);
|
||||||
prevNode.next = newNodeIndex;
|
prevNode.next = newNodeIndex;
|
||||||
nextNode.prev = newNodeIndex;
|
nextNode.prev = newNodeIndex;
|
||||||
|
|
||||||
return newNodeIndex;
|
return newNodeIndex;
|
||||||
}
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public int InsertBefore(int nodeIndex, int value)
|
public int InsertBefore(int nodeIndex, int value)
|
||||||
{
|
{
|
||||||
if (++_count >= _nodes.Length)
|
if (++_count >= _nodes.Length)
|
||||||
@ -81,7 +109,8 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
|||||||
|
|
||||||
return newNodeIndex;
|
return newNodeIndex;
|
||||||
}
|
}
|
||||||
public void Remove(int nodeIndex)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void RemoveIndex(int nodeIndex)
|
||||||
{
|
{
|
||||||
if (nodeIndex <= 0)
|
if (nodeIndex <= 0)
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
@ -95,7 +124,26 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
|||||||
_recycledNodes[_recycledNodesCount++] = nodeIndex;
|
_recycledNodes[_recycledNodesCount++] = nodeIndex;
|
||||||
_count--;
|
_count--;
|
||||||
}
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public int RemoveIndexAndReturnNextIndex(int nodeIndex)
|
||||||
|
{
|
||||||
|
if (nodeIndex <= 0)
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
|
||||||
|
ref var node = ref _nodes[nodeIndex];
|
||||||
|
int nextNode = node.next;
|
||||||
|
_nodes[node.next].prev = node.prev;
|
||||||
|
_nodes[node.prev].next = nextNode;
|
||||||
|
|
||||||
|
if (_recycledNodesCount >= _recycledNodes.Length)
|
||||||
|
Array.Resize(ref _recycledNodes, _recycledNodes.Length << 1);
|
||||||
|
_recycledNodes[_recycledNodesCount++] = nodeIndex;
|
||||||
|
_count--;
|
||||||
|
|
||||||
|
return nextNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void RemoveSpan(int startNodeIndex, int count)
|
public void RemoveSpan(int startNodeIndex, int count)
|
||||||
{
|
{
|
||||||
if (count <= 0)
|
if (count <= 0)
|
||||||
@ -127,19 +175,33 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
|||||||
_count -= count;
|
_count -= count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Add(int id) => InsertAfter(_lastNodeIndex, id);
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public ref readonly Node GetNode(int nodeIndex) => ref _nodes[nodeIndex];
|
public int Add(int id)
|
||||||
|
{
|
||||||
|
return InsertAfter(_lastNodeIndex, id);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public ref readonly Node GetNode(int nodeIndex)
|
||||||
|
{
|
||||||
|
return ref _nodes[nodeIndex];
|
||||||
|
}
|
||||||
|
|
||||||
#region Span/Enumerator
|
#region Span/Enumerator
|
||||||
IEnumerator<int> IEnumerable<int>.GetEnumerator() => GetEnumerator();
|
IEnumerator<int> IEnumerable<int>.GetEnumerator() => GetEnumerator();
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public SpanEnumerator GetEnumerator() => new SpanEnumerator(_nodes, _nodes[Head].next, _count);
|
public SpanEnumerator GetEnumerator() => new SpanEnumerator(_nodes, _nodes[Head].next, _count);
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Span GetSpan(int startNodeIndex, int count) => new Span(this, startNodeIndex, count);
|
public Span GetSpan(int startNodeIndex, int count) => new Span(this, startNodeIndex, count);
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Span EmptySpan() => new Span(this, 0, 0);
|
public Span EmptySpan() => new Span(this, 0, 0);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public LongSpan GetLongs(EcsWorld world) => new LongSpan(world, this, _nodes[Head].next, _count);
|
public LongSpan GetLongs(EcsWorld world) => new LongSpan(world, this, _nodes[Head].next, _count);
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public LongSpan GetLongSpan(EcsWorld world, int startNodeIndex, int count) => new LongSpan(world, this, startNodeIndex, count);
|
public LongSpan GetLongSpan(EcsWorld world, int startNodeIndex, int count) => new LongSpan(world, this, startNodeIndex, count);
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public LongSpan EmptyLongSpan(EcsWorld world) => new LongSpan(world, this, 0, 0);
|
public LongSpan EmptyLongSpan(EcsWorld world) => new LongSpan(world, this, 0, 0);
|
||||||
|
|
||||||
public readonly ref struct Span
|
public readonly ref struct Span
|
||||||
@ -147,12 +209,14 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
|||||||
private readonly IdsLinkedList _source;
|
private readonly IdsLinkedList _source;
|
||||||
private readonly int _startNodeIndex;
|
private readonly int _startNodeIndex;
|
||||||
private readonly int _count;
|
private readonly int _count;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Span(IdsLinkedList source, int startNodeIndex, int count)
|
public Span(IdsLinkedList source, int startNodeIndex, int count)
|
||||||
{
|
{
|
||||||
_source = source;
|
_source = source;
|
||||||
_startNodeIndex = startNodeIndex;
|
_startNodeIndex = startNodeIndex;
|
||||||
_count = count;
|
_count = count;
|
||||||
}
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public SpanEnumerator GetEnumerator() => new SpanEnumerator(_source._nodes, _startNodeIndex, _count);
|
public SpanEnumerator GetEnumerator() => new SpanEnumerator(_source._nodes, _startNodeIndex, _count);
|
||||||
}
|
}
|
||||||
public struct SpanEnumerator : IEnumerator<int>
|
public struct SpanEnumerator : IEnumerator<int>
|
||||||
@ -161,6 +225,7 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
|||||||
private int _count;
|
private int _count;
|
||||||
private int _index;
|
private int _index;
|
||||||
private int _next;
|
private int _next;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public SpanEnumerator(Node[] nodes, int startIndex, int count)
|
public SpanEnumerator(Node[] nodes, int startIndex, int count)
|
||||||
{
|
{
|
||||||
_nodes = nodes;
|
_nodes = nodes;
|
||||||
@ -168,15 +233,26 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
|||||||
_count = count;
|
_count = count;
|
||||||
_next = startIndex;
|
_next = startIndex;
|
||||||
}
|
}
|
||||||
public int Current => _nodes[_index].value;
|
public int Current
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _nodes[_index].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object IEnumerator.Current => Current;
|
object IEnumerator.Current => Current;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool MoveNext()
|
public bool MoveNext()
|
||||||
{
|
{
|
||||||
_index = _next;
|
_index = _next;
|
||||||
_next = _nodes[_next].next;
|
_next = _nodes[_next].next;
|
||||||
return _index > 0 && _count-- > 0;
|
return _index > 0 && _count-- > 0;
|
||||||
}
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
void IDisposable.Dispose() { }
|
void IDisposable.Dispose() { }
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
void IEnumerator.Reset()
|
void IEnumerator.Reset()
|
||||||
{
|
{
|
||||||
_index = -1;
|
_index = -1;
|
||||||
@ -189,6 +265,7 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
|||||||
private readonly IdsLinkedList _source;
|
private readonly IdsLinkedList _source;
|
||||||
private readonly int _startNodeIndex;
|
private readonly int _startNodeIndex;
|
||||||
private readonly int _count;
|
private readonly int _count;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public LongSpan(EcsWorld world, IdsLinkedList source, int startNodeIndex, int count)
|
public LongSpan(EcsWorld world, IdsLinkedList source, int startNodeIndex, int count)
|
||||||
{
|
{
|
||||||
_world = world;
|
_world = world;
|
||||||
@ -196,6 +273,7 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
|||||||
_startNodeIndex = startNodeIndex;
|
_startNodeIndex = startNodeIndex;
|
||||||
_count = count;
|
_count = count;
|
||||||
}
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public LongSpanEnumerator GetEnumerator() => new LongSpanEnumerator(_world, _source._nodes, _startNodeIndex, _count);
|
public LongSpanEnumerator GetEnumerator() => new LongSpanEnumerator(_world, _source._nodes, _startNodeIndex, _count);
|
||||||
}
|
}
|
||||||
public struct LongSpanEnumerator : IEnumerator<entlong>
|
public struct LongSpanEnumerator : IEnumerator<entlong>
|
||||||
@ -205,6 +283,7 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
|||||||
private int _count;
|
private int _count;
|
||||||
private int _index;
|
private int _index;
|
||||||
private int _next;
|
private int _next;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public LongSpanEnumerator(EcsWorld world, Node[] nodes, int startIndex, int count)
|
public LongSpanEnumerator(EcsWorld world, Node[] nodes, int startIndex, int count)
|
||||||
{
|
{
|
||||||
_world = world;
|
_world = world;
|
||||||
@ -213,15 +292,26 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
|||||||
_count = count;
|
_count = count;
|
||||||
_next = startIndex;
|
_next = startIndex;
|
||||||
}
|
}
|
||||||
public entlong Current => _world.GetEntityLong(_nodes[_index].value);
|
public entlong Current
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _world.GetEntityLong(_nodes[_index].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object IEnumerator.Current => Current;
|
object IEnumerator.Current => Current;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool MoveNext()
|
public bool MoveNext()
|
||||||
{
|
{
|
||||||
_index = _next;
|
_index = _next;
|
||||||
_next = _nodes[_next].next;
|
_next = _nodes[_next].next;
|
||||||
return _index > 0 && _count-- > 0;
|
return _index > 0 && _count-- > 0;
|
||||||
}
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
void IDisposable.Dispose() { }
|
void IDisposable.Dispose() { }
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
void IEnumerator.Reset()
|
void IEnumerator.Reset()
|
||||||
{
|
{
|
||||||
_index = -1;
|
_index = -1;
|
||||||
@ -240,6 +330,7 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
|||||||
public int next;
|
public int next;
|
||||||
/// <summary>prev node index</summary>
|
/// <summary>prev node index</summary>
|
||||||
public int prev;
|
public int prev;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Set(int value, int prev, int next)
|
public void Set(int value, int prev, int next)
|
||||||
{
|
{
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
Loading…
Reference in New Issue
Block a user