From 255760a3d7f92cc9027f68f141c6cffc8ea333ec Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Fri, 20 Mar 2020 18:09:24 -0700 Subject: [PATCH] unmanaged component store --- encompass-cs/Collections/ComponentStore.cs | 2 +- encompass-cs/Collections/FixedArray.cs | 69 +++++++++++++++++++ .../Collections/TypedComponentStore.cs | 9 ++- test/ComponentTest.cs | 3 +- 4 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 encompass-cs/Collections/FixedArray.cs diff --git a/encompass-cs/Collections/ComponentStore.cs b/encompass-cs/Collections/ComponentStore.cs index e7d6491..2743e68 100644 --- a/encompass-cs/Collections/ComponentStore.cs +++ b/encompass-cs/Collections/ComponentStore.cs @@ -8,7 +8,7 @@ namespace Encompass { private Dictionary _stores = new Dictionary(512); public ComponentBitSet ComponentBitSet { get; private set; } - private Dictionary _typeToIndex; + private readonly Dictionary _typeToIndex; public ComponentStore(Dictionary typeToIndex) { diff --git a/encompass-cs/Collections/FixedArray.cs b/encompass-cs/Collections/FixedArray.cs new file mode 100644 index 0000000..242e9c6 --- /dev/null +++ b/encompass-cs/Collections/FixedArray.cs @@ -0,0 +1,69 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +internal unsafe class FixedArray : 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() * 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); + } +} diff --git a/encompass-cs/Collections/TypedComponentStore.cs b/encompass-cs/Collections/TypedComponentStore.cs index 0fd06fa..8ae25b6 100644 --- a/encompass-cs/Collections/TypedComponentStore.cs +++ b/encompass-cs/Collections/TypedComponentStore.cs @@ -14,11 +14,11 @@ namespace Encompass public abstract void ClearPriorities(); } - internal class TypedComponentStore : TypedComponentStore where TComponent : unmanaged + internal unsafe class TypedComponentStore : TypedComponentStore where TComponent : unmanaged { private readonly Dictionary _indices = new Dictionary(512); private readonly Dictionary _priorities = new Dictionary(512); - private readonly TComponent[] _components = new TComponent[512]; + private readonly FixedArray _components = new FixedArray(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(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(Unsafe.AsPointer(ref component)); + _components[_indices[entityID]] = component; } public override bool Remove(int entityID, int priority) diff --git a/test/ComponentTest.cs b/test/ComponentTest.cs index 684a07f..95c8f68 100644 --- a/test/ComponentTest.cs +++ b/test/ComponentTest.cs @@ -48,7 +48,8 @@ namespace Tests foreach (var addComponentTestMessage in ReadMessages()) { Assert.IsTrue(HasComponent(addComponentTestMessage.entity)); - Assert.That(GetComponent(addComponentTestMessage.entity), Is.EqualTo(addComponentTestMessage.mockComponent)); + var gottenComponent = GetComponent(addComponentTestMessage.entity); + gottenComponent.Should().BeEquivalentTo(addComponentTestMessage.mockComponent); } } }