diff --git a/Svelto.Common b/Svelto.Common
index 800c1a9..7d7aaba 160000
--- a/Svelto.Common
+++ b/Svelto.Common
@@ -1 +1 @@
-Subproject commit 800c1a9abe35986fabb6562178e27d3b17c34b5c
+Subproject commit 7d7aaba893e8aa0a24b8c36b46a8ed805a8f514c
diff --git a/Svelto.ECS/.github/FUNDING.yml b/Svelto.ECS/.github/FUNDING.yml
deleted file mode 100644
index f6dca80..0000000
--- a/Svelto.ECS/.github/FUNDING.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-# These are supported funding model platforms
-
-custom: https://www.paypal.me/smandala
diff --git a/Svelto.ECS/.gitignore b/Svelto.ECS/.gitignore
deleted file mode 100644
index 7ef0a76..0000000
--- a/Svelto.ECS/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-/obj
-/bin/Release/netstandard2.0
-/bin/Debug/netstandard2.0
diff --git a/Svelto.ECS/.gitmodules b/Svelto.ECS/.gitmodules
deleted file mode 100644
index cd05d00..0000000
--- a/Svelto.ECS/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "Svelto.Common"]
- path = Svelto.Common
- url = https://github.com/sebas77/Svelto.Common
diff --git a/Svelto.ECS/CheckEntityUtilities.cs b/Svelto.ECS/CheckEntityUtilities.cs
index e85326b..a002893 100644
--- a/Svelto.ECS/CheckEntityUtilities.cs
+++ b/Svelto.ECS/CheckEntityUtilities.cs
@@ -1,29 +1,30 @@
#if DEBUG && !PROFILE_SVELTO
+using System;
using System.Collections.Generic;
using Svelto.DataStructures;
#else
+using System;
using System.Diagnostics;
#endif
namespace Svelto.ECS
{
///
- /// Note: this check doesn't catch the case when an add and remove is done on the same entity before the next
- /// submission. Two operations on the same entity are not allowed between submissions.
+ /// Note: this check doesn't catch the case when an add and remove is done on the same entity before the nextI am
+ /// submission. Two operations on the same entity are not allowed between submissions.
///
public partial class EnginesRoot
{
-#if DEBUG && !PROFILE_SVELTO
- void CheckRemoveEntityID(EGID egid)
+#if DEBUG && !PROFILE_SVELTO
+ void CheckRemoveEntityID(EGID egid, Type entityComponent, string caller = "")
{
- // Console.LogError("removed".FastConcat(egid.ToString()));
if (_idCheckers.TryGetValue(egid.groupID, out var hash))
{
if (hash.Contains(egid.entityID) == false)
throw new ECSException("Entity with not found ID is about to be removed: id: "
- .FastConcat(egid.entityID)
- .FastConcat(" groupid: ")
- .FastConcat(egid.groupID));
+ .FastConcat(" caller: ", caller, " ")
+ .FastConcat(egid.entityID).FastConcat(" groupid: ").FastConcat(egid.groupID.ToName())
+ .FastConcat(" type: ").FastConcat(entityComponent != null ? entityComponent.Name : "not available"));
hash.Remove(egid.entityID);
@@ -33,46 +34,39 @@ namespace Svelto.ECS
else
{
throw new ECSException("Entity with not found ID is about to be removed: id: "
- .FastConcat(egid.entityID)
- .FastConcat(" groupid: ")
- .FastConcat(egid.groupID));
+ .FastConcat(" caller: ", caller, " ")
+ .FastConcat(egid.entityID).FastConcat(" groupid: ").FastConcat(egid.groupID.ToName())
+ .FastConcat(" type: ").FastConcat(entityComponent != null ? entityComponent.Name : "not available"));
}
}
- void CheckAddEntityID(EGID egid)
+ void CheckAddEntityID(EGID egid, Type entityComponent, string caller = "")
{
// Console.LogError("added ".FastConcat(egid.ToString()));
-
+
if (_idCheckers.TryGetValue(egid.groupID, out var hash) == false)
hash = _idCheckers[egid.groupID] = new HashSet();
else
- {
if (hash.Contains(egid.entityID))
throw new ECSException("Entity with used ID is about to be built: '"
- .FastConcat("' id: '")
- .FastConcat(egid.entityID)
- .FastConcat("' groupid: '")
- .FastConcat(egid.groupID)
- .FastConcat("'"));
- }
-
+ .FastConcat("' id: '").FastConcat(egid.entityID).FastConcat("' groupid: '")
+ .FastConcat(egid.groupID.ToName()).FastConcat(" ", entityComponent != null ? entityComponent.Name : "not available")
+ .FastConcat("'"));
+
hash.Add(egid.entityID);
}
-
- void RemoveGroupID(ExclusiveGroupStruct groupID)
- {
- _idCheckers.Remove(groupID);
- }
+
+ void RemoveGroupID(ExclusiveGroupStruct groupID) { _idCheckers.Remove(groupID); }
readonly FasterDictionary> _idCheckers = new FasterDictionary>();
#else
[Conditional("_CHECKS_DISABLED")]
- void CheckRemoveEntityID(EGID egid)
+ void CheckRemoveEntityID(EGID egid, Type entityComponent, string caller = "")
{
}
[Conditional("_CHECKS_DISABLED")]
- void CheckAddEntityID(EGID egid)
+ void CheckAddEntityID(EGID egid, Type entityComponen, string caller = "")
{
}
@@ -82,4 +76,4 @@ namespace Svelto.ECS
}
#endif
}
-}
+}
\ No newline at end of file
diff --git a/Svelto.ECS/EntityBuilder.CheckFields.cs b/Svelto.ECS/ComponentBuilder.CheckFields.cs
similarity index 94%
rename from Svelto.ECS/EntityBuilder.CheckFields.cs
rename to Svelto.ECS/ComponentBuilder.CheckFields.cs
index 0895f16..6ff8372 100644
--- a/Svelto.ECS/EntityBuilder.CheckFields.cs
+++ b/Svelto.ECS/ComponentBuilder.CheckFields.cs
@@ -7,7 +7,7 @@ using System.Reflection;
namespace Svelto.ECS
{
- internal static class EntityBuilderUtilities
+ internal static class ComponentBuilderUtilities
{
const string MSG = "Entity Structs field and Entity View Struct components must hold value types.";
@@ -48,16 +48,16 @@ namespace Svelto.ECS
if (fields.Length < 1)
{
- ProcessError("Entity View Structs must hold only entity components interfaces.", entityComponentType);
+ ProcessError("No valid fields found in Entity View Struct", entityComponentType);
}
for (int i = fields.Length - 1; i >= 0; --i)
{
FieldInfo fieldInfo = fields[i];
- if (fieldInfo.FieldType.IsInterfaceEx() == false)
+ if (fieldInfo.FieldType.IsInterfaceEx() == false && fieldInfo.FieldType.IsValueTypeEx() == false)
{
- ProcessError("Entity View Structs must hold only entity components interfaces.",
+ ProcessError("Entity View Structs must hold only public interfaces or value type fields.",
entityComponentType);
}
@@ -120,7 +120,7 @@ namespace Svelto.ECS
static readonly Type SERIALIZABLE_ENTITY_STRUCT = typeof(SerializableEntityComponent);
static readonly Type STRINGTYPE = typeof(string);
- internal static readonly Type ENTITY_STRUCT_INFO_VIEW = typeof(EntityInfoComponentView);
+ internal static readonly Type ENTITY_STRUCT_INFO_VIEW = typeof(EntityInfoViewComponent);
}
public class EntityComponentException : Exception
diff --git a/Svelto.ECS/ComponentBuilder.cs b/Svelto.ECS/ComponentBuilder.cs
index 5b58344..f36c1c8 100644
--- a/Svelto.ECS/ComponentBuilder.cs
+++ b/Svelto.ECS/ComponentBuilder.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
+using Svelto.Common;
using Svelto.DataStructures;
using Svelto.ECS.Hybrid;
using Svelto.ECS.Internal;
@@ -13,11 +14,6 @@ namespace Svelto.ECS
public ComponentBuilder()
{
_initializer = DEFAULT_IT;
-
- EntityBuilderUtilities.CheckFields(ENTITY_COMPONENT_TYPE, IS_ENTITY_VIEW_COMPONENT);
-
- if (IS_ENTITY_VIEW_COMPONENT)
- EntityViewComponentCache.InitCache();
}
public ComponentBuilder(in T initializer) : this()
@@ -36,8 +32,6 @@ namespace Svelto.ECS
T entityComponent = default;
if (IS_ENTITY_VIEW_COMPONENT)
{
- DBC.ECS.Check.Require(implementors != null,
- $"Implementors not found while building an EntityComponent `{typeof(T)}`");
DBC.ECS.Check.Require(castedDic.ContainsKey(egid.entityID) == false,
$"building an entity with already used entity id! id: '{(ulong) egid}', {ENTITY_COMPONENT_NAME}");
@@ -82,21 +76,35 @@ namespace Svelto.ECS
IS_ENTITY_VIEW_COMPONENT = typeof(IEntityViewComponent).IsAssignableFrom(ENTITY_COMPONENT_TYPE);
HAS_EGID = typeof(INeedEGID).IsAssignableFrom(ENTITY_COMPONENT_TYPE);
ENTITY_COMPONENT_NAME = ENTITY_COMPONENT_TYPE.ToString();
-#if UNITY_ECS
- EntityComponentIDMap.Register(new Filler());
-#endif
+ var IS_UNMANAGED = ENTITY_COMPONENT_TYPE.IsUnmanaged();
+
+ if (IS_UNMANAGED)
+ EntityComponentIDMap.Register(new Filler());
+
SetEGIDWithoutBoxing.Warmup();
+
+ ComponentBuilderUtilities.CheckFields(ENTITY_COMPONENT_TYPE, IS_ENTITY_VIEW_COMPONENT);
+
+ if (IS_ENTITY_VIEW_COMPONENT)
+ EntityViewComponentCache.InitCache();
+ else
+ {
+ if (ENTITY_COMPONENT_TYPE != ComponentBuilderUtilities.ENTITY_STRUCT_INFO_VIEW && ENTITY_COMPONENT_TYPE.IsUnmanaged() == false)
+ throw new Exception($"Entity Component check failed, unexpected struct type (must be unmanaged) {ENTITY_COMPONENT_TYPE}");
+ }
}
+
readonly T _initializer;
internal static readonly Type ENTITY_COMPONENT_TYPE;
- public static readonly bool HAS_EGID;
+ public static readonly bool HAS_EGID;
+ internal static readonly bool IS_ENTITY_VIEW_COMPONENT;
- static readonly T DEFAULT_IT;
- static readonly bool IS_ENTITY_VIEW_COMPONENT;
- static readonly string ENTITY_COMPONENT_NAME;
+ static readonly T DEFAULT_IT;
+ static readonly string ENTITY_COMPONENT_NAME;
+
static class EntityViewComponentCache
{
internal static readonly FasterList>> cachedFields;
@@ -116,11 +124,13 @@ namespace Svelto.ECS
for (var i = fields.Length - 1; i >= 0; --i)
{
var field = fields[i];
- DBC.ECS.Check.Require(field.FieldType.IsInterface == true, "Entity View Components must hold only public interfaces");
- var setter = FastInvoke.MakeSetter(field);
+ if (field.FieldType.IsInterface == true)
+ {
+ var setter = FastInvoke.MakeSetter(field);
- //for each interface, cache the setter for this type
- cachedFields.Add(new KeyValuePair>(field.FieldType, setter));
+ //for each interface, cache the setter for this type
+ cachedFields.Add(new KeyValuePair>(field.FieldType, setter));
+ }
}
cachedTypes = new Dictionary();
diff --git a/Svelto.ECS/DataStructures/AtomicNativeBags.cs b/Svelto.ECS/DataStructures/AtomicNativeBags.cs
index 0a99862..c858617 100644
--- a/Svelto.ECS/DataStructures/AtomicNativeBags.cs
+++ b/Svelto.ECS/DataStructures/AtomicNativeBags.cs
@@ -12,13 +12,13 @@ namespace Svelto.ECS.DataStructures.Unity
public unsafe struct AtomicNativeBags:IDisposable
{
public const int DefaultThreadIndex = -1;
- public const int MinThreadIndex = DefaultThreadIndex;
+ const int MinThreadIndex = DefaultThreadIndex;
-#if UNITY_ECS
+#if UNITY_COLLECTIONS
[global::Unity.Collections.LowLevel.Unsafe.NativeDisableUnsafePtrRestriction]
#endif
- NativeBag* _data;
- public readonly Allocator Allocator;
+ readonly NativeBag* _data;
+ readonly Allocator _allocator;
readonly uint _threadsCount;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -26,20 +26,20 @@ namespace Svelto.ECS.DataStructures.Unity
public AtomicNativeBags(Common.Allocator allocator, uint threadsCount)
{
- Allocator = allocator;
+ _allocator = allocator;
_threadsCount = threadsCount;
var bufferSize = MemoryUtilities.SizeOf();
var bufferCount = _threadsCount;
var allocationSize = bufferSize * bufferCount;
- var ptr = (byte*)MemoryUtilities.Alloc((uint) allocationSize, allocator);
+ var ptr = (byte*)MemoryUtilities.Alloc((uint) allocationSize, allocator);
MemoryUtilities.MemClear((IntPtr) ptr, (uint) allocationSize);
for (int i = 0; i < bufferCount; i++)
{
var bufferPtr = (NativeBag*)(ptr + bufferSize * i);
- var buffer = new NativeBag((uint) i, allocator);
+ var buffer = new NativeBag(allocator);
MemoryUtilities.CopyStructureToPtr(ref buffer, (IntPtr) bufferPtr);
}
@@ -60,7 +60,7 @@ namespace Svelto.ECS.DataStructures.Unity
{
GetBuffer(i).Dispose();
}
- MemoryUtilities.Free((IntPtr) _data, Allocator);
+ MemoryUtilities.Free((IntPtr) _data, _allocator);
}
public void Clear()
diff --git a/Svelto.ECS/DataStructures/FastTypeSafeDictionary.cs b/Svelto.ECS/DataStructures/FastTypeSafeDictionary.cs
index 19cb75d..dc55efc 100644
--- a/Svelto.ECS/DataStructures/FastTypeSafeDictionary.cs
+++ b/Svelto.ECS/DataStructures/FastTypeSafeDictionary.cs
@@ -264,11 +264,6 @@ namespace Svelto.ECS.Internal
get => _implementation.unsafeValues;
}
- public object GenerateSentinel()
- {
- throw new NotImplementedException();
- }
-
public SetDictionary implementation => _implementation;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
diff --git a/Svelto.ECS/DataStructures/ITypeSafeDictionary.cs b/Svelto.ECS/DataStructures/ITypeSafeDictionary.cs
index d8a744b..f111a12 100644
--- a/Svelto.ECS/DataStructures/ITypeSafeDictionary.cs
+++ b/Svelto.ECS/DataStructures/ITypeSafeDictionary.cs
@@ -7,34 +7,27 @@ namespace Svelto.ECS.Internal
public interface ITypeSafeDictionary : ITypeSafeDictionary where TValue : IEntityComponent
{
void Add(uint egidEntityId, in TValue entityComponent);
- ref TValue GetValueByRef(uint key);
ref TValue this[uint idEntityId] { get; }
bool TryGetValue(uint entityId, out TValue item);
ref TValue GetOrCreate(uint idEntityId);
- TValue[] GetValuesArray(out uint count);
- TValue[] unsafeValues { get; }
- object GenerateSentinel();
+ IBuffer GetValues(out uint count);
+ ref TValue GetDirectValueByRef(uint key);
}
- public interface ITypeSafeDictionary
+ public interface ITypeSafeDictionary:IDisposable
{
- uint Count { get; }
+ uint count { get; }
ITypeSafeDictionary Create();
void AddEntitiesToEngines(FasterDictionary, FasterList> entityComponentEnginesDb,
ITypeSafeDictionary realDic, ExclusiveGroupStruct @group, in PlatformProfiler profiler);
-
void RemoveEntitiesFromEngines(FasterDictionary, FasterList> entityComponentEnginesDB,
in PlatformProfiler profiler, ExclusiveGroupStruct @group);
-
void AddEntitiesFromDictionary(ITypeSafeDictionary entitiesToSubmit, uint groupId);
-
void MoveEntityFromEngines(EGID fromEntityGid, EGID? toEntityID, ITypeSafeDictionary toGroup,
FasterDictionary, FasterList> engines, in PlatformProfiler profiler);
-
void AddEntityToDictionary(EGID fromEntityGid, EGID toEntityID, ITypeSafeDictionary toGroup);
-
void RemoveEntityFromDictionary(EGID fromEntityGid);
void SetCapacity(uint size);
diff --git a/Svelto.ECS/DataStructures/NativeBag.cs b/Svelto.ECS/DataStructures/NativeBag.cs
index 6db1021..e8a5ab9 100644
--- a/Svelto.ECS/DataStructures/NativeBag.cs
+++ b/Svelto.ECS/DataStructures/NativeBag.cs
@@ -12,12 +12,12 @@ namespace Svelto.ECS.DataStructures
/// is done.
/// You can reserve a position in the queue to update it later.
/// The datastructure is a struct and it's "copyable"
- /// I eventually decided to call it NativeBag and not NativeRingBuffer because it can also be used as
+ /// I eventually decided to call it NativeBag and not NativeBag because it can also be used as
/// a preallocated memory pool where any kind of T can be stored as long as T is unmanaged
///
public struct NativeBag : IDisposable
{
-#if UNITY_ECS
+#if UNITY_COLLECTIONS
[global::Unity.Collections.LowLevel.Unsafe.NativeDisableUnsafePtrRestriction]
#endif
unsafe UnsafeBlob* _queue;
@@ -73,31 +73,11 @@ namespace Svelto.ECS.DataStructures
unsafe
{
var sizeOf = MemoryUtilities.SizeOf();
- var listData = (UnsafeBlob*) MemoryUtilities.Alloc((uint) sizeOf, allocator);
+ var listData = (UnsafeBlob*) MemoryUtilities.Alloc((uint) sizeOf, allocator);
//clear to nullify the pointers
MemoryUtilities.MemClear((IntPtr) listData, (uint) sizeOf);
listData->allocator = allocator;
-#if DEBUG && !PROFILE_SVELTO
- listData->id = 0xDEADBEEF;
-#endif
- _queue = listData;
- }
- }
-
- public NativeBag(uint bufferID, Allocator allocator)
- {
- unsafe
- {
- var sizeOf = MemoryUtilities.SizeOf();
- var listData = (UnsafeBlob*) MemoryUtilities.Alloc((uint) sizeOf, allocator);
-
- //clear to nullify the pointers
- MemoryUtilities.MemClear((IntPtr) listData, (uint) sizeOf);
- listData->allocator = allocator;
-#if DEBUG && !PROFILE_SVELTO
- listData->id = bufferID;
-#endif
_queue = listData;
}
}
@@ -113,7 +93,7 @@ namespace Svelto.ECS.DataStructures
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref T ReserveEnqueue(out UnsafeArrayIndex index) where T : unmanaged
+ public ref T ReserveEnqueue(out UnsafeArrayIndex index) where T : struct
{
unsafe
{
@@ -123,14 +103,14 @@ namespace Svelto.ECS.DataStructures
#endif
var sizeOf = MemoryUtilities.SizeOf();
if (_queue->space - sizeOf < 0)
- _queue->Realloc((uint) ((_queue->capacity + sizeOf) * 1.5f));
+ _queue->Realloc((uint) ((_queue->capacity + sizeOf) * 2.0f));
return ref _queue->Reserve(out index);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Enqueue(in T item) where T : unmanaged
+ public void Enqueue(in T item) where T : struct
{
unsafe
{
@@ -140,7 +120,7 @@ namespace Svelto.ECS.DataStructures
#endif
var sizeOf = MemoryUtilities.SizeOf();
if (_queue->space - sizeOf < 0)
- _queue->Realloc((uint) ((_queue->capacity + sizeOf) * 1.5f));
+ _queue->Realloc((uint) ((_queue->capacity + MemoryUtilities.Align4((uint) sizeOf)) * 2.0f));
_queue->Write(item);
}
@@ -159,7 +139,7 @@ namespace Svelto.ECS.DataStructures
}
}
- public T Dequeue() where T : unmanaged
+ public T Dequeue() where T : struct
{
unsafe
{
@@ -167,7 +147,7 @@ namespace Svelto.ECS.DataStructures
}
}
- public ref T AccessReserved(UnsafeArrayIndex reserverIndex) where T : unmanaged
+ public ref T AccessReserved(UnsafeArrayIndex reserverIndex) where T : struct
{
unsafe
{
diff --git a/Svelto.ECS/DataStructures/NativeDynamicArray.cs b/Svelto.ECS/DataStructures/NativeDynamicArray.cs
index eefb7d9..83efdd2 100644
--- a/Svelto.ECS/DataStructures/NativeDynamicArray.cs
+++ b/Svelto.ECS/DataStructures/NativeDynamicArray.cs
@@ -7,8 +7,8 @@ namespace Svelto.ECS.DataStructures
{
public struct NativeDynamicArray : IDisposable
{
-#if UNITY_ECS
- [global::Unity.Collections.LowLevel.Unsafe.NativeDisableUnsafePtrRestriction]
+#if UNITY_COLLECTIONS
+ [global::Unity.Burst.NoAlias] [global::Unity.Collections.LowLevel.Unsafe.NativeDisableUnsafePtrRestriction]
#endif
unsafe UnsafeArray* _list;
#if DEBUG && !PROFILE_SVELTO
@@ -16,7 +16,7 @@ namespace Svelto.ECS.DataStructures
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public uint Count() where T:unmanaged
+ public int Count() where T : struct
{
unsafe
{
@@ -26,13 +26,13 @@ namespace Svelto.ECS.DataStructures
if (hashType != TypeHash.hash)
throw new Exception("NativeDynamicArray: not excepted type used");
-#endif
- return (uint) (_list->count / MemoryUtilities.SizeOf());
+#endif
+ return (_list->count / MemoryUtilities.SizeOf());
}
}
-
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public uint Capacity() where T:unmanaged
+ public int Capacity() where T : struct
{
unsafe
{
@@ -42,12 +42,12 @@ namespace Svelto.ECS.DataStructures
if (hashType != TypeHash.hash)
throw new Exception("NativeDynamicArray: not excepted type used");
-#endif
- return (uint) (_list->capacity / MemoryUtilities.SizeOf());
+#endif
+ return (_list->capacity / MemoryUtilities.SizeOf());
}
}
- public static NativeDynamicArray Alloc(Allocator allocator, uint newLength = 0) where T : unmanaged
+ public static NativeDynamicArray Alloc(Allocator allocator, uint newLength = 0) where T : struct
{
unsafe
{
@@ -55,17 +55,16 @@ namespace Svelto.ECS.DataStructures
#if DEBUG && !PROFILE_SVELTO
rtnStruc.hashType = TypeHash.hash;
#endif
- var sizeOf = MemoryUtilities.SizeOf();
+ var sizeOf = MemoryUtilities.SizeOf();
+
+ uint pointerSize = (uint) MemoryUtilities.SizeOf();
+ UnsafeArray* listData = (UnsafeArray*) MemoryUtilities.Alloc(pointerSize, allocator);
- uint pointerSize = (uint) MemoryUtilities.SizeOf();
- UnsafeArray* listData =
- (UnsafeArray*) MemoryUtilities.Alloc(pointerSize, allocator);
-
//clear to nullify the pointers
MemoryUtilities.MemClear((IntPtr) listData, pointerSize);
listData->allocator = allocator;
- listData->Realloc((uint) (newLength * sizeOf));
+ listData->Realloc((uint) (newLength * sizeOf));
rtnStruc._list = listData;
@@ -74,7 +73,7 @@ namespace Svelto.ECS.DataStructures
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref T Get(uint index) where T : unmanaged
+ public ref T Get(uint index) where T : struct
{
unsafe
{
@@ -91,7 +90,7 @@ namespace Svelto.ECS.DataStructures
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Set(uint index, in T value) where T : unmanaged
+ public void Set(uint index, in T value) where T : struct
{
unsafe
{
@@ -101,24 +100,24 @@ namespace Svelto.ECS.DataStructures
if (hashType != TypeHash.hash)
throw new Exception("NativeDynamicArray: not excepted type used");
if (index >= Capacity())
- throw new Exception($"NativeDynamicArray: out of bound access, index {index} count {Count()}");
-#endif
+ throw new Exception($"NativeDynamicArray: out of bound access, index {index} capacity {Capacity()}");
+#endif
_list->Set(index, value);
}
}
public unsafe void Dispose()
{
-#if DEBUG && !PROFILE_SVELTO
+#if DEBUG && !PROFILE_SVELTO
if (_list == null)
throw new Exception("NativeDynamicArray: null-access");
#endif
- _list->Dispose();
- _list = null;
+ _list->Dispose();
+ _list = null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Add(in T item) where T : unmanaged
+ public void Add(in T item) where T : struct
{
unsafe
{
@@ -129,16 +128,52 @@ namespace Svelto.ECS.DataStructures
throw new Exception("NativeDynamicArray: not excepted type used");
#endif
var structSize = (uint) MemoryUtilities.SizeOf();
-
- if (_list->space - (int)structSize < 0)
- _list->Realloc((uint) ((Count() + 1) * structSize * 1.5f));
-
+
+ if (_list->space - (int) structSize < 0)
+ _list->Realloc((uint) (((uint) ((Count() + 1) * 1.5f) * (float) structSize)));
+
_list->Add(item);
}
}
-
+
+ public void Grow(uint newCapacity) where T : struct
+ {
+ unsafe
+ {
+#if DEBUG && !PROFILE_SVELTO
+ if (_list == null)
+ throw new Exception("NativeDynamicArray: null-access");
+ if (hashType != TypeHash.hash)
+ throw new Exception("NativeDynamicArray: not excepted type used");
+ if (newCapacity <= Capacity())
+ throw new Exception("New capacity must be greater than current one");
+#endif
+ uint structSize = (uint) MemoryUtilities.SizeOf();
+
+ uint size = (uint) (newCapacity * structSize);
+ _list->Realloc((uint) size);
+ }
+ }
+
+ public void SetCount(uint count) where T : struct
+ {
+ unsafe
+ {
+#if DEBUG && !PROFILE_SVELTO
+ if (_list == null)
+ throw new Exception("NativeDynamicArray: null-access");
+ if (hashType != TypeHash.hash)
+ throw new Exception("NativeDynamicArray: not excepted type used");
+#endif
+ uint structSize = (uint) MemoryUtilities.SizeOf();
+ uint size = (uint) (count * structSize);
+
+ _list->SetCountTo((uint) size);
+ }
+ }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void AddWithoutGrow(in T item) where T : unmanaged
+ public void AddWithoutGrow(in T item) where T : struct
{
unsafe
{
@@ -157,6 +192,29 @@ namespace Svelto.ECS.DataStructures
}
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void UnorderedRemoveAt(uint index) where T : struct
+ {
+ unsafe
+ {
+#if DEBUG && !PROFILE_SVELTO
+ if (_list == null)
+ throw new Exception("NativeDynamicArray: null-access");
+ if (hashType != TypeHash.hash)
+ throw new Exception("NativeDynamicArray: not excepted type used");
+ if (Count() == 0)
+ throw new Exception("NativeDynamicArray: empty array invalid operation");
+#endif
+ var count = Count() - 1;
+ if (index < count)
+ {
+ Set(index, Get((uint) count));
+ }
+
+ _list->Pop();
+ }
+ }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()
{
@@ -182,6 +240,21 @@ namespace Svelto.ECS.DataStructures
return (T*) _list->ptr;
}
+ public IntPtr ToIntPTR() where T : struct
+ {
+ unsafe
+ {
+#if DEBUG && !PROFILE_SVELTO
+ if (_list == null)
+ throw new Exception("NativeDynamicArray: null-access");
+ if (hashType != TypeHash.hash)
+ throw new Exception("NativeDynamicArray: not excepted type used");
+
+#endif
+ return (IntPtr) _list->ptr;
+ }
+ }
+
public T[] ToManagedArray() where T : unmanaged
{
unsafe
@@ -193,17 +266,19 @@ namespace Svelto.ECS.DataStructures
throw new Exception("NativeDynamicArray: not excepted type used");
#endif
- var ret = new T[Count()];
+ var count = Count();
+ var ret = new T[count];
+ var lengthToCopyInBytes = count * MemoryUtilities.SizeOf();
- fixed (void * handle = ret)
+ fixed (void* handle = ret)
{
- Buffer.MemoryCopy(_list->ptr, handle, _list->count, _list->count);
+ Unsafe.CopyBlock(handle, _list->ptr, (uint) lengthToCopyInBytes);
}
return ret;
}
}
-
+
public T[] ToManagedArrayUntrimmed() where T : unmanaged
{
unsafe
@@ -213,17 +288,82 @@ namespace Svelto.ECS.DataStructures
throw new Exception("NativeDynamicArray: null-access");
if (hashType != TypeHash.hash)
throw new Exception("NativeDynamicArray: not excepted type used");
-
#endif
- var ret = new T[Capacity()];
+ var capacity = Capacity();
+ var lengthToCopyInBytes = capacity * MemoryUtilities.SizeOf();
+ var ret = new T[capacity];
- fixed (void * handle = ret)
+ fixed (void* handle = ret)
{
- Buffer.MemoryCopy(_list->ptr, handle, _list->capacity, _list->capacity);
+ Unsafe.CopyBlock(handle, _list->ptr, (uint) lengthToCopyInBytes);
}
return ret;
}
}
+
+ public void RemoveAt(uint index) where T : struct
+ {
+ unsafe
+ {
+#if DEBUG && !PROFILE_SVELTO
+ if (_list == null)
+ throw new Exception("NativeDynamicArray: null-access");
+ if (hashType != TypeHash.hash)
+ throw new Exception("NativeDynamicArray: not excepted type used");
+#endif
+
+ var sizeOf = MemoryUtilities.SizeOf();
+ //Unsafe.CopyBlock may not be memory overlapping safe (memcpy vs memmove)
+ Buffer.MemoryCopy(_list->ptr + (index + 1) * sizeOf, _list->ptr + index * sizeOf, _list->count
+ , (uint) ((Count() - (index + 1)) * sizeOf));
+ _list->Pop();
+ }
+ }
+
+ public void MemClear()
+ {
+ unsafe
+ {
+ MemoryUtilities.MemClear((IntPtr) _list->ptr, (uint) _list->capacity);
+ }
+ }
+ }
+
+ public ref struct NativeDynamicArrayCast where T : struct
+ {
+ NativeDynamicArray _array;
+
+ public NativeDynamicArrayCast(NativeDynamicArray array) : this() { _array = array; }
+
+ public int count
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _array.Count();
+ }
+
+ public ref T this[int index]
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => ref _array.Get((uint) index);
+ }
+
+ public ref T this[uint index]
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => ref _array.Get(index);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Add(in T id) { _array.Add(id); }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void UnorderedRemoveAt(uint index) { _array.UnorderedRemoveAt(index); }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void RemoveAt(uint index) { _array.RemoveAt(index); }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Clear() { _array.Clear(); }
}
-}
+}
\ No newline at end of file
diff --git a/Svelto.ECS/DataStructures/NativeDynamicArrayUnityExtension.cs b/Svelto.ECS/DataStructures/NativeDynamicArrayUnityExtension.cs
new file mode 100644
index 0000000..3688940
--- /dev/null
+++ b/Svelto.ECS/DataStructures/NativeDynamicArrayUnityExtension.cs
@@ -0,0 +1,23 @@
+#if UNITY_COLLECTIONS
+using Unity.Collections;
+using Unity.Collections.LowLevel.Unsafe;
+
+namespace Svelto.ECS.DataStructures
+{
+ public static class NativeDynamicArrayUnityExtension
+ {
+ public static NativeArray ToNativeArray(this NativeDynamicArray array) where T : struct
+ {
+ unsafe
+ {
+ var nativeArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(
+ (void*) array.ToIntPTR(), (int) array.Count(), Allocator.None);
+#if ENABLE_UNITY_COLLECTIONS_CHECKS
+ NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref nativeArray, AtomicSafetyHandle.Create());
+#endif
+ return nativeArray;
+ }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Svelto.ECS/DataStructures/SharedNativeInt.cs b/Svelto.ECS/DataStructures/SharedNativeInt.cs
index 1bcecdb..b5269e6 100644
--- a/Svelto.ECS/DataStructures/SharedNativeInt.cs
+++ b/Svelto.ECS/DataStructures/SharedNativeInt.cs
@@ -6,7 +6,7 @@ namespace Svelto.ECS.DataStructures
{
public struct SharedNativeInt: IDisposable
{
-#if UNITY_ECS
+#if UNITY_COLLECTIONS
[global::Unity.Collections.LowLevel.Unsafe.NativeDisableUnsafePtrRestriction]
#endif
unsafe int* data;
diff --git a/Svelto.ECS/DataStructures/SharedNativeUInt.cs b/Svelto.ECS/DataStructures/SharedNativeUInt.cs
deleted file mode 100644
index a6474b3..0000000
--- a/Svelto.ECS/DataStructures/SharedNativeUInt.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Threading;
-
-namespace Svelto.ECS.DataStructures
-{
- public struct SharedNativeUInt: IDisposable
- {
-#if UNITY_ECS
- [global::Unity.Collections.LowLevel.Unsafe.NativeDisableUnsafePtrRestriction]
-#endif
- unsafe uint* data;
-
- public SharedNativeUInt(uint t)
- {
- unsafe
- {
- data = (uint*) Marshal.AllocHGlobal(sizeof(uint));
- *data = t;
- }
- }
-
- public static implicit operator uint(SharedNativeUInt t)
- {
- unsafe
- {
-#if DEBUG && !PROFILE_SVELTO
- if (t.data == null)
- throw new Exception("using disposed SharedUInt");
-#endif
-
- return *t.data;
- }
- }
-
- public void Dispose()
- {
- unsafe
- {
- if (data != null)
- {
- Marshal.FreeHGlobal((IntPtr) data);
- data = null;
- }
- }
- }
-
- public void Decrement()
- {
- unsafe
- {
- int result = Interlocked.Decrement(ref Unsafe.As(ref *data));
-
-#if DEBUG && !PROFILE_SVELTO
- if (result < 0)
- throw new Exception("can't have negative numbers");
-#endif
- }
- }
-
- public void Increment()
- {
- unsafe
- {
- Interlocked.Increment(ref Unsafe.As(ref *data));
- }
- }
- }
-}
\ No newline at end of file
diff --git a/Svelto.ECS/DataStructures/TypeSafeDictionary.cs b/Svelto.ECS/DataStructures/TypeSafeDictionary.cs
index 7ce5ef9..2bc30e0 100644
--- a/Svelto.ECS/DataStructures/TypeSafeDictionary.cs
+++ b/Svelto.ECS/DataStructures/TypeSafeDictionary.cs
@@ -2,202 +2,468 @@
using System.Runtime.CompilerServices;
using Svelto.Common;
using Svelto.DataStructures;
+using Svelto.ECS.Hybrid;
namespace Svelto.ECS.Internal
{
sealed class TypeSafeDictionary : ITypeSafeDictionary where TValue : struct, IEntityComponent
{
- static readonly Type _type = typeof(TValue);
- static readonly string _typeName = _type.Name;
- static readonly bool _hasEgid = typeof(INeedEGID).IsAssignableFrom(_type);
+ static readonly Type _type = typeof(TValue);
+ static readonly string _typeName = _type.Name;
+ static readonly bool _hasEgid = typeof(INeedEGID).IsAssignableFrom(_type);
+
+ internal static readonly bool _isUmanaged =
+ _type.IsUnmanaged() && (typeof(IEntityViewComponent).IsAssignableFrom(_type) == false);
+
+ internal SveltoDictionary>, ManagedStrategy> implMgd;
+ internal SveltoDictionary>, NativeStrategy> implUnmgd;
public TypeSafeDictionary(uint size)
{
- _implementation = new FasterDictionary(size);
+ if (_isUmanaged)
+ implUnmgd = new SveltoDictionary>, NativeStrategy>(size);
+ else
+ {
+ implMgd = new SveltoDictionary>, ManagedStrategy>(size);
+ }
}
- public TypeSafeDictionary()
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Add(uint egidEntityId, in TValue entityComponent)
{
- _implementation = new FasterDictionary(1);
+ if (_isUmanaged)
+ implUnmgd.Add(egidEntityId, entityComponent);
+ else
+ implMgd.Add(egidEntityId, entityComponent);
}
///
- /// Add entities from external typeSafeDictionary
+ /// Add entities from external typeSafeDictionary
///
///
///
///
- public void AddEntitiesFromDictionary(ITypeSafeDictionary entitiesToSubmit, uint groupId)
+ public void AddEntitiesFromDictionary(ITypeSafeDictionary entitiesToSubmit, uint groupId)
{
- var typeSafeDictionary = entitiesToSubmit as TypeSafeDictionary;
+ if (_isUmanaged)
+ {
+ var typeSafeDictionary = (entitiesToSubmit as TypeSafeDictionary).implUnmgd;
- foreach (var tuple in typeSafeDictionary)
+ foreach (var tuple in typeSafeDictionary)
+ try
+ {
+ if (_hasEgid)
+ SetEGIDWithoutBoxing.SetIDWithoutBoxing(
+ ref tuple.Value, new EGID(tuple.Key, groupId));
+
+ implUnmgd.Add(tuple.Key, tuple.Value);
+ }
+ catch (Exception e)
+ {
+ Console.LogException(
+ e, "trying to add an EntityComponent with the same ID more than once Entity: ".FastConcat(typeof(TValue).ToString()).FastConcat(", group ").FastConcat(groupId).FastConcat(", id ").FastConcat(tuple.Key));
+
+ throw;
+ }
+ }
+ else
{
- try
- {
- if (_hasEgid)
- SetEGIDWithoutBoxing.SetIDWithoutBoxing(ref tuple.Value, new EGID(tuple.Key, groupId));
+ var typeSafeDictionary = (entitiesToSubmit as TypeSafeDictionary).implMgd;
- _implementation.Add(tuple.Key, tuple.Value);
- }
- catch (Exception e)
- {
- Svelto.Console.LogException(e,
- "trying to add an EntityComponent with the same ID more than once Entity: "
- .FastConcat(typeof(TValue).ToString()).FastConcat(", group ").FastConcat(groupId)
- .FastConcat(", id ").FastConcat(tuple.Key));
+ foreach (var tuple in typeSafeDictionary)
+ try
+ {
+ if (_hasEgid)
+ SetEGIDWithoutBoxing.SetIDWithoutBoxing(
+ ref tuple.Value, new EGID(tuple.Key, groupId));
- throw;
- }
+ implMgd.Add(tuple.Key, tuple.Value);
+ }
+ catch (Exception e)
+ {
+ Console.LogException(
+ e, "trying to add an EntityComponent with the same ID more than once Entity: ".FastConcat(typeof(TValue).ToString()).FastConcat(", group ").FastConcat(groupId).FastConcat(", id ").FastConcat(tuple.Key));
+
+ throw;
+ }
}
}
-
+
+ public void AddEntitiesToEngines
+ (FasterDictionary, FasterList> entityComponentEnginesDB
+ , ITypeSafeDictionary realDic, ExclusiveGroupStruct group, in PlatformProfiler profiler)
+ {
+ if (_isUmanaged)
+ {
+ var typeSafeDictionary = realDic as ITypeSafeDictionary;
+
+ //this can be optimized, should pass all the entities and not restart the process for each one
+ foreach (var value in implUnmgd)
+ AddEntityComponentToEngines(entityComponentEnginesDB, ref typeSafeDictionary[value.Key]
+ , null, in profiler, new EGID(value.Key, group));
+ }
+ else
+ {
+ var typeSafeDictionary = realDic as ITypeSafeDictionary;
+
+ //this can be optimized, should pass all the entities and not restart the process for each one
+ foreach (var value in implMgd)
+ AddEntityComponentToEngines(entityComponentEnginesDB, ref typeSafeDictionary[value.Key]
+ , null, in profiler, new EGID(value.Key, group));
+ }
+ }
+
public void AddEntityToDictionary(EGID fromEntityGid, EGID toEntityID, ITypeSafeDictionary toGroup)
{
- var valueIndex = _implementation.GetIndex(fromEntityGid.entityID);
+ if (_isUmanaged)
+ {
+ var valueIndex = implUnmgd.GetIndex(fromEntityGid.entityID);
+
+ DBC.ECS.Check.Require(toGroup != null
+ , "Invalid To Group"); //todo check this, if it's right merge GetIndex
+ {
+ var toGroupCasted = toGroup as ITypeSafeDictionary;
+ ref var entity = ref implUnmgd.GetDirectValueByRef(valueIndex);
+
+ if (_hasEgid)
+ SetEGIDWithoutBoxing.SetIDWithoutBoxing(ref entity, toEntityID);
- if (toGroup != null)
+ toGroupCasted.Add(fromEntityGid.entityID, entity);
+ }
+ }
+ else
{
- var toGroupCasted = toGroup as ITypeSafeDictionary;
- ref var entity = ref _implementation.unsafeValues[(int) valueIndex];
+ var valueIndex = implMgd.GetIndex(fromEntityGid.entityID);
- if (_hasEgid) SetEGIDWithoutBoxing.SetIDWithoutBoxing(ref entity, toEntityID);
+ DBC.ECS.Check.Require(toGroup != null
+ , "Invalid To Group"); //todo check this, if it's right merge GetIndex
+ {
+ var toGroupCasted = toGroup as ITypeSafeDictionary;
+ ref var entity = ref implMgd.GetDirectValueByRef(valueIndex);
+
+ if (_hasEgid)
+ SetEGIDWithoutBoxing.SetIDWithoutBoxing(ref entity, toEntityID);
- toGroupCasted.Add(fromEntityGid.entityID, entity);
+ toGroupCasted.Add(fromEntityGid.entityID, entity);
+ }
}
}
- public void AddEntitiesToEngines(FasterDictionary, FasterList> entityComponentEnginesDB,
- ITypeSafeDictionary realDic,
- ExclusiveGroupStruct @group,
- in PlatformProfiler profiler)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Clear()
{
- var typeSafeDictionary = realDic as ITypeSafeDictionary;
+ if (_isUmanaged)
+ {
+ implUnmgd.Clear();
+ }
+ else
+ {
+ implMgd.Clear();
+ }
+ }
- //this can be optimized, should pass all the entities and not restart the process for each one
- foreach (var value in _implementation)
- AddEntityComponentToEngines(entityComponentEnginesDB, ref typeSafeDictionary.GetValueByRef(value.Key), null,
- in profiler, new EGID(value.Key, group));
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void FastClear()
+ {
+ if (_isUmanaged)
+ {
+ implUnmgd.FastClear();
+ }
+ else
+ {
+ implMgd.FastClear();
+ }
}
- public void RemoveEntitiesFromEngines(
- FasterDictionary, FasterList> entityComponentEnginesDB, in PlatformProfiler profiler,
- ExclusiveGroupStruct @group)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool ContainsKey(uint egidEntityId)
{
- foreach (var value in _implementation)
- RemoveEntityComponentFromEngines(entityComponentEnginesDB, ref _implementation.GetValueByRef(value.Key), null,
- in profiler, new EGID(value.Key, group));
+ if (_isUmanaged)
+ {
+ return implUnmgd.ContainsKey(egidEntityId);
+ }
+ else
+ {
+ return implMgd.ContainsKey(egidEntityId);
+ }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void FastClear() { _implementation.FastClear(); }
+ public ITypeSafeDictionary Create()
+ {
+ return TypeSafeDictionaryFactory.Create(1);
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool Has(uint key) { return _implementation.ContainsKey(key); }
+ public uint GetIndex(uint valueEntityId)
+ {
+ if (_isUmanaged)
+ {
+ return this.implUnmgd.GetIndex(valueEntityId);
+ }
+ else
+ {
+ return this.implMgd.GetIndex(valueEntityId);
+ }
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void RemoveEntityFromDictionary(EGID fromEntityGid)
+ public ref TValue GetOrCreate(uint idEntityId)
{
- _implementation.Remove(fromEntityGid.entityID);
+ if (_isUmanaged)
+ {
+ return ref this.implUnmgd.GetOrCreate(idEntityId);
+ }
+ else
+ {
+ return ref this.implMgd.GetOrCreate(idEntityId);
+ }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void SetCapacity(uint size) { _implementation.SetCapacity(size); }
+ public IBuffer GetValues(out uint count)
+ {
+ if (_isUmanaged)
+ {
+ return this.implUnmgd.GetValues(out count);
+ }
+ else
+ {
+ return this.implMgd.GetValues(out count);
+ }
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Trim() { _implementation.Trim(); }
+ public ref TValue GetDirectValueByRef(uint key)
+ {
+ if (_isUmanaged)
+ {
+ return ref this.implUnmgd.GetDirectValueByRef(key);
+ }
+ else
+ {
+ return ref this.implMgd.GetDirectValueByRef(key);
+ }
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Clear() { _implementation.Clear(); }
+ public bool Has(uint key)
+ {
+ if (_isUmanaged)
+ {
+ return this.implUnmgd.ContainsKey(key);
+ }
+ else
+ {
+ return this.implMgd.ContainsKey(key);
+ }
+ }
- public void MoveEntityFromEngines(EGID fromEntityGid,
- EGID? toEntityID, ITypeSafeDictionary toGroup,
- FasterDictionary, FasterList> engines,
- in PlatformProfiler profiler)
+ public void MoveEntityFromEngines
+ (EGID fromEntityGid, EGID? toEntityID, ITypeSafeDictionary toGroup
+ , FasterDictionary, FasterList> engines, in PlatformProfiler profiler)
{
- var valueIndex = _implementation.GetIndex(fromEntityGid.entityID);
+ if (_isUmanaged)
+ {
+ var valueIndex = this.implUnmgd.GetIndex(fromEntityGid.entityID);
+
+ ref var entity = ref this.implUnmgd.GetDirectValueByRef(valueIndex);
+
+ if (toGroup != null)
+ {
+ RemoveEntityComponentFromEngines(engines, ref entity, fromEntityGid.groupID, in profiler
+ , fromEntityGid);
- ref var entity = ref _implementation.unsafeValues[(int) valueIndex];
+ var toGroupCasted = toGroup as ITypeSafeDictionary;
+ var previousGroup = fromEntityGid.groupID;
- if (toGroup != null)
+ if (_hasEgid)
+ SetEGIDWithoutBoxing.SetIDWithoutBoxing(ref entity, toEntityID.Value);
+
+ var index = toGroupCasted.GetIndex(toEntityID.Value.entityID);
+
+ AddEntityComponentToEngines(engines, ref toGroupCasted.GetDirectValueByRef(index), previousGroup
+ , in profiler, toEntityID.Value);
+ }
+ else
+ {
+ RemoveEntityComponentFromEngines(engines, ref entity, null, in profiler, fromEntityGid);
+ }
+ }
+ else
{
- RemoveEntityComponentFromEngines(engines, ref entity, fromEntityGid.groupID, in profiler, fromEntityGid);
+ var valueIndex = this.implMgd.GetIndex(fromEntityGid.entityID);
- var toGroupCasted = toGroup as ITypeSafeDictionary;
- var previousGroup = fromEntityGid.groupID;
+ ref var entity = ref this.implMgd.GetDirectValueByRef(valueIndex);
- if (_hasEgid) SetEGIDWithoutBoxing.SetIDWithoutBoxing(ref entity, toEntityID.Value);
+ if (toGroup != null)
+ {
+ RemoveEntityComponentFromEngines(engines, ref entity, fromEntityGid.groupID, in profiler
+ , fromEntityGid);
+
+ var toGroupCasted = toGroup as ITypeSafeDictionary;
+ var previousGroup = fromEntityGid.groupID;
+
+ if (_hasEgid)
+ SetEGIDWithoutBoxing.SetIDWithoutBoxing(ref entity, toEntityID.Value);
- var index = toGroupCasted.GetIndex(toEntityID.Value.entityID);
+ var index = toGroupCasted.GetIndex(toEntityID.Value.entityID);
- AddEntityComponentToEngines(engines, ref toGroupCasted.unsafeValues[(int) index], previousGroup, in profiler,
- toEntityID.Value);
+ AddEntityComponentToEngines(engines, ref toGroupCasted.GetDirectValueByRef(index), previousGroup
+ , in profiler, toEntityID.Value);
+ }
+ else
+ {
+ RemoveEntityComponentFromEngines(engines, ref entity, null, in profiler, fromEntityGid);
+ }
+ }
+ }
+
+ public void RemoveEntitiesFromEngines(FasterDictionary, FasterList> engines
+ , in PlatformProfiler profiler, ExclusiveGroupStruct group)
+ {
+ if (_isUmanaged)
+ {
+ foreach (var value in implUnmgd)
+ RemoveEntityComponentFromEngines(engines, ref implUnmgd.GetValueByRef(value.Key), null
+ , in profiler, new EGID(value.Key, group));
}
else
- RemoveEntityComponentFromEngines(engines, ref entity, null, in profiler, fromEntityGid);
+ {
+ foreach (var value in implMgd)
+ RemoveEntityComponentFromEngines(engines, ref implMgd.GetValueByRef(value.Key), null
+ , in profiler, new EGID(value.Key, group));
+ }
}
- public uint Count
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void RemoveEntityFromDictionary(EGID fromEntityGid)
{
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => _implementation.count;
+ if (_isUmanaged)
+ {
+ this.implUnmgd.Remove(fromEntityGid.entityID);
+ }
+ else
+ {
+ this.implMgd.Remove(fromEntityGid.entityID);
+ }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ITypeSafeDictionary Create() { return new TypeSafeDictionary(); }
+ public void SetCapacity(uint size)
+ {
+ if (_isUmanaged)
+ {
+ this.implUnmgd.SetCapacity(size);
+ }
+ else
+ {
+ this.implMgd.SetCapacity(size);
+ }
+ }
- void AddEntityComponentToEngines(FasterDictionary, FasterList> entityComponentEnginesDB,
- ref TValue entity,
- ExclusiveGroupStruct? previousGroup,
- in PlatformProfiler profiler,
- EGID egid)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Trim()
{
- //get all the engines linked to TValue
- if (!entityComponentEnginesDB.TryGetValue(new RefWrapper(_type), out var entityComponentsEngines)) return;
+ if (_isUmanaged)
+ {
+ this.implUnmgd.Trim();
+ }
+ else
+ {
+ this.implMgd.Trim();
+ }
+ }
- if (previousGroup == null)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool TryFindIndex(uint entityId, out uint index)
+ {
+ if (_isUmanaged)
{
- for (var i = 0; i < entityComponentsEngines.count; i++)
- try
- {
- using (profiler.Sample(entityComponentsEngines[i], _typeName))
- {
- (entityComponentsEngines[i] as IReactOnAddAndRemove).Add(ref entity, egid);
- }
- }
- catch (Exception e)
- {
- throw new
- ECSException("Code crashed inside Add callback ".FastConcat(typeof(TValue).ToString()), e);
- }
+ return implUnmgd.TryFindIndex(entityId, out index);
+ }
+ else
+ {
+ return implMgd.TryFindIndex(entityId, out index);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool TryGetValue(uint entityId, out TValue item)
+ {
+ if (_isUmanaged)
+ {
+ return this.implUnmgd.TryGetValue(entityId, out item);
}
else
{
+ return this.implMgd.TryGetValue(entityId, out item);
+ }
+ }
+
+ public uint count
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ if (_isUmanaged)
+ {
+ return this.implUnmgd.count;
+ }
+ else
+ {
+ return this.implMgd.count;
+ }
+ }
+ }
+
+ public ref TValue this[uint idEntityId]
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ if (_isUmanaged)
+ {
+ return ref this.implUnmgd.GetValueByRef(idEntityId);
+ }
+ else
+ {
+ return ref this.implMgd.GetValueByRef(idEntityId);
+ }
+ }
+ }
+
+ static void RemoveEntityComponentFromEngines
+ (FasterDictionary, FasterList> engines, ref TValue entity, uint? previousGroup
+ , in PlatformProfiler profiler, EGID egid)
+ {
+ if (!engines.TryGetValue(new RefWrapper(_type), out var entityComponentsEngines))
+ return;
+
+ if (previousGroup == null)
for (var i = 0; i < entityComponentsEngines.count; i++)
try
{
using (profiler.Sample(entityComponentsEngines[i], _typeName))
{
- (entityComponentsEngines[i] as IReactOnSwap).MovedTo(ref entity, previousGroup.Value,
- egid);
+ (entityComponentsEngines[i] as IReactOnAddAndRemove).Remove(ref entity, egid);
}
}
- catch (Exception e)
+ catch
{
- throw new
- ECSException("Code crashed inside MovedTo callback ".FastConcat(typeof(TValue).ToString()),
- e);
+ Svelto.Console.LogError("Code crashed inside Remove callback ".FastConcat(typeof(TValue).ToString()));
+
+ throw;
}
- }
}
- static void RemoveEntityComponentFromEngines(FasterDictionary, FasterList> @group,
- ref TValue entity,
- uint? previousGroup,
- in PlatformProfiler profiler,
- EGID egid)
+ void AddEntityComponentToEngines
+ (FasterDictionary, FasterList> engines, ref TValue entity
+ , ExclusiveGroupStruct? previousGroup, in PlatformProfiler profiler, EGID egid)
{
- if (!@group.TryGetValue(new RefWrapper(_type), out var entityComponentsEngines)) return;
+ //get all the engines linked to TValue
+ if (!engines.TryGetValue(new RefWrapper(_type), out var entityComponentsEngines))
+ return;
if (previousGroup == null)
{
@@ -205,86 +471,45 @@ namespace Svelto.ECS.Internal
try
{
using (profiler.Sample(entityComponentsEngines[i], _typeName))
- (entityComponentsEngines[i] as IReactOnAddAndRemove).Remove(ref entity, egid);
+ {
+ (entityComponentsEngines[i] as IReactOnAddAndRemove).Add(ref entity, egid);
+ }
}
- catch (Exception e)
+ catch
{
- throw new
- ECSException("Code crashed inside Remove callback ".FastConcat(typeof(TValue).ToString()),
- e);
+ Svelto.Console.LogError("Code crashed inside Add callback ".FastConcat(typeof(TValue).ToString()));
+
+ throw;
}
}
-#if SEEMS_UNNECESSARY
else
{
- for (var i = 0; i < entityComponentsEngines.Count; i++)
+ for (var i = 0; i < entityComponentsEngines.count; i++)
try
{
using (profiler.Sample(entityComponentsEngines[i], _typeName))
- (entityComponentsEngines[i] as IReactOnSwap).MovedFrom(ref entity, egid);
+ {
+ (entityComponentsEngines[i] as IReactOnSwap).MovedTo(
+ ref entity, previousGroup.Value, egid);
+ }
}
- catch (Exception e)
+ catch (Exception)
{
- throw new ECSException(
- "Code crashed inside Remove callback ".FastConcat(typeof(TValue).ToString()), e);
+ Svelto.Console.LogError("Code crashed inside MoveTo callback ".FastConcat(typeof(TValue).ToString()));
+
+ throw;
}
}
-#endif
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public TValue[] GetValuesArray(out uint count)
- {
- var managedBuffer = _implementation.GetValuesArray(out count);
- return managedBuffer;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool ContainsKey(uint egidEntityId) { return _implementation.ContainsKey(egidEntityId); }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Add(uint egidEntityId, in TValue entityComponent) { _implementation.Add(egidEntityId, entityComponent); }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public FasterDictionary.FasterDictionaryKeyValueEnumerator GetEnumerator()
- {
- return _implementation.GetEnumerator();
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref TValue GetValueByRef(uint key) { return ref _implementation.GetValueByRef(key); }
-
- public ref TValue this[uint idEntityId]
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => ref _implementation.GetValueByRef(idEntityId);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public uint GetIndex(uint valueEntityId) { return _implementation.GetIndex(valueEntityId); }
-
- public TValue[] unsafeValues
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => _implementation.unsafeValues;
}
- public object GenerateSentinel()
+ public void Dispose()
{
- return default;
+ if (_isUmanaged)
+ implUnmgd.Dispose();
+ else
+ implMgd.Dispose();
+
+ GC.SuppressFinalize(this);
}
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryGetValue(uint entityId, out TValue item) { return _implementation.TryGetValue(entityId, out item); }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref TValue GetOrCreate(uint idEntityId) { return ref _implementation.GetOrCreate(idEntityId); }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryFindIndex(uint entityId, out uint index) { return _implementation.TryFindIndex(entityId, out index); }
-
- internal FasterDictionary implementation => _implementation;
-
- readonly FasterDictionary _implementation;
}
}
\ No newline at end of file
diff --git a/Svelto.ECS/DataStructures/TypeSafeDictionaryUtilities.cs b/Svelto.ECS/DataStructures/TypeSafeDictionaryUtilities.cs
index 4d21f9f..57af0d1 100644
--- a/Svelto.ECS/DataStructures/TypeSafeDictionaryUtilities.cs
+++ b/Svelto.ECS/DataStructures/TypeSafeDictionaryUtilities.cs
@@ -9,13 +9,5 @@ namespace Svelto.ECS.Internal
return mapper;
}
-
- internal static NativeEGIDMapper ToNativeEGIDMapper(this TypeSafeDictionary dic,
- ExclusiveGroupStruct groupStructId) where T : unmanaged, IEntityComponent
- {
- var mapper = new NativeEGIDMapper(groupStructId, dic.implementation.ToNative());
-
- return mapper;
- }
}
}
\ No newline at end of file
diff --git a/Svelto.ECS/DataStructures/UnsafeArray.cs b/Svelto.ECS/DataStructures/UnsafeArray.cs
index 4ba484f..a995dc6 100644
--- a/Svelto.ECS/DataStructures/UnsafeArray.cs
+++ b/Svelto.ECS/DataStructures/UnsafeArray.cs
@@ -9,12 +9,13 @@ namespace Svelto.ECS.DataStructures
internal unsafe byte* ptr => _ptr;
//expressed in bytes
- internal uint capacity => _capacity;
+ internal int capacity => (int) _capacity;
//expressed in bytes
- internal uint count => _writeIndex;
+ internal int count => (int) _writeIndex;
+
//expressed in bytes
- internal uint space => capacity - count;
+ internal int space => capacity - count;
///
///
@@ -26,37 +27,36 @@ namespace Svelto.ECS.DataStructures
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref T Get(uint index) where T : unmanaged
+ public ref T Get(uint index) where T : struct
{
unsafe
{
- T* buffer = (T*) ptr;
- return ref buffer[index];
+ return ref Unsafe.AsRef(Unsafe.Add(ptr, (int) index));
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Set(uint index, in T value) where T : unmanaged
+ public void Set(uint index, in T value) where T : struct
{
unsafe
{
- int sizeOf = MemoryUtilities.SizeOf();
+ uint sizeOf = (uint) MemoryUtilities.SizeOf();
uint writeIndex = (uint) (index * sizeOf);
#if DEBUG && !PROFILE_SVELTO
if (_capacity < writeIndex + sizeOf)
throw new Exception("no writing authorized");
-#endif
- T* buffer = (T*) ptr;
- buffer[index] = value;
+#endif
+ Unsafe.AsRef(Unsafe.Add(_ptr, (int) index)) = value;
if (_writeIndex < writeIndex + sizeOf)
_writeIndex = (uint) (writeIndex + sizeOf);
}
}
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Add(in T value) where T : unmanaged
+ public void Add(in T value) where T : struct
{
unsafe
{
@@ -73,7 +73,15 @@ namespace Svelto.ECS.DataStructures
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal void Realloc(uint newCapacity) where T : unmanaged
+ public void Pop() where T : struct
+ {
+ var structSize = MemoryUtilities.SizeOf();
+
+ _writeIndex -= (uint)structSize;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void Realloc(uint newCapacity)
{
unsafe
{
@@ -84,9 +92,9 @@ namespace Svelto.ECS.DataStructures
#endif
if (newCapacity >= 0)
{
- newPointer = (byte*) MemoryUtilities.Alloc(newCapacity, allocator);
+ newPointer = (byte*) MemoryUtilities.Alloc(newCapacity, allocator);
if (count > 0)
- Unsafe.CopyBlock(newPointer, ptr, count);
+ Unsafe.CopyBlock(newPointer, ptr, (uint) count);
}
if (ptr != null)
@@ -117,10 +125,17 @@ namespace Svelto.ECS.DataStructures
_writeIndex = 0;
}
-#if UNITY_ECS
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void SetCountTo(uint count)
+ {
+ _writeIndex = count;
+ }
+
+#if UNITY_COLLECTIONS
[global::Unity.Collections.LowLevel.Unsafe.NativeDisableUnsafePtrRestriction]
#endif
unsafe byte* _ptr;
+
uint _writeIndex;
uint _capacity;
}
diff --git a/Svelto.ECS/DataStructures/UnsafeBlob.cs b/Svelto.ECS/DataStructures/UnsafeBlob.cs
index f5e47c3..a658f02 100644
--- a/Svelto.ECS/DataStructures/UnsafeBlob.cs
+++ b/Svelto.ECS/DataStructures/UnsafeBlob.cs
@@ -1,10 +1,10 @@
using System;
using System.Runtime.CompilerServices;
using Svelto.Common;
-using Unity.Collections.LowLevel.Unsafe;
namespace Svelto.ECS.DataStructures
{
+ //ToDO to complete in future version of svelto, maybe removed
public struct UnsafeArrayIndex
{
internal uint index;
@@ -12,116 +12,119 @@ namespace Svelto.ECS.DataStructures
}
///
- /// Note: this must work inside burst, so it must follow burst restrictions
- /// Note: All the svelto native structures
+ /// Note: this must work inside burst, so it must follow burst restrictions
+ /// Note: All the svelto native structures
///
struct UnsafeBlob : IDisposable
{
- internal unsafe byte* ptr => _ptr;
+ internal unsafe byte* ptr { get; set; }
+
//expressed in bytes
internal uint capacity { get; private set; }
+
//expressed in bytes
internal uint size => _writeIndex - _readIndex;
+
//expressed in bytes
internal uint space => capacity - size;
///
///
internal Allocator allocator;
-#if DEBUG && !PROFILE_SVELTO
- internal uint id;
-#endif
-
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal void Write(in T item) where T : unmanaged
+ internal void Write(in T item) where T : struct
{
unsafe
{
var structSize = (uint) MemoryUtilities.SizeOf();
-
+
//the idea is, considering the wrap, a read pointer must always be behind a writer pointer
-#if DEBUG && !PROFILE_SVELTO
- if (space - (int)structSize < 0)
+#if DEBUG && !PROFILE_SVELTO
+ if (space - (int) structSize < 0)
throw new Exception("no writing authorized");
#endif
var writeHead = _writeIndex % capacity;
if (writeHead + structSize <= capacity)
{
- Unsafe.Write(_ptr + writeHead, item);
+ Unsafe.Write(ptr + writeHead, item);
}
else
- //copy with wrap, will start to copy and wrap for the reminder
+ //copy with wrap, will start to copy and wrap for the reminder
{
var byteCountToEnd = capacity - writeHead;
- fixed (T* readFrom = &item)
- {
- //read and copy the first portion of Item until the end of the stream
- Unsafe.CopyBlock(_ptr + writeHead, readFrom, byteCountToEnd);
+ var localCopyToAvoidGcIssues = item;
+ //read and copy the first portion of Item until the end of the stream
+ Unsafe.CopyBlock(ptr + writeHead, Unsafe.AsPointer(ref localCopyToAvoidGcIssues), byteCountToEnd);
- var restCount = structSize - byteCountToEnd;
+ var restCount = structSize - byteCountToEnd;
- //read and copy the remainder
- var @from = (byte*) readFrom;
- Unsafe.CopyBlock(_ptr, @from + byteCountToEnd, restCount);
- }
+ //read and copy the remainder
+ Unsafe.CopyBlock(ptr, (byte*) Unsafe.AsPointer(ref localCopyToAvoidGcIssues) + byteCountToEnd
+ , restCount);
}
- uint paddedStructSize = Align4(structSize);
-
+ //this is may seems a waste if you are going to use an unsafeBlob just for bytes, but it's necessary for mixed types.
+ //it's still possible to use WriteUnaligned though
+ var paddedStructSize = MemoryUtilities.Align4(structSize);
+
_writeIndex += paddedStructSize;
}
}
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal void WriteUnaligned(in T item) where T : unmanaged
- {
- unsafe
- {
- uint structSize = (uint) MemoryUtilities.SizeOf();
-
- //the idea is, considering the wrap, a read pointer must always be behind a writer pointer
-#if DEBUG && !PROFILE_SVELTO
- if (space - (int)structSize < 0)
- throw new Exception("no writing authorized");
-#endif
- var pointer = _writeIndex % capacity;
- if (pointer + structSize <= capacity)
- Unsafe.Write(_ptr + pointer, item);
- else
- {
- var byteCount = capacity - pointer;
- fixed (T* readFrom = &item)
- {
- Unsafe.CopyBlockUnaligned(_ptr + pointer, readFrom, byteCount);
-
- var restCount = structSize - byteCount;
- var @from = (byte*) readFrom;
- Unsafe.CopyBlockUnaligned(_ptr, @from + byteCount, restCount);
- }
- }
+// [MethodImpl(MethodImplOptions.AggressiveInlining)]
+// //ToDo: remove this and create an UnsafeBlobUnaligned, used on NativeRingBuffer where T cannot change
+// internal void WriteUnaligned(in T item) where T : struct
+// {
+// unsafe
+// {
+// var structSize = (uint) MemoryUtilities.SizeOf();
+//
+// //the idea is, considering the wrap, a read pointer must always be behind a writer pointer
+// #if DEBUG && !PROFILE_SVELTO
+// if (space - (int) structSize < 0)
+// throw new Exception("no writing authorized");
+// #endif
+// var pointer = _writeIndex % capacity;
+//
+// if (pointer + structSize <= capacity)
+// {
+// Unsafe.Write(ptr + pointer, item);
+// }
+// else
+// {
+// var byteCount = capacity - pointer;
+//
+// var localCopyToAvoidGCIssues = item;
+//
+// Unsafe.CopyBlockUnaligned(ptr + pointer, Unsafe.AsPointer(ref localCopyToAvoidGCIssues), byteCount);
+//
+// var restCount = structSize - byteCount;
+// Unsafe.CopyBlockUnaligned(ptr, (byte*) Unsafe.AsPointer(ref localCopyToAvoidGCIssues) + byteCount
+// , restCount);
+// }
+//
+// _writeIndex += structSize;
+// }
+// }
- _writeIndex += structSize;
- }
- }
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal T Read() where T : unmanaged
+ internal T Read() where T : struct
{
unsafe
{
var structSize = (uint) MemoryUtilities.SizeOf();
-
-#if DEBUG && !PROFILE_SVELTO
+
+#if DEBUG && !PROFILE_SVELTO
if (size < structSize) //are there enough bytes to read?
throw new Exception("dequeuing empty queue or unexpected type dequeued");
if (_readIndex > _writeIndex)
throw new Exception("unexpected read");
#endif
- var head = _readIndex % capacity;
- uint paddedStructSize = Align4(structSize);
+ var head = _readIndex % capacity;
+ var paddedStructSize = MemoryUtilities.Align4(structSize);
_readIndex += paddedStructSize;
if (_readIndex == _writeIndex)
@@ -134,78 +137,78 @@ namespace Svelto.ECS.DataStructures
}
if (head + paddedStructSize <= capacity)
- {
- return Unsafe.Read(_ptr + head);
- }
+ return Unsafe.Read(ptr + head);
T item = default;
- T* destination = &item;
var byteCountToEnd = capacity - head;
- Unsafe.CopyBlock(destination, _ptr + head, byteCountToEnd);
+ Unsafe.CopyBlock(Unsafe.AsPointer(ref item), ptr + head, byteCountToEnd);
var restCount = structSize - byteCountToEnd;
- Unsafe.CopyBlock((byte*) destination + byteCountToEnd, ptr, restCount);
+ Unsafe.CopyBlock((byte*) Unsafe.AsPointer(ref item) + byteCountToEnd, ptr, restCount);
return item;
}
}
-
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal ref T Reserve(out UnsafeArrayIndex index) where T : unmanaged
+ internal ref T Reserve(out UnsafeArrayIndex index) where T : struct
{
unsafe
{
var sizeOf = (uint) MemoryUtilities.SizeOf();
-
- T* buffer = (T *)(_ptr + _writeIndex);
+
+ ref var buffer = ref Unsafe.AsRef(ptr + _writeIndex);
+
#if DEBUG && !PROFILE_SVELTO
- if (_writeIndex > capacity) throw new Exception($"can't reserve if the writeIndex wrapped around the capacity, writeIndex {_writeIndex} capacity {capacity}");
- if (_writeIndex + sizeOf > capacity) throw new Exception("out of bound reserving");
-#endif
+ if (_writeIndex > capacity)
+ throw new Exception(
+ $"can't reserve if the writeIndex wrapped around the capacity, writeIndex {_writeIndex} capacity {capacity}");
+ if (_writeIndex + sizeOf > capacity)
+ throw new Exception("out of bound reserving");
+#endif
index = new UnsafeArrayIndex
{
capacity = capacity
, index = _writeIndex
};
- var align4 = Align4(sizeOf);
+ var align4 = MemoryUtilities.Align4(sizeOf);
_writeIndex += align4;
-
- return ref buffer[0];
+
+ return ref buffer;
}
}
-
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal ref T AccessReserved(UnsafeArrayIndex index) where T : unmanaged
+ internal ref T AccessReserved(UnsafeArrayIndex index) where T : struct
{
unsafe
{
#if DEBUG && !PROFILE_SVELTO
var size = MemoryUtilities.SizeOf();
- if (index.index + size > capacity) throw new Exception($"out of bound access, index {index.index} size {size} capacity {capacity}");
-#endif
- T* buffer = (T*) (_ptr + index.index);
-
- return ref buffer[0];
+ if (index.index + size > capacity)
+ throw new Exception($"out of bound access, index {index.index} size {size} capacity {capacity}");
+#endif
+ return ref Unsafe.AsRef(ptr + index.index);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal void Realloc(uint newCapacity) where T : unmanaged
+ internal void Realloc(uint newCapacity)
{
unsafe
{
//be sure it's multiple of 4. Assuming that what we write is aligned to 4, then we will always have aligned wrapped heads
- newCapacity = Align4(newCapacity);
-
+ newCapacity = MemoryUtilities.Align4(newCapacity);
+
byte* newPointer = null;
-#if DEBUG && !PROFILE_SVELTO
+#if DEBUG && !PROFILE_SVELTO
if (newCapacity <= capacity)
throw new Exception("new capacity must be bigger than current");
-#endif
+#endif
if (newCapacity > 0)
{
- newPointer = (byte*) MemoryUtilities.Alloc(newCapacity, allocator);
+ newPointer = (byte*) MemoryUtilities.Alloc(newCapacity, allocator);
if (size > 0)
{
var readerHead = _readIndex % capacity;
@@ -214,8 +217,8 @@ namespace Svelto.ECS.DataStructures
if (readerHead < writerHead)
{
//copy to the new pointer, from th reader position
- uint currentSize = _writeIndex - _readIndex;
- Unsafe.CopyBlock(newPointer, _ptr + readerHead, currentSize);
+ var currentSize = _writeIndex - _readIndex;
+ Unsafe.CopyBlock(newPointer, ptr + readerHead, currentSize);
}
//the assumption is that if size > 0 (so readerPointer and writerPointer are not the same)
//writerHead wrapped and reached readerHead. so I have to copy from readerHead to the end
@@ -224,19 +227,19 @@ namespace Svelto.ECS.DataStructures
{
var byteCountToEnd = capacity - readerHead;
- Unsafe.CopyBlock(newPointer, _ptr + readerHead, byteCountToEnd);
- Unsafe.CopyBlock(newPointer + byteCountToEnd, _ptr, writerHead);
+ Unsafe.CopyBlock(newPointer, ptr + readerHead, byteCountToEnd);
+ Unsafe.CopyBlock(newPointer + byteCountToEnd, ptr, writerHead);
}
}
}
- if (_ptr != null)
- MemoryUtilities.Free((IntPtr) _ptr, allocator);
+ if (ptr != null)
+ MemoryUtilities.Free((IntPtr) ptr, allocator);
_writeIndex = size;
_readIndex = 0;
-
- _ptr = newPointer;
+
+ ptr = newPointer;
capacity = newCapacity;
}
}
@@ -246,12 +249,12 @@ namespace Svelto.ECS.DataStructures
{
unsafe
{
- if (_ptr != null)
- MemoryUtilities.Free((IntPtr) _ptr, allocator);
+ if (ptr != null)
+ MemoryUtilities.Free((IntPtr) ptr, allocator);
- _ptr = null;
+ ptr = null;
_writeIndex = 0;
- capacity = 0;
+ capacity = 0;
}
}
@@ -259,18 +262,9 @@ namespace Svelto.ECS.DataStructures
public void Clear()
{
_writeIndex = 0;
- _readIndex = 0;
+ _readIndex = 0;
}
- uint Align4(uint input)
- {
- return (uint)(Math.Ceiling(input / 4.0) * 4);
- }
-
-#if UNITY_ECS
- [NativeDisableUnsafePtrRestriction]
-#endif
- unsafe byte* _ptr;
uint _writeIndex, _readIndex;
}
-}
+}
\ No newline at end of file
diff --git a/Svelto.ECS/Debugger/ExclusiveGroupDebugger.cs b/Svelto.ECS/Debugger/ExclusiveGroupDebugger.cs
new file mode 100644
index 0000000..b38e2dc
--- /dev/null
+++ b/Svelto.ECS/Debugger/ExclusiveGroupDebugger.cs
@@ -0,0 +1,69 @@
+using Svelto.ECS;
+
+#if DEBUG
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+public static class ExclusiveGroupDebugger
+{
+ static ExclusiveGroupDebugger()
+ {
+ Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
+ foreach (Assembly assembly in assemblies)
+ {
+ Type[] types = assembly.GetTypes();
+
+ foreach (Type type in types)
+ {
+ if (type != null && type.IsClass && type.IsSealed && type.IsAbstract) //this means only static classes
+ {
+ var fields = type.GetFields();
+ foreach (var field in fields)
+ {
+ if (field.IsStatic && typeof(ExclusiveGroup).IsAssignableFrom(field.FieldType))
+ {
+ string name = $"{type.FullName}.{field.Name}";
+ var group = (ExclusiveGroup) field.GetValue(null);
+ GroupMap.idToName[(ExclusiveGroupStruct) group] = name;
+ }
+
+ if (field.IsStatic && typeof(ExclusiveGroupStruct).IsAssignableFrom(field.FieldType))
+ {
+ string name = $"{type.FullName}.{field.Name}";
+ var group = (ExclusiveGroupStruct) field.GetValue(null);
+ GroupMap.idToName[@group] = name;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public static string ToName(this in ExclusiveGroupStruct group)
+ {
+ if (GroupMap.idToName.TryGetValue(group, out var name) == false)
+ name = $"";
+
+ return name;
+ }
+}
+
+public static class GroupMap
+{
+ static GroupMap()
+ {
+ GroupMap.idToName = new Dictionary();
+ }
+
+ internal static readonly Dictionary idToName;
+}
+#else
+public static class ExclusiveGroupDebugger
+{
+ public static string ToName(this in ExclusiveGroupStruct group)
+ {
+ return ((uint)group).ToString();
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Svelto.ECS/DynamicEntityDescriptor.cs b/Svelto.ECS/DynamicEntityDescriptor.cs
index df1da90..05aa65d 100644
--- a/Svelto.ECS/DynamicEntityDescriptor.cs
+++ b/Svelto.ECS/DynamicEntityDescriptor.cs
@@ -4,7 +4,7 @@ using Svelto.DataStructures;
namespace Svelto.ECS
{
///
- /// DynamicEntityDescriptor can be used to add entity views to an existing EntityDescriptor that act as flags,
+ /// DynamicEntityDescriptor can be used to add entity components to an existing EntityDescriptor that act as flags,
/// at building time.
/// This method allocates, so it shouldn't be abused
///
@@ -22,9 +22,9 @@ namespace Svelto.ECS
//assign it after otherwise the previous copy will overwrite the value in case the item
//is already present
- ComponentsToBuild[length] = new ComponentBuilder
+ ComponentsToBuild[length] = new ComponentBuilder
(
- new EntityInfoComponentView
+ new EntityInfoViewComponent
{
componentsToBuild = ComponentsToBuild
}
@@ -80,9 +80,9 @@ namespace Svelto.ECS
//assign it after otherwise the previous copy will overwrite the value in case the item
//is already present
- localEntitiesToBuild[index] = new ComponentBuilder
+ localEntitiesToBuild[index] = new ComponentBuilder
(
- new EntityInfoComponentView
+ new EntityInfoViewComponent
{
componentsToBuild = localEntitiesToBuild
}
@@ -100,7 +100,7 @@ namespace Svelto.ECS
for (var i = 0; i < length; i++)
{
//the special entity already exists
- if (defaultEntities[i].GetEntityComponentType() == EntityBuilderUtilities.ENTITY_STRUCT_INFO_VIEW)
+ if (defaultEntities[i].GetEntityComponentType() == ComponentBuilderUtilities.ENTITY_STRUCT_INFO_VIEW)
{
index = i;
break;
diff --git a/Svelto.ECS/ECSResources/ECSResources.cs b/Svelto.ECS/ECSResources/ECSResources.cs
index f307b2b..a1effb4 100644
--- a/Svelto.ECS/ECSResources/ECSResources.cs
+++ b/Svelto.ECS/ECSResources/ECSResources.cs
@@ -9,6 +9,10 @@ namespace Svelto.ECS.Experimental
public static implicit operator T(ECSResources ecsString) { return ResourcesECSDB.FromECS(ecsString.id); }
}
+ ///
+ /// To do. Or we reuse the ID or we need to clear this
+ ///
+ ///
static class ResourcesECSDB
{
static readonly FasterList _resources = new FasterList();
diff --git a/Svelto.ECS/ECSResources/ECSString.cs b/Svelto.ECS/ECSResources/ECSString.cs
index b31e54e..2717aaa 100644
--- a/Svelto.ECS/ECSResources/ECSString.cs
+++ b/Svelto.ECS/ECSResources/ECSString.cs
@@ -1,18 +1,25 @@
using System;
+using System.Runtime.InteropServices;
namespace Svelto.ECS.Experimental
{
[Serialization.DoNotSerialize]
+ [StructLayout(LayoutKind.Explicit)]
+ ///
+ /// Note: I should extend this to reuse unused id
+ ///
public struct ECSString:IEquatable
{
- uint _id;
+ [FieldOffset(0)] uint _id;
+ [FieldOffset(4)] uint _versioning;
+ [FieldOffset(0)] long _realID;
- public ECSString(string newText)
+ public ECSString(string newText):this()
{
_id = ResourcesECSDB.ToECS(newText);
}
-
- ECSString(uint id)
+
+ ECSString(uint id):this()
{
_id = id;
}
@@ -21,11 +28,24 @@ namespace Svelto.ECS.Experimental
{
return ResourcesECSDB.FromECS(ecsString._id);
}
-
+
+ ///
+ /// Note: Setting null String could be a good way to signal a disposing of the ID so that
+ /// it can be recycled.
+ /// Zero id must be a null string
+ ///
+ ///
public void Set(string newText)
{
if (_id != 0)
- ResourcesECSDB.resources(_id) = newText;
+ {
+ if (ResourcesECSDB.resources(_id).Equals(newText) == false)
+ {
+ ResourcesECSDB.resources(_id) = newText;
+
+ _versioning++;
+ }
+ }
else
_id = ResourcesECSDB.ToECS(newText);
}
@@ -39,14 +59,34 @@ namespace Svelto.ECS.Experimental
return new ECSString(id);
}
+ public override string ToString()
+ {
+ return ResourcesECSDB.FromECS(_id);
+ }
+
public bool Equals(ECSString other)
{
- return other._id == _id;
+ return _realID == other._realID;
}
- public override string ToString()
+ public static bool operator==(ECSString options1, ECSString options2)
{
- return ResourcesECSDB.FromECS(_id);
+ return options1._realID == options2._realID;
+ }
+
+ public static bool operator!=(ECSString options1, ECSString options2)
+ {
+ return options1._realID != options2._realID;
+ }
+
+ public override bool Equals(object obj)
+ {
+ throw new NotSupportedException(); //this is on purpose
+ }
+
+ public override int GetHashCode()
+ {
+ return _realID.GetHashCode();
}
}
}
\ No newline at end of file
diff --git a/Svelto.ECS/EGID.cs b/Svelto.ECS/EGID.cs
index 176c19b..4945031 100644
--- a/Svelto.ECS/EGID.cs
+++ b/Svelto.ECS/EGID.cs
@@ -5,7 +5,6 @@ using System.Runtime.InteropServices;
namespace Svelto.ECS
{
- //todo: add debug map
[Serialization.DoNotSerialize]
[Serializable]
[StructLayout(LayoutKind.Explicit)]
@@ -75,7 +74,7 @@ namespace Svelto.ECS
public override string ToString()
{
- return "id ".FastConcat(entityID).FastConcat(" group ").FastConcat(groupID);
+ return "id ".FastConcat(entityID).FastConcat(" group ").FastConcat(groupID.ToName());
}
}
}
diff --git a/Svelto.ECS/EGIDMapper.cs b/Svelto.ECS/EGIDMapper.cs
index b3ce79c..e4a23d0 100644
--- a/Svelto.ECS/EGIDMapper.cs
+++ b/Svelto.ECS/EGIDMapper.cs
@@ -1,66 +1,67 @@
-using System;
using System.Runtime.CompilerServices;
+using Svelto.DataStructures;
using Svelto.ECS.Internal;
namespace Svelto.ECS
{
public readonly struct EGIDMapper