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);
public ComponentBitSet ComponentBitSet { get; private set; }
private Dictionary<Type, int> _typeToIndex;
private readonly 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();
}
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> _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();
public override int Count { get => _indices.Count; }
@ -26,8 +26,7 @@ namespace Encompass
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); }
ref var refVal = ref _components[_indices[entityID]];
return ref Unsafe.AsRef<TComponent>(Unsafe.AsPointer(ref refVal));
return ref _components.ByRef(_indices[entityID]);
}
public unsafe void Set(int entityID, TComponent component)
@ -54,7 +53,7 @@ namespace Encompass
_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)

View File

@ -48,7 +48,8 @@ namespace Tests
foreach (var addComponentTestMessage in ReadMessages<AddComponentTestMessage>())
{
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);
}
}
}