unmanaged component store
continuous-integration/drone/push Build is passing Details

pull/3/head
Evan Hemsley 2020-03-20 18:09:24 -07:00
parent 408dd9bfeb
commit 255760a3d7
4 changed files with 76 additions and 7 deletions

View File

@ -8,7 +8,7 @@ namespace Encompass
{ {
private Dictionary<Type, TypedComponentStore> _stores = new Dictionary<Type, TypedComponentStore>(512); private Dictionary<Type, TypedComponentStore> _stores = new Dictionary<Type, TypedComponentStore>(512);
public ComponentBitSet ComponentBitSet { get; private set; } public ComponentBitSet ComponentBitSet { get; private set; }
private Dictionary<Type, int> _typeToIndex; private readonly Dictionary<Type, int> _typeToIndex;
public ComponentStore(Dictionary<Type, int> typeToIndex) public ComponentStore(Dictionary<Type, int> typeToIndex)
{ {

View File

@ -0,0 +1,69 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
internal unsafe class FixedArray<T> : IDisposable where T : unmanaged
{
private void* _buffer;
public int Length { get; private set; }
public T this[int i]
{
get { return ReadElement(_buffer, i); }
set { WriteElement(_buffer, i, value); }
}
public unsafe FixedArray(int length, bool clearMemory = false)
{
var bufferSize = Marshal.SizeOf<T>() * length;
_buffer = (void*)Alloc(bufferSize);
if (clearMemory)
{
Memset(_buffer, 0, bufferSize);
}
Length = length;
}
public ref T ByRef(int i)
{
return ref *(T*)((byte*)_buffer + i * sizeof(T));
}
void IDisposable.Dispose()
{
Free((IntPtr)_buffer);
_buffer = null;
Length = 0;
}
private static T ReadElement(void* buffer, int i)
{
return *(T*)((byte*)buffer + i * sizeof(T));
}
private static void WriteElement(void* buffer, int i, T value)
{
*(T*)((byte*)buffer + i * sizeof(T)) = value;
}
private unsafe static IntPtr Alloc(int size)
{
return Marshal.AllocHGlobal(size);
}
public unsafe static void Free(IntPtr ptr)
{
if (ptr != IntPtr.Zero)
{
Marshal.FreeHGlobal(ptr);
}
}
private unsafe static void Memset(void* ptr, byte value, int count)
{
Unsafe.InitBlock(ptr, value, (uint)count);
}
}

View File

@ -14,11 +14,11 @@ namespace Encompass
public abstract void ClearPriorities(); public abstract void ClearPriorities();
} }
internal class TypedComponentStore<TComponent> : TypedComponentStore where TComponent : unmanaged internal unsafe class TypedComponentStore<TComponent> : TypedComponentStore where TComponent : unmanaged
{ {
private readonly Dictionary<int, int> _indices = new Dictionary<int, int>(512); private readonly Dictionary<int, int> _indices = new Dictionary<int, int>(512);
private readonly Dictionary<int, int> _priorities = new Dictionary<int, int>(512); private readonly Dictionary<int, int> _priorities = new Dictionary<int, int>(512);
private readonly TComponent[] _components = new TComponent[512]; private readonly FixedArray<TComponent> _components = new FixedArray<TComponent>(512); // TODO: allow specify size
private readonly IDManager _idManager = new IDManager(); private readonly IDManager _idManager = new IDManager();
public override int Count { get => _indices.Count; } public override int Count { get => _indices.Count; }
@ -26,8 +26,7 @@ namespace Encompass
public unsafe ref readonly TComponent Get(int entityID) public unsafe ref readonly TComponent Get(int entityID)
{ {
if (!_indices.ContainsKey(entityID)) { throw new Exceptions.NoComponentOfTypeOnEntityException("No component of type {0} exists on Entity with ID {1}", typeof(TComponent), entityID); } if (!_indices.ContainsKey(entityID)) { throw new Exceptions.NoComponentOfTypeOnEntityException("No component of type {0} exists on Entity with ID {1}", typeof(TComponent), entityID); }
ref var refVal = ref _components[_indices[entityID]]; return ref _components.ByRef(_indices[entityID]);
return ref Unsafe.AsRef<TComponent>(Unsafe.AsPointer(ref refVal));
} }
public unsafe void Set(int entityID, TComponent component) public unsafe void Set(int entityID, TComponent component)
@ -54,7 +53,7 @@ namespace Encompass
_indices[entityID] = _idManager.NextID(); _indices[entityID] = _idManager.NextID();
} }
_components[_indices[entityID]] = Unsafe.AsRef<TComponent>(Unsafe.AsPointer(ref component)); _components[_indices[entityID]] = component;
} }
public override bool Remove(int entityID, int priority) public override bool Remove(int entityID, int priority)

View File

@ -48,7 +48,8 @@ namespace Tests
foreach (var addComponentTestMessage in ReadMessages<AddComponentTestMessage>()) foreach (var addComponentTestMessage in ReadMessages<AddComponentTestMessage>())
{ {
Assert.IsTrue(HasComponent<MockComponent>(addComponentTestMessage.entity)); Assert.IsTrue(HasComponent<MockComponent>(addComponentTestMessage.entity));
Assert.That(GetComponent<MockComponent>(addComponentTestMessage.entity), Is.EqualTo(addComponentTestMessage.mockComponent)); var gottenComponent = GetComponent<MockComponent>(addComponentTestMessage.entity);
gottenComponent.Should().BeEquivalentTo(addComponentTestMessage.mockComponent);
} }
} }
} }