refactor collections to use NativeMemory
parent
231575757e
commit
4722445f11
|
@ -89,7 +89,7 @@ namespace MoonTools.ECS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// these methods used to implement snapshots, templates, and debugging
|
// these methods used to implement transfers and debugging
|
||||||
|
|
||||||
internal unsafe void* UntypedGet(int entityID, int componentTypeIndex)
|
internal unsafe void* UntypedGet(int entityID, int componentTypeIndex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS
|
||||||
{
|
{
|
||||||
|
@ -19,16 +21,24 @@ namespace MoonTools.ECS
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class ComponentStorage<TComponent> : ComponentStorage where TComponent : unmanaged
|
internal unsafe class ComponentStorage<TComponent> : ComponentStorage, IDisposable where TComponent : unmanaged
|
||||||
{
|
{
|
||||||
private int nextID;
|
|
||||||
private readonly Dictionary<int, int> entityIDToStorageIndex = new Dictionary<int, int>(16);
|
private readonly Dictionary<int, int> entityIDToStorageIndex = new Dictionary<int, int>(16);
|
||||||
private int[] entityIDs = new int[16];
|
private TComponent* components;
|
||||||
private TComponent[] components = new TComponent[16];
|
private int* entityIDs;
|
||||||
|
private int count = 0;
|
||||||
|
private int capacity = 16;
|
||||||
|
private bool disposed;
|
||||||
|
|
||||||
|
public ComponentStorage()
|
||||||
|
{
|
||||||
|
components = (TComponent*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf<TComponent>()));
|
||||||
|
entityIDs = (int*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf<int>()));
|
||||||
|
}
|
||||||
|
|
||||||
public bool Any()
|
public bool Any()
|
||||||
{
|
{
|
||||||
return nextID > 0;
|
return count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ref readonly TComponent Get(int entityID)
|
public ref readonly TComponent Get(int entityID)
|
||||||
|
@ -38,16 +48,13 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
internal override unsafe void* UntypedGet(int entityID)
|
internal override unsafe void* UntypedGet(int entityID)
|
||||||
{
|
{
|
||||||
fixed (void* p = &components[entityIDToStorageIndex[entityID]])
|
return &components[entityIDToStorageIndex[entityID]];
|
||||||
{
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ref readonly TComponent GetFirst()
|
public ref readonly TComponent GetFirst()
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (nextID == 0)
|
if (count == 0)
|
||||||
{
|
{
|
||||||
throw new IndexOutOfRangeException("Component storage is empty!");
|
throw new IndexOutOfRangeException("Component storage is empty!");
|
||||||
}
|
}
|
||||||
|
@ -59,13 +66,14 @@ namespace MoonTools.ECS
|
||||||
{
|
{
|
||||||
if (!entityIDToStorageIndex.ContainsKey(entityID))
|
if (!entityIDToStorageIndex.ContainsKey(entityID))
|
||||||
{
|
{
|
||||||
var index = nextID;
|
var index = count;
|
||||||
nextID += 1;
|
count += 1;
|
||||||
|
|
||||||
if (index >= components.Length)
|
if (index >= capacity)
|
||||||
{
|
{
|
||||||
Array.Resize(ref components, components.Length * 2);
|
capacity *= 2;
|
||||||
Array.Resize(ref entityIDs, entityIDs.Length * 2);
|
components = (TComponent*) NativeMemory.Realloc(components, (nuint) (capacity * Unsafe.SizeOf<TComponent>()));
|
||||||
|
entityIDs = (int*) NativeMemory.Realloc(entityIDs, (nuint) (capacity * Unsafe.SizeOf<int>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
entityIDToStorageIndex[entityID] = index;
|
entityIDToStorageIndex[entityID] = index;
|
||||||
|
@ -77,7 +85,7 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
internal override unsafe void Set(int entityID, void* component)
|
internal override unsafe void Set(int entityID, void* component)
|
||||||
{
|
{
|
||||||
Set(entityID, *((TComponent*) component));
|
Set(entityID, *(TComponent*) component);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the entity had this component.
|
// Returns true if the entity had this component.
|
||||||
|
@ -87,7 +95,7 @@ namespace MoonTools.ECS
|
||||||
{
|
{
|
||||||
entityIDToStorageIndex.Remove(entityID);
|
entityIDToStorageIndex.Remove(entityID);
|
||||||
|
|
||||||
var lastElementIndex = nextID - 1;
|
var lastElementIndex = count - 1;
|
||||||
|
|
||||||
// move a component into the hole to maintain contiguous memory
|
// move a component into the hole to maintain contiguous memory
|
||||||
if (lastElementIndex != storageIndex)
|
if (lastElementIndex != storageIndex)
|
||||||
|
@ -98,7 +106,7 @@ namespace MoonTools.ECS
|
||||||
entityIDs[storageIndex] = lastEntityID;
|
entityIDs[storageIndex] = lastEntityID;
|
||||||
}
|
}
|
||||||
|
|
||||||
nextID -= 1;
|
count -= 1;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -108,19 +116,19 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
public override void Clear()
|
public override void Clear()
|
||||||
{
|
{
|
||||||
nextID = 0;
|
count = 0;
|
||||||
entityIDToStorageIndex.Clear();
|
entityIDToStorageIndex.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlySpan<TComponent> AllComponents()
|
public ReadOnlySpan<TComponent> AllComponents()
|
||||||
{
|
{
|
||||||
return new ReadOnlySpan<TComponent>(components, 0, nextID);
|
return new ReadOnlySpan<TComponent>(components, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Entity FirstEntity()
|
public Entity FirstEntity()
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (nextID == 0)
|
if (count == 0)
|
||||||
{
|
{
|
||||||
throw new IndexOutOfRangeException("Component storage is empty!");
|
throw new IndexOutOfRangeException("Component storage is empty!");
|
||||||
}
|
}
|
||||||
|
@ -143,6 +151,32 @@ namespace MoonTools.ECS
|
||||||
{
|
{
|
||||||
return entityIDToStorageIndex.Keys;
|
return entityIDToStorageIndex.Keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!disposed)
|
||||||
|
{
|
||||||
|
NativeMemory.Free(components);
|
||||||
|
NativeMemory.Free(entityIDs);
|
||||||
|
components = null;
|
||||||
|
entityIDs = null;
|
||||||
|
|
||||||
|
disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~ComponentStorage()
|
||||||
|
{
|
||||||
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||||
|
Dispose(disposing: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||||
|
Dispose(disposing: true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,69 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS.Collections
|
||||||
{
|
{
|
||||||
public class DynamicArray<T> where T : unmanaged
|
public unsafe class NativeArray<T> : IDisposable where T : unmanaged
|
||||||
{
|
{
|
||||||
private T[] Array;
|
private T* Array;
|
||||||
public int Count { get; private set; }
|
private int count;
|
||||||
|
private int capacity;
|
||||||
|
|
||||||
public Span<T> ToSpan() => new Span<T>(Array, 0, Count);
|
public int Count => count;
|
||||||
public ReverseSpanEnumerator<T> GetEnumerator() => new ReverseSpanEnumerator<T>(new Span<T>(Array, 0, Count));
|
|
||||||
|
|
||||||
public DynamicArray(int capacity = 16)
|
public ReverseSpanEnumerator<T> GetEnumerator() => new ReverseSpanEnumerator<T>(new Span<T>(Array, Count));
|
||||||
|
|
||||||
|
private bool disposed;
|
||||||
|
|
||||||
|
public NativeArray(int capacity = 16)
|
||||||
{
|
{
|
||||||
Array = new T[capacity];
|
this.capacity = capacity;
|
||||||
Count = 0;
|
Array = (T*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf<T>()));
|
||||||
|
count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ref T this[int i]
|
public ref T this[int i] => ref Array[i];
|
||||||
{
|
|
||||||
get { return ref Array[i]; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(T item)
|
public void Add(T item)
|
||||||
{
|
{
|
||||||
if (Count >= Array.Length)
|
if (count >= capacity)
|
||||||
{
|
{
|
||||||
global::System.Array.Resize(ref Array, Array.Length * 2);
|
capacity *= 2;
|
||||||
|
Array = (T*) NativeMemory.Realloc(Array, (nuint) (capacity * Unsafe.SizeOf<T>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Array[Count] = item;
|
Array[count] = item;
|
||||||
Count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
Count = 0;
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!disposed)
|
||||||
|
{
|
||||||
|
NativeMemory.Free(Array);
|
||||||
|
Array = null;
|
||||||
|
|
||||||
|
disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~NativeArray()
|
||||||
|
{
|
||||||
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||||
|
Dispose(disposing: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||||
|
Dispose(disposing: true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using MoonTools.ECS.Collections;
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,26 +1,31 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS.Collections
|
||||||
{
|
{
|
||||||
internal class IndexableSet<T> where T : unmanaged
|
public unsafe class IndexableSet<T> : IDisposable where T : unmanaged
|
||||||
{
|
{
|
||||||
private Dictionary<T, int> indices;
|
private Dictionary<T, int> indices;
|
||||||
private T[] array;
|
private T* array;
|
||||||
public int Count { get; private set; }
|
private int count;
|
||||||
public ReverseSpanEnumerator<T> GetEnumerator() => new ReverseSpanEnumerator<T>(new Span<T>(array, 0, Count));
|
private int capacity;
|
||||||
|
private bool disposed;
|
||||||
|
|
||||||
public IndexableSet(int size = 32)
|
public int Count => count;
|
||||||
|
public ReverseSpanEnumerator<T> GetEnumerator() => new ReverseSpanEnumerator<T>(new Span<T>(array, count));
|
||||||
|
|
||||||
|
public IndexableSet(int capacity = 32)
|
||||||
{
|
{
|
||||||
indices = new Dictionary<T, int>(size);
|
this.capacity = capacity;
|
||||||
array = new T[size];
|
count = 0;
|
||||||
|
|
||||||
|
indices = new Dictionary<T, int>(capacity);
|
||||||
|
array = (T*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf<T>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public T this[int i]
|
public T this[int i] => array[i];
|
||||||
{
|
|
||||||
get { return array[i]; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(T element)
|
public bool Contains(T element)
|
||||||
{
|
{
|
||||||
|
@ -31,15 +36,16 @@ namespace MoonTools.ECS
|
||||||
{
|
{
|
||||||
if (!Contains(element))
|
if (!Contains(element))
|
||||||
{
|
{
|
||||||
indices.Add(element, Count);
|
indices.Add(element, count);
|
||||||
|
|
||||||
if (Count >= array.Length)
|
if (count >= capacity)
|
||||||
{
|
{
|
||||||
Array.Resize(ref array, array.Length * 2);
|
capacity *= 2;
|
||||||
|
array = (T*) NativeMemory.Realloc(array, (nuint) (capacity * Unsafe.SizeOf<T>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
array[Count] = element;
|
array[count] = element;
|
||||||
Count += 1;
|
count += 1;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -58,7 +64,7 @@ namespace MoonTools.ECS
|
||||||
var index = indices[element];
|
var index = indices[element];
|
||||||
array[index] = lastElement;
|
array[index] = lastElement;
|
||||||
indices[lastElement] = index;
|
indices[lastElement] = index;
|
||||||
Count -= 1;
|
count -= 1;
|
||||||
indices.Remove(element);
|
indices.Remove(element);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -66,45 +72,32 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
Count = 0;
|
indices.Clear();
|
||||||
|
count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct Enumerator
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
/// <summary>The set being enumerated.</summary>
|
if (!disposed)
|
||||||
private readonly IndexableSet<T> _set;
|
|
||||||
/// <summary>The next index to yield.</summary>
|
|
||||||
private int _index;
|
|
||||||
|
|
||||||
/// <summary>Initialize the enumerator.</summary>
|
|
||||||
/// <param name="set">The set to enumerate.</param>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal Enumerator(IndexableSet<T> set)
|
|
||||||
{
|
{
|
||||||
_set = set;
|
NativeMemory.Free(array);
|
||||||
_index = _set.Count;
|
array = null;
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Advances the enumerator to the next element of the span.</summary>
|
disposed = true;
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool MoveNext()
|
|
||||||
{
|
|
||||||
int index = _index - 1;
|
|
||||||
if (index >= 0)
|
|
||||||
{
|
|
||||||
_index = index;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Gets the element at the current position of the enumerator.</summary>
|
~IndexableSet()
|
||||||
public T Current
|
{
|
||||||
{
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
Dispose(disposing: false);
|
||||||
get => _set[_index];
|
}
|
||||||
}
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||||
|
Dispose(disposing: true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using MoonTools.ECS.Collections;
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS
|
||||||
{
|
{
|
||||||
|
@ -8,17 +11,18 @@ namespace MoonTools.ECS
|
||||||
public abstract void Clear();
|
public abstract void Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class MessageStorage<TMessage> : MessageStorage where TMessage : unmanaged
|
internal unsafe class MessageStorage<TMessage> : MessageStorage, IDisposable where TMessage : unmanaged
|
||||||
{
|
{
|
||||||
private int count = 0;
|
private int count = 0;
|
||||||
private int capacity = 128;
|
private int capacity = 128;
|
||||||
private TMessage[] messages;
|
private TMessage* messages;
|
||||||
// duplicating storage here for fast iteration
|
// duplicating storage here for fast iteration
|
||||||
private Dictionary<int, DynamicArray<TMessage>> entityToMessages = new Dictionary<int, DynamicArray<TMessage>>();
|
private Dictionary<int, NativeArray<TMessage>> entityToMessages = new Dictionary<int, NativeArray<TMessage>>();
|
||||||
|
private bool disposed;
|
||||||
|
|
||||||
public MessageStorage()
|
public MessageStorage()
|
||||||
{
|
{
|
||||||
messages = new TMessage[capacity];
|
messages = (TMessage*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf<TMessage>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(in TMessage message)
|
public void Add(in TMessage message)
|
||||||
|
@ -26,7 +30,7 @@ namespace MoonTools.ECS
|
||||||
if (count == capacity)
|
if (count == capacity)
|
||||||
{
|
{
|
||||||
capacity *= 2;
|
capacity *= 2;
|
||||||
Array.Resize(ref messages, capacity);
|
messages = (TMessage*) NativeMemory.Realloc(messages, (nuint) (capacity * Unsafe.SizeOf<TMessage>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
messages[count] = message;
|
messages[count] = message;
|
||||||
|
@ -37,7 +41,7 @@ namespace MoonTools.ECS
|
||||||
{
|
{
|
||||||
if (!entityToMessages.ContainsKey(entityID))
|
if (!entityToMessages.ContainsKey(entityID))
|
||||||
{
|
{
|
||||||
entityToMessages.Add(entityID, new DynamicArray<TMessage>());
|
entityToMessages.Add(entityID, new NativeArray<TMessage>());
|
||||||
}
|
}
|
||||||
entityToMessages[entityID].Add(message);
|
entityToMessages[entityID].Add(message);
|
||||||
|
|
||||||
|
@ -51,7 +55,7 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
public ReadOnlySpan<TMessage> All()
|
public ReadOnlySpan<TMessage> All()
|
||||||
{
|
{
|
||||||
return new ReadOnlySpan<TMessage>(messages, 0, count);
|
return new ReadOnlySpan<TMessage>(messages, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TMessage First()
|
public TMessage First()
|
||||||
|
@ -89,5 +93,39 @@ namespace MoonTools.ECS
|
||||||
set.Clear();
|
set.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!disposed)
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
foreach (var array in entityToMessages.Values)
|
||||||
|
{
|
||||||
|
array.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeMemory.Free(messages);
|
||||||
|
messages = null;
|
||||||
|
|
||||||
|
disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~MessageStorage()
|
||||||
|
{
|
||||||
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||||
|
Dispose(disposing: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||||
|
Dispose(disposing: true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using MoonTools.ECS.Collections;
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS
|
||||||
{
|
{
|
||||||
|
@ -16,19 +19,28 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
// Relation is the two entities, A related to B.
|
// Relation is the two entities, A related to B.
|
||||||
// TRelation is the data attached to the relation.
|
// TRelation is the data attached to the relation.
|
||||||
internal class RelationStorage<TRelation> : RelationStorage where TRelation : unmanaged
|
internal unsafe class RelationStorage<TRelation> : RelationStorage, IDisposable where TRelation : unmanaged
|
||||||
{
|
{
|
||||||
private int count = 0;
|
private int count = 0;
|
||||||
|
private int capacity = 16;
|
||||||
|
private (Entity, Entity)* relations;
|
||||||
|
private TRelation* relationDatas;
|
||||||
private Dictionary<(Entity, Entity), int> indices = new Dictionary<(Entity, Entity), int>(16);
|
private Dictionary<(Entity, Entity), int> indices = new Dictionary<(Entity, Entity), int>(16);
|
||||||
private (Entity, Entity)[] relations = new (Entity, Entity)[16];
|
|
||||||
private TRelation[] relationDatas = new TRelation[16];
|
|
||||||
private Dictionary<int, IndexableSet<Entity>> outRelations = new Dictionary<int, IndexableSet<Entity>>(16);
|
private Dictionary<int, IndexableSet<Entity>> outRelations = new Dictionary<int, IndexableSet<Entity>>(16);
|
||||||
private Dictionary<int, IndexableSet<Entity>> inRelations = new Dictionary<int, IndexableSet<Entity>>(16);
|
private Dictionary<int, IndexableSet<Entity>> inRelations = new Dictionary<int, IndexableSet<Entity>>(16);
|
||||||
private Stack<IndexableSet<Entity>> listPool = new Stack<IndexableSet<Entity>>();
|
private Stack<IndexableSet<Entity>> listPool = new Stack<IndexableSet<Entity>>();
|
||||||
|
|
||||||
|
private bool disposed;
|
||||||
|
|
||||||
|
public RelationStorage()
|
||||||
|
{
|
||||||
|
relations = ((Entity, Entity)*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf<(Entity, Entity)>()));
|
||||||
|
relationDatas = (TRelation*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf<TRelation>()));
|
||||||
|
}
|
||||||
|
|
||||||
public ReverseSpanEnumerator<(Entity, Entity)> All()
|
public ReverseSpanEnumerator<(Entity, Entity)> All()
|
||||||
{
|
{
|
||||||
return new ReverseSpanEnumerator<(Entity, Entity)>(new Span<(Entity, Entity)>(relations, 0, count));
|
return new ReverseSpanEnumerator<(Entity, Entity)>(new Span<(Entity, Entity)>(relations, count));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Set(in Entity entityA, in Entity entityB, TRelation relationData)
|
public void Set(in Entity entityA, in Entity entityB, TRelation relationData)
|
||||||
|
@ -56,10 +68,11 @@ namespace MoonTools.ECS
|
||||||
}
|
}
|
||||||
inRelations[idB].Add(idA);
|
inRelations[idB].Add(idA);
|
||||||
|
|
||||||
if (count >= relationDatas.Length)
|
if (count >= capacity)
|
||||||
{
|
{
|
||||||
Array.Resize(ref relations, relations.Length * 2);
|
capacity *= 2;
|
||||||
Array.Resize(ref relationDatas, relationDatas.Length * 2);
|
relations = ((Entity, Entity)*) NativeMemory.Realloc(relations, (nuint) (capacity * Unsafe.SizeOf<(Entity, Entity)>()));
|
||||||
|
relationDatas = (TRelation*) NativeMemory.Realloc(relationDatas, (nuint) (capacity * Unsafe.SizeOf<TRelation>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
relations[count] = relation;
|
relations[count] = relation;
|
||||||
|
@ -219,7 +232,7 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
public override unsafe void Set(int entityA, int entityB, void* relationData)
|
public override unsafe void Set(int entityA, int entityB, void* relationData)
|
||||||
{
|
{
|
||||||
Set(entityA, entityB, *((TRelation*) relationData));
|
Set(entityA, entityB, *(TRelation*) relationData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetStorageIndex(int entityA, int entityB)
|
public override int GetStorageIndex(int entityA, int entityB)
|
||||||
|
@ -229,10 +242,7 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
public override unsafe void* Get(int relationStorageIndex)
|
public override unsafe void* Get(int relationStorageIndex)
|
||||||
{
|
{
|
||||||
fixed (void* p = &relationDatas[relationStorageIndex])
|
return &relationDatas[relationStorageIndex];
|
||||||
{
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UnrelateAll(int entityID)
|
public override void UnrelateAll(int entityID)
|
||||||
|
@ -282,5 +292,41 @@ namespace MoonTools.ECS
|
||||||
}
|
}
|
||||||
outRelations.Clear();
|
outRelations.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!disposed)
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
foreach (var set in listPool)
|
||||||
|
{
|
||||||
|
set.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeMemory.Free(relations);
|
||||||
|
NativeMemory.Free(relationDatas);
|
||||||
|
relations = null;
|
||||||
|
relationDatas = null;
|
||||||
|
|
||||||
|
disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~RelationStorage()
|
||||||
|
{
|
||||||
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||||
|
Dispose(disposing: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||||
|
Dispose(disposing: true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue