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
3c79ea24e3
commit
08b25ed671
@ -1,11 +1,21 @@
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public abstract class EcsArcWorld : EcsWorld { }
|
||||
public abstract class EcsArcWorld : EcsWorld
|
||||
{
|
||||
public EcsArcWorld() : base(null) { }
|
||||
public EcsArcWorld(IEcsWorldConfig config) : base(config) { }
|
||||
}
|
||||
public sealed class EcsLoopArcWorld<TWorld> : EcsArcWorld
|
||||
where TWorld : EcsWorld
|
||||
{ }
|
||||
{
|
||||
public EcsLoopArcWorld() : base(null) { }
|
||||
public EcsLoopArcWorld(IEcsWorldConfig config) : base(config) { }
|
||||
}
|
||||
public sealed class EcsArcWorld<TStartWorld, TEndWorld> : EcsArcWorld
|
||||
where TStartWorld : EcsWorld
|
||||
where TEndWorld : EcsWorld
|
||||
{ }
|
||||
{
|
||||
public EcsArcWorld() : base(null) { }
|
||||
public EcsArcWorld(IEcsWorldConfig config) : base(config) { }
|
||||
}
|
||||
}
|
||||
|
@ -2,13 +2,13 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using static DCFApixels.DragonECS.Relations.Utils.EcsJoin;
|
||||
using static DCFApixels.DragonECS.EcsGraph;
|
||||
|
||||
namespace DCFApixels.DragonECS.Relations.Utils
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public readonly ref struct EcsReadonlyJoin
|
||||
public readonly ref struct EcsReadonlyGraph
|
||||
{
|
||||
private readonly EcsJoin _source;
|
||||
private readonly EcsGraph _source;
|
||||
|
||||
#region Properties
|
||||
public bool IsNull => _source == null;
|
||||
@ -51,7 +51,7 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
||||
|
||||
#region Constructors
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public EcsReadonlyJoin(EcsJoin source) { _source = source; }
|
||||
public EcsReadonlyGraph(EcsGraph source) { _source = source; }
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
@ -67,7 +67,7 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
||||
|
||||
#region Internal
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal EcsJoin GetSource_Internal() => _source;
|
||||
internal EcsGraph GetSource_Internal() => _source;
|
||||
#endregion
|
||||
|
||||
#region Other
|
||||
@ -86,20 +86,20 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
||||
#endregion
|
||||
}
|
||||
//[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||
public class EcsJoin
|
||||
public class EcsGraph
|
||||
{
|
||||
private readonly EcsArc _source;
|
||||
private readonly bool _isLoop;
|
||||
|
||||
private readonly BasketList _startBaskets;
|
||||
private readonly BasketList _endBaskets;
|
||||
private readonly RelNodesInfo[] _relNodesMapping;
|
||||
private RelNodesInfo[] _relNodesMapping;
|
||||
|
||||
#region Properties
|
||||
public EcsReadonlyJoin Readonly
|
||||
public EcsReadonlyGraph Readonly
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get { return new EcsReadonlyJoin(this); }
|
||||
get { return new EcsReadonlyGraph(this); }
|
||||
}
|
||||
public EcsArc Arc
|
||||
{
|
||||
@ -140,20 +140,12 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public EcsJoin(EcsArc arc)
|
||||
public EcsGraph(EcsArc arc)
|
||||
{
|
||||
_source = arc;
|
||||
_isLoop = arc.IsLoop;
|
||||
|
||||
_startBaskets = new BasketList();
|
||||
//if (_isLoop)
|
||||
//{
|
||||
// _endBaskets = _startBaskets;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// _endBaskets = new BasketList();
|
||||
//}
|
||||
_endBaskets = new BasketList();
|
||||
|
||||
_relNodesMapping = new RelNodesInfo[arc.ArcWorld.Capacity];
|
||||
@ -167,14 +159,7 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
||||
ref RelNodesInfo arcInfo = ref _relNodesMapping[relEntityID];
|
||||
|
||||
arcInfo.startNodeIndex = _startBaskets.AddToBasket(startEntityID, relEntityID);
|
||||
//if (_isLoop)
|
||||
//{
|
||||
// arcInfo.endNodeIndex = arcInfo.startNodeIndex;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
arcInfo.endNodeIndex = _endBaskets.AddToBasket(endEntityID, relEntityID);
|
||||
//}
|
||||
}
|
||||
public void Del(int relEntityID)
|
||||
{
|
||||
@ -214,59 +199,21 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
||||
|
||||
foreach (var relEntityID in _startBaskets.GetBasketIterator(startEntityID))
|
||||
{
|
||||
//int endEntityID = _source.GetRelEnd(relEntityID);
|
||||
//int endNodeIndex = _relNodesMapping[relEntityID].endNodeIndex;
|
||||
//int revereceRelEntitiy = _endBaskets.Get(endNodeIndex);
|
||||
//
|
||||
////_endBaskets.RemoveFromBasket(endEntityID, endNodeIndex);
|
||||
//
|
||||
//arc.ArcWorld.DelEntity(relEntityID);
|
||||
//if(!_isLoop)
|
||||
//{
|
||||
// arc.ArcWorld.DelEntity(revereceRelEntitiy);
|
||||
//}
|
||||
|
||||
arc.ArcWorld.DelEntity(relEntityID);
|
||||
//if (_isLoop)
|
||||
//{
|
||||
// int endNodeIndex = _relNodesMapping[relEntityID].endNodeIndex;
|
||||
// int revereceRelEntitiy = _endBaskets.Get(endNodeIndex);
|
||||
// arc.ArcWorld.DelEntity(revereceRelEntitiy);
|
||||
//}
|
||||
arc.ArcWorld.TryDelEntity(relEntityID);
|
||||
}
|
||||
//_startBaskets.RemoveBasket(startEntityID);
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void DelEndAndDelRelEntities(int endEntityID, EcsArc arc)
|
||||
{
|
||||
foreach (var relEntityID in _endBaskets.GetBasketIterator(endEntityID))
|
||||
{
|
||||
//int startEntityID = _source.GetRelStart(relEntityID);
|
||||
//int startNodeIndex = _relNodesMapping[relEntityID].startNodeIndex;
|
||||
//int revereceRelEntitiy = _startBaskets.Get(startNodeIndex);
|
||||
//
|
||||
////_startBaskets.RemoveFromBasket(startEntityID, startNodeIndex);
|
||||
//
|
||||
//arc.ArcWorld.DelEntity(relEntityID);
|
||||
//if(!_isLoop)
|
||||
//{
|
||||
// arc.ArcWorld.DelEntity(revereceRelEntitiy);
|
||||
//}
|
||||
|
||||
arc.ArcWorld.DelEntity(relEntityID);
|
||||
//if (_isLoop)
|
||||
//{
|
||||
// int startNodeIndex = _relNodesMapping[relEntityID].startNodeIndex;
|
||||
// int revereceRelEntitiy = _startBaskets.Get(startNodeIndex);
|
||||
// arc.ArcWorld.DelEntity(revereceRelEntitiy);
|
||||
//}
|
||||
arc.ArcWorld.TryDelEntity(relEntityID);
|
||||
}
|
||||
//_endBaskets.RemoveBasket(endEntityID);
|
||||
}
|
||||
public struct FriendEcsArc
|
||||
{
|
||||
private EcsJoin _join;
|
||||
public FriendEcsArc(EcsArc arc, EcsJoin join)
|
||||
private EcsGraph _join;
|
||||
public FriendEcsArc(EcsArc arc, EcsGraph join)
|
||||
{
|
||||
if (arc.IsInit_Internal != false)
|
||||
{
|
||||
@ -403,7 +350,22 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
||||
|
||||
#region Operators
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator EcsReadonlyJoin(EcsJoin a) => a.Readonly;
|
||||
public static implicit operator EcsReadonlyGraph(EcsGraph a) => a.Readonly;
|
||||
#endregion
|
||||
|
||||
#region UpSize
|
||||
public void UpArcSize(int minSize)
|
||||
{
|
||||
Array.Resize(ref _relNodesMapping, minSize);
|
||||
}
|
||||
public void UpStartSize(int minSize)
|
||||
{
|
||||
_startBaskets.UpBasketsSize(minSize);
|
||||
}
|
||||
public void UpEndSize(int minSize)
|
||||
{
|
||||
_endBaskets.UpBasketsSize(minSize);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region DebuggerProxy
|
@ -1,6 +1,5 @@
|
||||
using DCFApixels.DragonECS.Relations.Internal;
|
||||
using DCFApixels.DragonECS.Relations.Utils;
|
||||
using Leopotam.EcsLite;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
@ -23,8 +22,8 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
private readonly SparseArray64<int> _relationsMatrix = new SparseArray64<int>();
|
||||
|
||||
private EcsJoin _joinEntities;
|
||||
private EcsJoin.FriendEcsArc _joinEntitiesFriend;
|
||||
private EcsGraph _entitiesGraph;
|
||||
private EcsGraph.FriendEcsArc _entitiesGraphFriend;
|
||||
|
||||
private EcsGroup _relEntities;
|
||||
private RelEntityInfo[] _relEntityInfos; //N * (N - 1) / 2
|
||||
@ -63,10 +62,10 @@ namespace DCFApixels.DragonECS
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get { return _relEntities.Readonly; }
|
||||
}
|
||||
public EcsReadonlyJoin JoinEntities
|
||||
public EcsReadonlyGraph EntitiesGraph
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get { return _joinEntities.Readonly; }
|
||||
get { return _entitiesGraph.Readonly; }
|
||||
}
|
||||
public bool IsLoop
|
||||
{
|
||||
@ -86,8 +85,13 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
_relEntityInfos = new RelEntityInfo[arcWorld.Capacity];
|
||||
|
||||
_arcWorldHandler = new ArcWorldHandler(this);
|
||||
|
||||
_relEntities = EcsGroup.New(_arcWorld);
|
||||
_entitiesGraph = new EcsGraph(this);
|
||||
|
||||
_entitiesGraphFriend = new EcsGraph.FriendEcsArc(this, _entitiesGraph);
|
||||
|
||||
_arcWorldHandler = new ArcWorldHandler(this);
|
||||
if (_isLoop)
|
||||
{
|
||||
_loopWorldHandler = new LoopWorldHandler(this);
|
||||
@ -98,11 +102,6 @@ namespace DCFApixels.DragonECS
|
||||
_endWorldHandler = new EndWorldHandler(this);
|
||||
}
|
||||
|
||||
|
||||
_relEntities = EcsGroup.New(_arcWorld);
|
||||
_joinEntities = new EcsJoin(this);
|
||||
|
||||
_joinEntitiesFriend = new EcsJoin.FriendEcsArc(this, _joinEntities);
|
||||
_isInit = true;
|
||||
}
|
||||
public void Destroy()
|
||||
@ -126,7 +125,7 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
if (HasRelation(startEntityID, endEntityID))
|
||||
{
|
||||
Throw.UndefinedRelationException();
|
||||
Throw.RelationAlreadyExists();
|
||||
}
|
||||
|
||||
int relEntity = _arcWorld.NewEntity();
|
||||
@ -134,7 +133,7 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
_relEntityInfos[relEntity] = new RelEntityInfo(startEntityID, endEntityID);
|
||||
_relEntities.Add(relEntity);
|
||||
_joinEntities.Add(relEntity);
|
||||
_entitiesGraph.Add(relEntity);
|
||||
return relEntity;
|
||||
}
|
||||
public void DelRelation(int startEntityID, int endEntityID)
|
||||
@ -147,17 +146,6 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
Throw.UndefinedRelationException();
|
||||
}
|
||||
//if (!_relationsMatrix.TryGetValue(startEntityID, endEntityID, out int relEntity))
|
||||
//{
|
||||
// Throw.UndefinedRelationException();
|
||||
//}
|
||||
//_joinEntities.Del(relEntity);
|
||||
//
|
||||
//_relationsMatrix.Remove(startEntityID, endEntityID);
|
||||
//_arcWorld.DelEntity(relEntity);
|
||||
//
|
||||
//_relEntityInfos[relEntity] = RelEntityInfo.Empty;
|
||||
//_relEntities.Remove(relEntity);
|
||||
}
|
||||
|
||||
private void ClearRelation_Internal(int startEntityID, int endEntityID)
|
||||
@ -165,7 +153,7 @@ namespace DCFApixels.DragonECS
|
||||
if (_relationsMatrix.TryGetValue(startEntityID, endEntityID, out int relEntity))
|
||||
{
|
||||
_relEntities.Remove(relEntity);
|
||||
_joinEntities.Del(relEntity);
|
||||
_entitiesGraph.Del(relEntity);
|
||||
_relationsMatrix.Remove(startEntityID, endEntityID);
|
||||
_relEntityInfos[relEntity] = RelEntityInfo.Empty;
|
||||
}
|
||||
@ -273,6 +261,7 @@ namespace DCFApixels.DragonECS
|
||||
public void OnWorldResize(int arcWorldNewSize)
|
||||
{
|
||||
Array.Resize(ref _arc._relEntityInfos, arcWorldNewSize);
|
||||
_arc._entitiesGraph.UpArcSize(arcWorldNewSize);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@ -283,6 +272,7 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
_arc = arc;
|
||||
_arc.StartWorld.AddListener(this);
|
||||
OnWorldResize(_arc.StartWorld.Capacity);
|
||||
}
|
||||
public void Destroy()
|
||||
{
|
||||
@ -293,12 +283,15 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
foreach (var startEntityID in startEntityBuffer)
|
||||
{
|
||||
_arc._joinEntitiesFriend.DelStartAndDelRelEntities(startEntityID, _arc);
|
||||
_arc._entitiesGraphFriend.DelStartAndDelRelEntities(startEntityID, _arc);
|
||||
}
|
||||
_arc._arcWorld.ReleaseDelEntityBuffer(startEntityBuffer.Length);
|
||||
_arc._arcWorld.ReleaseDelEntityBufferAll();
|
||||
}
|
||||
public void OnWorldDestroy() { }
|
||||
public void OnWorldResize(int startWorldNewSize) { }
|
||||
public void OnWorldResize(int startWorldNewSize)
|
||||
{
|
||||
_arc._entitiesGraph.UpStartSize(startWorldNewSize);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
private class EndWorldHandler : IEcsWorldEventListener
|
||||
@ -308,6 +301,7 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
_arc = arc;
|
||||
_arc.EndWorld.AddListener(this);
|
||||
OnWorldResize(_arc.EndWorld.Capacity);
|
||||
}
|
||||
public void Destroy()
|
||||
{
|
||||
@ -318,12 +312,15 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
foreach (var endEntityID in endEntityBuffer)
|
||||
{
|
||||
_arc._joinEntitiesFriend.DelEndAndDelRelEntities(endEntityID, _arc);
|
||||
_arc._entitiesGraphFriend.DelEndAndDelRelEntities(endEntityID, _arc);
|
||||
}
|
||||
_arc._arcWorld.ReleaseDelEntityBuffer(endEntityBuffer.Length);
|
||||
_arc._arcWorld.ReleaseDelEntityBufferAll();
|
||||
}
|
||||
public void OnWorldDestroy() { }
|
||||
public void OnWorldResize(int endWorldNewSize) { }
|
||||
public void OnWorldResize(int endWorldNewSize)
|
||||
{
|
||||
_arc._entitiesGraph.UpEndSize(endWorldNewSize);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
private class LoopWorldHandler : IEcsWorldEventListener
|
||||
@ -333,6 +330,7 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
_arc = arc;
|
||||
_arc.StartWorld.AddListener(this);
|
||||
OnWorldResize(_arc.StartWorld.Capacity);
|
||||
}
|
||||
public void Destroy()
|
||||
{
|
||||
@ -343,13 +341,17 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
foreach (var startEntityID in startEntityBuffer)
|
||||
{
|
||||
_arc._joinEntitiesFriend.DelStartAndDelRelEntities(startEntityID, _arc);
|
||||
_arc._joinEntitiesFriend.DelEndAndDelRelEntities(startEntityID, _arc);
|
||||
_arc._entitiesGraphFriend.DelStartAndDelRelEntities(startEntityID, _arc);
|
||||
_arc._entitiesGraphFriend.DelEndAndDelRelEntities(startEntityID, _arc);
|
||||
}
|
||||
_arc._arcWorld.ReleaseDelEntityBuffer(startEntityBuffer.Length);
|
||||
_arc._arcWorld.ReleaseDelEntityBufferAll();
|
||||
}
|
||||
public void OnWorldDestroy() { }
|
||||
public void OnWorldResize(int startWorldNewSize) { }
|
||||
public void OnWorldResize(int startWorldNewSize)
|
||||
{
|
||||
_arc._entitiesGraph.UpStartSize(startWorldNewSize);
|
||||
_arc._entitiesGraph.UpEndSize(startWorldNewSize);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
|
10
src/EcsWorldConfig.cs
Normal file
10
src/EcsWorldConfig.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public static class EcsWorldConfigRelationsExtensions
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
public static class EcsWorldGraph
|
||||
{
|
||||
private static readonly SparseArray64<EcsArc> _matrix = new SparseArray64<EcsArc>(4);
|
||||
private static readonly SparseArray<EcsArc> _matrix = new SparseArray<EcsArc>(4);
|
||||
private static EcsArc[] _arcsMapping = new EcsArc[4];
|
||||
|
||||
#region Register/Unregister
|
||||
@ -103,7 +103,7 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
|
||||
|
||||
public static EcsArc SetLoopArcAuto<TWorld>(this TWorld self, out EcsLoopArcWorld<TWorld> arcWorld)
|
||||
public static EcsArc SetLoopArcAuto<TWorld>(this TWorld self, out EcsLoopArcWorld<TWorld> arcWorld, IEcsWorldConfig config = null)
|
||||
where TWorld : EcsWorld
|
||||
{
|
||||
if (self == null)
|
||||
@ -114,10 +114,10 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
EcsDebug.PrintWarning($"{nameof(TWorld)} is not {self.GetType().Name}");
|
||||
}
|
||||
arcWorld = new EcsLoopArcWorld<TWorld>();
|
||||
arcWorld = new EcsLoopArcWorld<TWorld>(config);
|
||||
return Register(self, self, arcWorld);
|
||||
}
|
||||
public static EcsArc SetArcAuto<TStartWorld, TEndWorld>(this TStartWorld start, TEndWorld end, out EcsArcWorld<TStartWorld, TEndWorld> arcWorld)
|
||||
public static EcsArc SetArcAuto<TStartWorld, TEndWorld>(this TStartWorld start, TEndWorld end, out EcsArcWorld<TStartWorld, TEndWorld> arcWorld, IEcsWorldConfig config = null)
|
||||
where TStartWorld : EcsWorld
|
||||
where TEndWorld : EcsWorld
|
||||
{
|
||||
@ -129,19 +129,19 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
EcsDebug.PrintWarning($"{nameof(TStartWorld)} is not {start.GetType().Name} or {nameof(TEndWorld)} is not {end.GetType().Name}");
|
||||
}
|
||||
arcWorld = new EcsArcWorld<TStartWorld, TEndWorld>();
|
||||
arcWorld = new EcsArcWorld<TStartWorld, TEndWorld>(config);
|
||||
return Register(start, end, arcWorld);
|
||||
}
|
||||
public static EcsArc SetLoopArcAuto<TWorld>(this TWorld self)
|
||||
public static EcsArc SetLoopArcAuto<TWorld>(this TWorld self, IEcsWorldConfig config = null)
|
||||
where TWorld : EcsWorld
|
||||
{
|
||||
return SetLoopArcAuto(self, out _);
|
||||
return SetLoopArcAuto(self, out _, config);
|
||||
}
|
||||
public static EcsArc SetArcAuto<TStartWorld, TEndWorld>(this TStartWorld start, TEndWorld end)
|
||||
public static EcsArc SetArcAuto<TStartWorld, TEndWorld>(this TStartWorld start, TEndWorld end, IEcsWorldConfig config = null)
|
||||
where TStartWorld : EcsWorld
|
||||
where TEndWorld : EcsWorld
|
||||
{
|
||||
return SetArcAuto(start, end, out _);
|
||||
return SetArcAuto(start, end, out _, config);
|
||||
}
|
||||
|
||||
public static EcsArc SetLoopArc(this EcsWorld self, EcsArcWorld arc) => SetArc(self, self, arc);
|
||||
|
@ -1,15 +1,185 @@
|
||||
namespace DCFApixels.DragonECS.Relations.Utils
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DCFApixels.DragonECS.Relations.Internal
|
||||
{
|
||||
internal static class ArrayUtility
|
||||
{
|
||||
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 static int NormalizeSizeToPowerOfTwo(int minSize)
|
||||
{
|
||||
return 1 << (GetHighBitNumber((uint)minSize - 1u) + 1);
|
||||
}
|
||||
public static void Fill<T>(T[] array, T value, int startIndex = 0, int length = -1)
|
||||
{
|
||||
if (length < 0)
|
||||
{
|
||||
length = array.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
length = startIndex + length;
|
||||
}
|
||||
for (int i = startIndex; i < length; i++)
|
||||
{
|
||||
array[i] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
internal readonly struct EnumerableInt : IEnumerable<int>
|
||||
{
|
||||
public readonly int start;
|
||||
public readonly int length;
|
||||
private EnumerableInt(int start, int length)
|
||||
{
|
||||
this.start = start;
|
||||
this.length = length;
|
||||
}
|
||||
public static EnumerableInt Range(int start, int length) => new EnumerableInt(start, length);
|
||||
public static EnumerableInt StartEnd(int start, int end) => new EnumerableInt(start, end - start);
|
||||
IEnumerator<int> IEnumerable<int>.GetEnumerator() => GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Enumerator GetEnumerator() => new Enumerator(start, start + length);
|
||||
public struct Enumerator : IEnumerator<int>
|
||||
{
|
||||
private readonly int _max;
|
||||
private int _current;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Enumerator(int max, int current)
|
||||
{
|
||||
_max = max;
|
||||
_current = current - 1;
|
||||
}
|
||||
public int Current
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _current;
|
||||
}
|
||||
object IEnumerator.Current => Current;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext() => ++_current < _max;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Reset() { }
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
internal static unsafe class UnmanagedArrayUtility
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T* New<T>(int capacity) where T : unmanaged
|
||||
{
|
||||
return (T*)Marshal.AllocHGlobal(Marshal.SizeOf<T>() * capacity).ToPointer();
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void New<T>(out T* ptr, int capacity) where T : unmanaged
|
||||
{
|
||||
ptr = (T*)Marshal.AllocHGlobal(Marshal.SizeOf<T>(default) * capacity).ToPointer();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T* NewAndInit<T>(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;
|
||||
|
||||
return (T*)newPointer;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void NewAndInit<T>(out T* ptr, int capacity) where T : unmanaged
|
||||
{
|
||||
int newSize = Marshal.SizeOf(typeof(T)) * capacity;
|
||||
byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
|
||||
|
||||
for (int i = 0; i < newSize; i++)
|
||||
*(newPointer + i) = 0;
|
||||
|
||||
ptr = (T*)newPointer;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Free(void* pointer)
|
||||
{
|
||||
Marshal.FreeHGlobal(new IntPtr(pointer));
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Free<T>(ref T* pointer, ref int length) where T : unmanaged
|
||||
{
|
||||
Marshal.FreeHGlobal(new IntPtr(pointer));
|
||||
pointer = null;
|
||||
length = 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T* Clone<T>(T* sourcePtr, int length) where T : unmanaged
|
||||
{
|
||||
T* clone = New<T>(length);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
clone[i] = sourcePtr[i];
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T* Resize<T>(void* oldPointer, int newCount) where T : unmanaged
|
||||
{
|
||||
return (T*)(Marshal.ReAllocHGlobal(
|
||||
new IntPtr(oldPointer),
|
||||
new IntPtr(Marshal.SizeOf<T>(default) * newCount))).ToPointer();
|
||||
}
|
||||
}
|
||||
|
||||
public static class CollectionUtility
|
||||
{
|
||||
public static string EntitiesToString(IEnumerable<int> range, string name)
|
||||
{
|
||||
return $"{name}({range.Count()}) {{{string.Join(", ", range.OrderBy(o => o))}}})";
|
||||
}
|
||||
public static string AutoToString<T>(IEnumerable<T> range, string name)
|
||||
{
|
||||
return $"{name}({range.Count()}) {{{string.Join(", ", range.Select(o => o.ToString()))}}})";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,7 @@
|
||||
using DCFApixels.DragonECS.Relations.Internal;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@ -192,11 +190,14 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private void UpBasketsSize(int minSize)
|
||||
public void UpBasketsSize(int minSize)
|
||||
{
|
||||
int newSize = GetHighBitNumber((uint)minSize) << 1;
|
||||
if (minSize > _baskets.Length)
|
||||
{
|
||||
int newSize = 1 << (GetHighBitNumber((uint)minSize - 1) + 1);
|
||||
Array.Resize(ref _baskets, newSize);
|
||||
}
|
||||
}
|
||||
private static int GetHighBitNumber(uint bits)
|
||||
{
|
||||
if (bits == 0)
|
||||
@ -271,10 +272,6 @@ namespace DCFApixels.DragonECS
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public BasketIterator GetBasketIterator(int basketIndex)
|
||||
{
|
||||
if (_baskets.Length <= basketIndex)
|
||||
{
|
||||
UpBasketsSize(basketIndex);
|
||||
}
|
||||
return new BasketIterator(this, basketIndex);
|
||||
}
|
||||
public readonly struct BasketIterator : IEnumerable<int>
|
||||
|
@ -26,6 +26,11 @@ namespace DCFApixels.DragonECS.Relations.Internal
|
||||
{
|
||||
throw new EcsRelationException();
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
internal static void RelationAlreadyExists()
|
||||
{
|
||||
throw new EcsRelationException("This relation already exists.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
//SparseArray64. Analogous to Dictionary<long, T>, but faster.
|
||||
//Benchmark result of indexer.get speed test with 300 elements:
|
||||
//[Dictinary: 6.705us] [SparseArray64: 2.512us].
|
||||
using DCFApixels.DragonECS.Relations.Internal;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.Contracts;
|
||||
@ -9,14 +10,15 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace DCFApixels.DragonECS.Relations.Utils
|
||||
{
|
||||
internal class SparseArray64<TValue>
|
||||
internal unsafe class SparseArray64<TValue>
|
||||
where TValue : unmanaged
|
||||
{
|
||||
public const int MIN_CAPACITY_BITS_OFFSET = 4;
|
||||
public const int MIN_CAPACITY = 1 << MIN_CAPACITY_BITS_OFFSET;
|
||||
private const int EMPTY = -1;
|
||||
|
||||
private int[] _buckets = Array.Empty<int>();
|
||||
private Entry[] _entries = Array.Empty<Entry>();
|
||||
private UnsafeArray<int> _buckets;
|
||||
private UnsafeArray<Entry> _entries;
|
||||
|
||||
private int _count;
|
||||
|
||||
@ -28,26 +30,45 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
||||
#region Properties
|
||||
public TValue this[long keyX, long keyY]
|
||||
{
|
||||
get => _entries[FindEntry(keyX + (keyY << 32))].value;
|
||||
set => Insert(keyX + (keyY << 32), value);
|
||||
get
|
||||
{
|
||||
//TODO Проверить необходимость проверки на Null
|
||||
return _entries.ptr[FindEntry(keyX + (keyY << 32))].value;
|
||||
}
|
||||
set
|
||||
{
|
||||
Insert(keyX + (keyY << 32), value);
|
||||
}
|
||||
}
|
||||
public TValue this[long key]
|
||||
{
|
||||
get => _entries[FindEntry(key)].value;
|
||||
set => Insert(key, value);
|
||||
get
|
||||
{
|
||||
//TODO Проверить необходимость проверки на Null
|
||||
return _entries.ptr[FindEntry(key)].value;
|
||||
}
|
||||
set
|
||||
{
|
||||
Insert(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public int Count => _count;
|
||||
public int Count
|
||||
{
|
||||
get { return _count; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public SparseArray64(int minCapacity = MIN_CAPACITY)
|
||||
{
|
||||
minCapacity = NormalizeCapacity(minCapacity);
|
||||
_buckets = new int[minCapacity];
|
||||
_buckets = new UnsafeArray<int>(minCapacity);
|
||||
for (int i = 0; i < minCapacity; i++)
|
||||
{
|
||||
_buckets[i] = EMPTY;
|
||||
_entries = new Entry[minCapacity];
|
||||
}
|
||||
_entries = new UnsafeArray<Entry>(minCapacity);
|
||||
_modBitMask = (minCapacity - 1) & 0x7FFFFFFF;
|
||||
}
|
||||
#endregion
|
||||
@ -148,7 +169,7 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
value = _entries[index].value;
|
||||
value = _entries.ptr[index].value;
|
||||
return true;
|
||||
}
|
||||
public bool TryGetValue(long keyX, long keyY, out TValue value)
|
||||
@ -159,7 +180,7 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
value = _entries[index].value;
|
||||
value = _entries.ptr[index].value;
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
@ -184,7 +205,10 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
||||
{
|
||||
_buckets[i] = -1;
|
||||
}
|
||||
Array.Clear(_entries, 0, _count);
|
||||
for (int i = 0; i < _count; i++)
|
||||
{
|
||||
_entries[i] = default;
|
||||
}
|
||||
_count = 0;
|
||||
}
|
||||
}
|
||||
@ -197,12 +221,15 @@ namespace DCFApixels.DragonECS.Relations.Utils
|
||||
_modBitMask = (newSize - 1) & 0x7FFFFFFF;
|
||||
|
||||
Contract.Assert(newSize >= _entries.Length);
|
||||
int[] newBuckets = new int[newSize];
|
||||
UnsafeArray<int> newBuckets = new UnsafeArray<int>(newSize);
|
||||
for (int i = 0; i < newBuckets.Length; i++)
|
||||
newBuckets[i] = EMPTY;
|
||||
|
||||
Entry[] newEntries = new Entry[newSize];
|
||||
Array.Copy(_entries, 0, newEntries, 0, _count);
|
||||
UnsafeArray<Entry> newEntries = UnsafeArray<Entry>.Resize(_entries, newSize);
|
||||
//UnsafeArray<Entry> newEntries = new UnsafeArray<Entry>(newSize);
|
||||
//Array.Copy(_entries, 0, newEntries, 0, _count);
|
||||
|
||||
|
||||
for (int i = 0; i < _count; i++)
|
||||
{
|
||||
if (newEntries[i].hashKey >= 0)
|
||||
|
119
src/Utils/UnsafeArray.cs
Normal file
119
src/Utils/UnsafeArray.cs
Normal file
@ -0,0 +1,119 @@
|
||||
using DCFApixels.DragonECS.Utils;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DCFApixels.DragonECS.Relations.Internal
|
||||
{
|
||||
[DebuggerTypeProxy(typeof(UnsafeArray<>.DebuggerProxy))]
|
||||
internal unsafe struct UnsafeArray<T> : IDisposable, IEnumerable<T>
|
||||
where T : unmanaged
|
||||
{
|
||||
internal T* ptr;
|
||||
internal int Length;
|
||||
|
||||
public ref T this[int index]
|
||||
{
|
||||
get { return ref ptr[index]; }
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public UnsafeArray(int length)
|
||||
{
|
||||
UnmanagedArrayUtility.New(out ptr, length);
|
||||
Length = length;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public UnsafeArray(int length, bool isInit)
|
||||
{
|
||||
UnmanagedArrayUtility.NewAndInit(out ptr, length);
|
||||
Length = length;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private UnsafeArray(T* ptr, int length)
|
||||
{
|
||||
this.ptr = ptr;
|
||||
Length = length;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public UnsafeArray<T> Clone()
|
||||
{
|
||||
return new UnsafeArray<T>(UnmanagedArrayUtility.Clone(ptr, Length), Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Dispose()
|
||||
{
|
||||
UnmanagedArrayUtility.Free(ref ptr, ref Length);
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
T* ptr = this.ptr;
|
||||
return CollectionUtility.AutoToString(EnumerableInt.Range(0, Length).Select(i => ptr[i]), "ua");
|
||||
}
|
||||
|
||||
public static void Resize(ref UnsafeArray<T> array, int newSize)
|
||||
{
|
||||
array.ptr = UnmanagedArrayUtility.Resize<T>(array.ptr, newSize);
|
||||
array.Length = newSize;
|
||||
}
|
||||
public static UnsafeArray<T> Resize(UnsafeArray<T> array, int newSize)
|
||||
{
|
||||
return new UnsafeArray<T>(UnmanagedArrayUtility.Resize<T>(array.ptr, newSize), newSize);
|
||||
}
|
||||
|
||||
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Enumerator GetEnumerator() => new Enumerator(ptr, Length);
|
||||
public struct Enumerator : IEnumerator<T>
|
||||
{
|
||||
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];
|
||||
}
|
||||
object IEnumerator.Current => Current;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext() => ++_index < _length;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Reset() { }
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
internal class DebuggerProxy
|
||||
{
|
||||
public T[] elements;
|
||||
public int length;
|
||||
public DebuggerProxy(UnsafeArray<T> instance)
|
||||
{
|
||||
elements = EnumerableInt.Range(0, instance.Length).Select(i => instance.ptr[i]).ToArray();
|
||||
length = instance.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static class UnsafeArrayExtentions
|
||||
{
|
||||
public static void Resize<T>(ref UnsafeArray<T> self, int newSize)
|
||||
where T : unmanaged
|
||||
{
|
||||
UnsafeArray<T>.Resize(ref self, newSize);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user