This commit is contained in:
Mikhail 2024-02-03 21:37:11 +08:00
parent 3c79ea24e3
commit 08b25ed671
11 changed files with 448 additions and 147 deletions

View File

@ -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) { }
}
}

View File

@ -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

View File

@ -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
View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
namespace DCFApixels.DragonECS
{
public static class EcsWorldConfigRelationsExtensions
{
}
}

View File

@ -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);

View File

@ -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()))}}})";
}
}
}

View File

@ -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>

View File

@ -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.");
}
}
}

View File

@ -1,5 +1,4 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS
{

View File

@ -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
View 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);
}
}
}