From 345392dff547d245b28224e43cd9bea923d1da40 Mon Sep 17 00:00:00 2001 From: sebas77 Date: Sat, 21 Oct 2017 20:01:48 +0100 Subject: [PATCH] - Added new features to be able to handle nodes as pure structs - FasterList Clear has been renamed to FastClear. The standard Clear will clean the array like the normal List does - An engine can now receive callback for when nodes are disabled and enabled - --- DataStructures/FasterList.cs | 30 +++- DataStructures/LockFreeQueue.cs | 142 ++++++++++++++++++ .../Priority Queue/HeapPriorityQueue.cs | 2 +- DataStructures/ThreadSafeDictionary.cs | 2 - ECS/EngineNodeDB.cs | 8 +- ECS/EnginesRoot.cs | 74 +++++---- ECS/EntityDescriptor.cs | 38 ++--- ECS/IEngine.cs | 26 ++++ ECS/IEnginesRoot.cs | 2 +- ECS/INode.cs | 6 +- ...ipleNodesEngine.cs => MultiNodesEngine.cs} | 20 +-- ECS/SingleNodeEngine.cs | 2 +- ECS/StructNodes.cs | 110 +++++++++++--- Utilities/DesignByContract.cs | 6 +- 14 files changed, 353 insertions(+), 115 deletions(-) create mode 100644 DataStructures/LockFreeQueue.cs rename ECS/{MultipleNodesEngine.cs => MultiNodesEngine.cs} (62%) diff --git a/DataStructures/FasterList.cs b/DataStructures/FasterList.cs index 40407e4..6828af0 100644 --- a/DataStructures/FasterList.cs +++ b/DataStructures/FasterList.cs @@ -121,6 +121,8 @@ namespace Svelto.DataStructures public struct FasterReadOnlyList : IList { + public static FasterReadOnlyList DefaultList = new FasterReadOnlyList(new FasterList()); + public int Count { get { return _list.Count; } } public bool IsReadOnly { get { return true; } } @@ -274,6 +276,19 @@ namespace Svelto.DataStructures } } + public void FastClear() + { + _lockQ.EnterWriteLock(); + try + { + _list.FastClear(); + } + finally + { + _lockQ.ExitWriteLock(); + } + } + public bool Contains(T item) { _lockQ.EnterReadLock(); @@ -382,6 +397,8 @@ namespace Svelto.DataStructures public struct FasterReadOnlyListCast : IList where U:T { + public static FasterReadOnlyListCast DefaultList = new FasterReadOnlyListCast(new FasterList()); + public int Count { get { return _list.Count; } } public bool IsReadOnly { get { return true; } } @@ -455,7 +472,6 @@ namespace Svelto.DataStructures public class FasterList : IList, IFasterList { - public static FasterList DefaultList = new FasterList(); const int MIN_SIZE = 4; public int Count @@ -529,7 +545,7 @@ namespace Svelto.DataStructures for (int i = 0; i < initialSize; i++) list.Add(new U()); - list.Clear(); + list._count = 0; return list; } @@ -583,12 +599,12 @@ namespace Svelto.DataStructures /// Careful, you could keep on holding references you don't want to hold to anymore /// Use DeepClear in case. /// - public void Clear() + public void FastClear() { _count = 0; } - public void DeepClear() + public void Clear() { Array.Clear(_buffer, 0, _buffer.Length); @@ -727,11 +743,13 @@ namespace Svelto.DataStructures DesignByContract.Check.Require(index < _count && _count > 0, "out of bound index"); if (index == --_count) + { + _buffer[_count] = default(T); return false; + } - T swap = _buffer[index]; _buffer[index] = _buffer[_count]; - _buffer[_count] = swap; + _buffer[_count] = default(T); return true; } diff --git a/DataStructures/LockFreeQueue.cs b/DataStructures/LockFreeQueue.cs new file mode 100644 index 0000000..01ae6e5 --- /dev/null +++ b/DataStructures/LockFreeQueue.cs @@ -0,0 +1,142 @@ +using System.Collections.Generic; +using System.Threading; + +//from unify wiki +namespace Svelto.DataStructures +{ + public class SingleLinkNode + { + // Note; the Next member cannot be a property since + // it participates in many CAS operations + public SingleLinkNode Next; + public T Item; + } + + public static class SyncMethods + { + public static bool CAS(ref T location, T comparand, T newValue) where T : class + { + return + (object)comparand == + (object)Interlocked.CompareExchange(ref location, newValue, comparand); + } + } + + public class LockFreeLinkPool + { + private SingleLinkNode head; + + public LockFreeLinkPool() + { + head = new SingleLinkNode(); + } + + public void Push(SingleLinkNode newNode) + { + newNode.Item = default(T); + do + { + newNode.Next = head.Next; + } while (!SyncMethods.CAS>(ref head.Next, newNode.Next, newNode)); + return; + } + + public bool Pop(out SingleLinkNode node) + { + do + { + node = head.Next; + if (node == null) + { + return false; + } + } while (!SyncMethods.CAS>(ref head.Next, node, node.Next)); + return true; + } + } + + public class LockFreeQueue + { + + SingleLinkNode head; + SingleLinkNode tail; + LockFreeLinkPool trash; + + public LockFreeQueue() + { + head = new SingleLinkNode(); + tail = head; + trash = new LockFreeLinkPool(); + } + + public void Enqueue(T item) + { + SingleLinkNode oldTail = null; + SingleLinkNode oldTailNext; + + SingleLinkNode newNode; + if (!trash.Pop(out newNode)) + { + newNode = new SingleLinkNode(); + } + else + { + newNode.Next = null; + } + newNode.Item = item; + + bool newNodeWasAdded = false; + while (!newNodeWasAdded) + { + oldTail = tail; + oldTailNext = oldTail.Next; + + if (tail == oldTail) + { + if (oldTailNext == null) + newNodeWasAdded = SyncMethods.CAS>(ref tail.Next, null, newNode); + else + SyncMethods.CAS>(ref tail, oldTail, oldTailNext); + } + } + SyncMethods.CAS>(ref tail, oldTail, newNode); + } + + public bool Dequeue(out T item) + { + item = default(T); + SingleLinkNode oldHead = null; + + bool haveAdvancedHead = false; + while (!haveAdvancedHead) + { + + oldHead = head; + SingleLinkNode oldTail = tail; + SingleLinkNode oldHeadNext = oldHead.Next; + + if (oldHead == head) + { + if (oldHead == oldTail) + { + if (oldHeadNext == null) + { + return false; + } + SyncMethods.CAS>(ref tail, oldTail, oldHeadNext); + } + else + { + item = oldHeadNext.Item; + haveAdvancedHead = SyncMethods.CAS>(ref head, oldHead, oldHeadNext); + if (haveAdvancedHead) + { + trash.Push(oldHead); + } + } + } + } + return true; + } + } +} \ No newline at end of file diff --git a/DataStructures/Priority Queue/HeapPriorityQueue.cs b/DataStructures/Priority Queue/HeapPriorityQueue.cs index c30e06d..606acd5 100644 --- a/DataStructures/Priority Queue/HeapPriorityQueue.cs +++ b/DataStructures/Priority Queue/HeapPriorityQueue.cs @@ -66,7 +66,7 @@ namespace Svelto.DataStructures #endif public void Clear() { - _nodes.Clear(); + _nodes.FastClear(); _numNodes = 0; } diff --git a/DataStructures/ThreadSafeDictionary.cs b/DataStructures/ThreadSafeDictionary.cs index 0bfb662..19e72e4 100644 --- a/DataStructures/ThreadSafeDictionary.cs +++ b/DataStructures/ThreadSafeDictionary.cs @@ -3,8 +3,6 @@ using System; using System.Collections.Generic; using System.Threading; -//note, rewrite like ThreadSafeQueue - namespace Svelto.DataStructures { /// diff --git a/ECS/EngineNodeDB.cs b/ECS/EngineNodeDB.cs index 36bef54..c10540f 100644 --- a/ECS/EngineNodeDB.cs +++ b/ECS/EngineNodeDB.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using Svelto.DataStructures; -using Svelto.ECS.Internal; namespace Svelto.ECS { @@ -9,13 +8,11 @@ namespace Svelto.ECS { internal EngineNodeDB( Dictionary> nodesDB, Dictionary> nodesDBdic, - Dictionary> metaNodesDB, - Dictionary structNodesDB) + Dictionary> metaNodesDB) { _nodesDB = nodesDB; _nodesDBdic = nodesDBdic; _metaNodesDB = metaNodesDB; - _structNodesDB = structNodesDB; } public FasterReadOnlyListCast QueryNodes() where T:INode @@ -102,13 +99,12 @@ namespace Svelto.ECS static FasterReadOnlyListCast RetrieveEmptyNodeList() where T : INode { - return new FasterReadOnlyListCast(FasterList.DefaultList); + return FasterReadOnlyListCast.DefaultList; } readonly Dictionary> _nodesDB; readonly Dictionary> _nodesDBdic; readonly Dictionary> _metaNodesDB; - readonly Dictionary _structNodesDB; readonly ReadOnlyDictionary _defaultEmptyNodeDict = new ReadOnlyDictionary(new Dictionary()); } diff --git a/ECS/EnginesRoot.cs b/ECS/EnginesRoot.cs index a70807b..4aa482a 100644 --- a/ECS/EnginesRoot.cs +++ b/ECS/EnginesRoot.cs @@ -16,23 +16,6 @@ using System.Reflection; namespace Svelto.ECS { - class Scheduler : MonoBehaviour - { - IEnumerator Start() - { - while (true) - { - yield return _waitForEndOfFrame; - - OnTick(); - } - } - - internal Action OnTick; - - readonly WaitForEndOfFrame _waitForEndOfFrame = new WaitForEndOfFrame(); - } - public sealed class EnginesRoot : IEnginesRoot, IEntityFactory { public EnginesRoot(NodeSubmissionScheduler nodeScheduler) @@ -50,7 +33,8 @@ namespace Svelto.ECS _metaNodesToAdd = new FasterList(); _metaNodesDB = new Dictionary>(); - _structNodesDB = new Dictionary(); + _sharedStructNodeLists = new SharedStructNodeLists(); + _sharedGroupedStructNodeLists = new SharedGroupedStructNodesLists(); _internalRemove = InternalRemove; _internalDisable = InternalDisable; @@ -60,6 +44,8 @@ namespace Svelto.ECS _scheduler = nodeScheduler; _scheduler.Schedule(SubmitNodes); + _structNodeEngineType = typeof(IStructNodeEngine<>); + _groupedStructNodesEngineType = typeof(IGroupedStructNodesEngine<>); _activableNodeEngineType = typeof(IActivableNodeEngine<>); _implementedInterfaceTypes = new Dictionary(); @@ -84,9 +70,11 @@ namespace Svelto.ECS do { + var nodesToAdd = _nodesToAdd.ToArrayFast(); + for (int i = startNodes; i < nodesCount; i++) { - var node = _nodesToAdd[i]; + var node = nodesToAdd[i]; var nodeType = node.GetType(); AddNodeToTheDB(node, nodeType); @@ -95,9 +83,11 @@ namespace Svelto.ECS AddNodeToNodesDictionary(nodeWithId, nodeType); } + var metaNodesToAdd = _metaNodesToAdd.ToArrayFast(); + for (int i = startMetaNodes; i < metaNodesCount; i++) { - var node = _metaNodesToAdd[i]; + var node = metaNodesToAdd[i]; var nodeType = node.GetType(); AddNodeToMetaDB(node, nodeType); @@ -108,13 +98,13 @@ namespace Svelto.ECS for (int i = startNodes; i < nodesCount; i++) { - var node = _nodesToAdd[i]; + var node = nodesToAdd[i]; AddNodeToTheSuitableEngines(node, node.GetType()); } for (int i = startMetaNodes; i < metaNodesCount; i++) { - var node = _metaNodesToAdd[i]; + var node = metaNodesToAdd[i]; AddNodeToTheSuitableEngines(node, node.GetType()); } @@ -147,7 +137,7 @@ namespace Svelto.ECS var queryableNodeEngine = engine as IQueryableNodeEngine; if (queryableNodeEngine != null) queryableNodeEngine.nodesDB = - new EngineNodeDB(_nodesDB, _nodesDBdic, _metaNodesDB, _structNodesDB); + new EngineNodeDB(_nodesDB, _nodesDBdic, _metaNodesDB); var engineType = engine.GetType(); var implementedInterfaces = engineType.GetInterfaces(); @@ -185,8 +175,6 @@ namespace Svelto.ECS } var genericTypeDefinition = interfaceType.GetGenericTypeDefinition(); - var a = interfaceType.GetGenericArguments(); - var b = genericTypeDefinition.GetGenericArguments(); _implementedInterfaceTypes.Add(genericTypeDefinition, interfaceType.GetGenericArguments()); @@ -199,6 +187,18 @@ namespace Svelto.ECS bool engineAdded = false; + if (_implementedInterfaceTypes.ContainsKey(_structNodeEngineType)) + { + ((IStructNodeEngine)engine).CreateStructNodes + (_sharedStructNodeLists); + } + + if (_implementedInterfaceTypes.ContainsKey(_groupedStructNodesEngineType)) + { + ((IGroupedStructNodesEngine)engine).CreateStructNodes + (_sharedGroupedStructNodeLists); + } + Type[] arguments; if (_implementedInterfaceTypes.TryGetValue(_activableNodeEngineType, out arguments)) @@ -298,7 +298,7 @@ namespace Svelto.ECS /// /// /// - public void BuildEntityInGroup(int entityID, int groupID, + public void BuildEntityInGroup(short entityID, short groupID, EntityDescriptor ed) { var entityNodes = ed.BuildNodes(entityID, @@ -349,19 +349,10 @@ namespace Svelto.ECS void AddNodeToTheDB(T node, Type nodeType) where T : INode { FasterList nodes; + if (_nodesDB.TryGetValue(nodeType, out nodes) == false) + nodes = _nodesDB[nodeType] = new FasterList(); - if (node is IStructNodeWithID == false) - { - if (_nodesDB.TryGetValue(nodeType, out nodes) == false) - nodes = _nodesDB[nodeType] = new FasterList(); - - nodes.Add(node); - } - else - { - if (_nodesDB.TryGetValue(nodeType, out nodes) == false) - nodes = _nodesDB[nodeType] = new FasterList(); - } + nodes.Add(node); } void AddNodeToNodesDictionary(T node, Type nodeType) where T : INodeWithID @@ -535,14 +526,15 @@ namespace Svelto.ECS readonly Dictionary> _nodesDB; readonly Dictionary> _metaNodesDB; - readonly Dictionary _structNodesDB; readonly Dictionary> _nodesDBdic; readonly FasterList _nodesToAdd; readonly FasterList _metaNodesToAdd; - readonly WeakReference _engineRootWeakReference; + readonly WeakReference _engineRootWeakReference; + readonly SharedStructNodeLists _sharedStructNodeLists; + readonly SharedGroupedStructNodesLists _sharedGroupedStructNodeLists; readonly NodeSubmissionScheduler _scheduler; @@ -551,6 +543,8 @@ namespace Svelto.ECS readonly Action> _internalDisable; readonly Action> _internalMetaRemove; + readonly Type _structNodeEngineType; + readonly Type _groupedStructNodesEngineType; readonly Type _activableNodeEngineType; readonly Dictionary _implementedInterfaceTypes; diff --git a/ECS/EntityDescriptor.cs b/ECS/EntityDescriptor.cs index 1550f60..946e1a8 100644 --- a/ECS/EntityDescriptor.cs +++ b/ECS/EntityDescriptor.cs @@ -10,10 +10,12 @@ namespace Svelto.ECS { public class EntityDescriptor { - protected EntityDescriptor(INodeBuilder[] nodesToBuild, params object[] componentsImplementor) + protected EntityDescriptor(INodeBuilder[] nodesToBuild) { _nodesToBuild = new FasterList(nodesToBuild); - + } + protected EntityDescriptor(INodeBuilder[] nodesToBuild, params object[] componentsImplementor):this(nodesToBuild) + { ProcessImplementors(componentsImplementor); } @@ -84,12 +86,9 @@ namespace Svelto.ECS Action> disableEntity, FasterList nodes) { - Action removeEntityAction = () => - { removeEntity(nodes); nodes.Clear(); }; - Action disableEntityAction = () => - { disableEntity(nodes); }; - Action enableEntityAction = () => - { enableEntity(nodes); }; + Action removeEntityAction = () => { removeEntity(nodes); nodes.Clear(); }; + Action disableEntityAction = () => disableEntity(nodes); + Action enableEntityAction = () => enableEntity(nodes); for (int index = 0; index < _removingImplementors.Count; index++) _removingImplementors[index].removeEntity = removeEntityAction; @@ -99,7 +98,7 @@ namespace Svelto.ECS _enablingImplementors[index].enableEntity = enableEntityAction; } - INode FillNode(INode node, FillNodeMode mode) + TNode FillNode(TNode node, FillNodeMode mode) where TNode : INode { var fields = node.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance); @@ -131,21 +130,21 @@ namespace Svelto.ECS readonly FasterList _disablingImplementors = new FasterList(); readonly FasterList _removingImplementors = new FasterList(); readonly FasterList _enablingImplementors = new FasterList(); - readonly Dictionary _implementorsByType = new Dictionary(); + readonly FasterList _nodesToBuild; } public interface INodeBuilder { - INodeWithID Build(int ID); + INode Build(int ID); FillNodeMode reflects { get; } } public class NodeBuilder : INodeBuilder where NodeType : NodeWithID, new() { - public INodeWithID Build(int ID) + public INode Build(int ID) { NodeWithID node = NodeWithID.BuildNode(ID); @@ -155,20 +154,25 @@ namespace Svelto.ECS public FillNodeMode reflects { get { return FillNodeMode.Strict; } } } - //To Do: Probably I will need to add an - //FastStructNodeBuilder where reflects is false public class StructNodeBuilder : INodeBuilder where NodeType : struct, IStructNodeWithID { - public INodeWithID Build(int ID) + public INode Build(int ID) { + var shortID = (short)ID; IStructNodeWithID node = default(NodeType); - node.ID = ID; + node.ID = shortID; return node; } - public FillNodeMode reflects { get { return FillNodeMode.Relaxed; } } + public virtual FillNodeMode reflects { get { return FillNodeMode.Relaxed; } } + } + + public class FastStructNodeBuilder : StructNodeBuilder + where NodeType : struct, IStructNodeWithID + { + public override FillNodeMode reflects { get { return FillNodeMode.None; } } } public enum FillNodeMode diff --git a/ECS/IEngine.cs b/ECS/IEngine.cs index b39e4df..d811e9a 100644 --- a/ECS/IEngine.cs +++ b/ECS/IEngine.cs @@ -2,6 +2,16 @@ using Svelto.ECS.Internal; namespace Svelto.ECS.Internal { + public interface IStructNodeEngine : IEngine + { + void CreateStructNodes(SharedStructNodeLists sharedStructNodeLists); + } + + public interface IGroupedStructNodesEngine : IEngine + { + void CreateStructNodes(SharedGroupedStructNodesLists sharedStructNodeLists); + } + public interface IActivableNodeEngine : IEngine { void Enable(INode obj); @@ -32,5 +42,21 @@ namespace Svelto.ECS { IEngineNodeDB nodesDB { set; } } + + /// + /// The engines can receive and store INodes structs + /// Unboxing will happen during the Add, but the + /// data will then be stored and processed as stucts + /// + public interface IStructNodeEngine : IStructNodeEngine where T:struct, IStructNodeWithID + { } + + /// + /// same as above, but the nodes are grouped by ID + /// usually the ID is the owner of the nodes of that + /// group + /// + public interface IGroupedStructNodesEngine : IGroupedStructNodesEngine where T:struct, IGroupedStructNodeWithID + { } } diff --git a/ECS/IEnginesRoot.cs b/ECS/IEnginesRoot.cs index 5535222..544fbc6 100644 --- a/ECS/IEnginesRoot.cs +++ b/ECS/IEnginesRoot.cs @@ -13,6 +13,6 @@ namespace Svelto.ECS void BuildMetaEntity(int metaEntityID, EntityDescriptor ED); - void BuildEntityInGroup(int entityID, int groupID, EntityDescriptor ED); + void BuildEntityInGroup(short entityID, short groupID, EntityDescriptor ED); } } diff --git a/ECS/INode.cs b/ECS/INode.cs index ac85ef8..3f3999c 100644 --- a/ECS/INode.cs +++ b/ECS/INode.cs @@ -8,14 +8,14 @@ namespace Svelto.ECS int ID { get; } } - public interface IStructNodeWithID : INodeWithID + public interface IStructNodeWithID : INode { - new int ID { get; set; } + short ID { get; set; } } public interface IGroupedStructNodeWithID : IStructNodeWithID { - int groupID { get; set; } + short groupID { get; set; } } public class NodeWithID: INodeWithID diff --git a/ECS/MultipleNodesEngine.cs b/ECS/MultiNodesEngine.cs similarity index 62% rename from ECS/MultipleNodesEngine.cs rename to ECS/MultiNodesEngine.cs index 70586c1..2907917 100644 --- a/ECS/MultipleNodesEngine.cs +++ b/ECS/MultiNodesEngine.cs @@ -5,8 +5,8 @@ namespace Svelto.ECS.Internal public abstract class MultiNodesEngine where T : INode { - protected internal abstract void Add(T node); - protected internal abstract void Remove(T node); + protected abstract void AddNode(T node); + protected abstract void RemoveNode(T node); } } @@ -20,28 +20,28 @@ namespace Svelto.ECS public abstract void Remove(INode node); } - public abstract class MultiNodesEngine : MultiNodesEngine, + public abstract class MultiNodesEngine : MultiNodesEngine, INodeEngine - where T : INode + where T : INode where U : INode { - protected abstract void Add(T node); - protected abstract void Remove(T node); + protected abstract void AddNode(U node); + protected abstract void RemoveNode(U node); public void Add(INode node) { if (node is T) - Add((T) node); + AddNode((T)node); else - ((MultiNodesEngine)(this)).Add((U)node); + AddNode((U)node); } public void Remove(INode node) { if (node is T) - Remove((T)node); + RemoveNode((T)node); else - ((MultiNodesEngine)(this)).Remove((U)node); + RemoveNode((U)node); } } } \ No newline at end of file diff --git a/ECS/SingleNodeEngine.cs b/ECS/SingleNodeEngine.cs index 3d7a45f..e641f32 100644 --- a/ECS/SingleNodeEngine.cs +++ b/ECS/SingleNodeEngine.cs @@ -3,7 +3,7 @@ namespace Svelto.ECS { public abstract class SingleNodeEngine : INodeEngine - where TNodeType : class, INode + where TNodeType : INode { public void Add(INode obj) { diff --git a/ECS/StructNodes.cs b/ECS/StructNodes.cs index aa708f4..582abab 100644 --- a/ECS/StructNodes.cs +++ b/ECS/StructNodes.cs @@ -1,22 +1,21 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Svelto.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS { - public class StructNodes: IStructNodes where T:struct, IStructNodeWithID + public class StructNodes where T:struct, IStructNodeWithID { - public FasterList list + public T[] GetList(out int numberOfItems) { - get - { - return _internalList; - } + numberOfItems = _internalList.Count; + return _internalList.ToArrayFast(); } - public StructNodes() + public StructNodes(SharedStructNodeLists container) { - _internalList = new FasterList(); + _internalList = container.GetList(); } public void Add(T node) @@ -29,46 +28,107 @@ namespace Svelto.ECS readonly FasterList _internalList; } - public class StructGroupNodes: IStructGroupNodes + public class StructGroupNodes where T : struct, IGroupedStructNodeWithID { + public StructGroupNodes(SharedGroupedStructNodesLists container) + { + _container = container; + } + public void Add(int groupID, T node) { T convert = (T)node; - var fasterList = GetList(groupID); - _indices[node.ID] = fasterList.Count; + var fasterList = (_container.GetList(groupID) as FasterList); + indices[node.ID] = fasterList.Count; fasterList.Add(convert); } public void Remove(int groupID, T node) { - var fasterList = GetList(groupID); - var index = _indices[node.ID]; - _indices.Remove(node.ID); + var fasterList = (_container.GetList(groupID) as FasterList); + var index = indices[node.ID]; + indices.Remove(node.ID); if (fasterList.UnorderedRemoveAt(index)) - _indices[fasterList[index].ID] = index; + indices[fasterList[index].ID] = index; } - public FasterList GetList(int groupID) + public T[] GetList(int groupID, out int numberOfItems) { - return _nodes[groupID]; + var fasterList = (_container.GetList(groupID) as FasterList); + numberOfItems = fasterList.Count; + return fasterList.ToArrayFast(); } - readonly Dictionary _indices = new Dictionary(); - Dictionary> _nodes = new Dictionary>(); + readonly SharedGroupedStructNodesLists _container; + readonly Dictionary indices = new Dictionary(); } -} -namespace Svelto.ECS.Internal -{ - public interface IStructGroupNodes + public class SharedStructNodeLists { + readonly Dictionary _collection; + + internal SharedStructNodeLists() + { + _collection = new Dictionary(); + } + + internal FasterList GetList() where T:struct + { + IFasterList list; + if (_collection.TryGetValue(typeof (T), out list)) + { + return list as FasterList; + } + + list = new FasterList(); + + _collection.Add(typeof (T), list); + + return (FasterList) list; + } } - public interface IStructNodes + public class SharedGroupedStructNodesLists { + internal SharedGroupedStructNodesLists() + { + _collection = new Dictionary>(); + } + + internal IFasterList GetList(int groupID) where T : struct + { + Dictionary dic = GetGroup(); + IFasterList localList; + + if (dic.TryGetValue(groupID, out localList)) + return localList; + + localList = new FasterList(); + dic.Add(groupID, localList); + + return localList; + } + + internal Dictionary GetGroup() where T : struct + { + Dictionary dic; + + if (_collection.TryGetValue(typeof(T), out dic)) + { + return dic; + } + + dic = new Dictionary(); + + _collection.Add(typeof(T), dic); + + return dic; + } + + readonly Dictionary> _collection; } } \ No newline at end of file diff --git a/Utilities/DesignByContract.cs b/Utilities/DesignByContract.cs index d34861e..0ac9bf8 100644 --- a/Utilities/DesignByContract.cs +++ b/Utilities/DesignByContract.cs @@ -26,10 +26,10 @@ // // Alternatively, you can define these in the project properties dialog. -#if UNITY_EDITOR || ROBO_TEST_BUILD -#define DBC_CHECK_ALL +#if DEBUG && !PROFILER +#define DBC_CHECK_ALL #endif - + using System; using System.Diagnostics;