diff --git a/Context/Factories/MonoBehaviourFactory.cs b/Context/Factories/MonoBehaviourFactory.cs index 7f862ab..bd376b6 100644 --- a/Context/Factories/MonoBehaviourFactory.cs +++ b/Context/Factories/MonoBehaviourFactory.cs @@ -2,7 +2,6 @@ #region using System; -using Svelto.DataStructures; using UnityEngine; #endregion diff --git a/Context/IUnityCompositionRoot.cs b/Context/IUnityCompositionRoot.cs new file mode 100644 index 0000000..c4db99a --- /dev/null +++ b/Context/IUnityCompositionRoot.cs @@ -0,0 +1,11 @@ +#if UNITY_5 || UNITY_5_3_OR_NEWER +namespace Svelto.Context +{ + public interface IUnityCompositionRoot + { + void OnContextCreated(UnityContext contextHolder); + void OnContextInitialized(); + void OnContextDestroyed(); + } +} +#endif \ No newline at end of file diff --git a/Context/IWaitForFrameworkDestruction.cs b/Context/IWaitForFrameworkDestruction.cs index 622fa3e..e830787 100644 --- a/Context/IWaitForFrameworkDestruction.cs +++ b/Context/IWaitForFrameworkDestruction.cs @@ -1,5 +1,3 @@ -using System; - namespace Svelto.Context { public interface IWaitForFrameworkDestruction diff --git a/Context/IWaitForFrameworkInitialization.cs b/Context/IWaitForFrameworkInitialization.cs index 937cbbc..f1b8dfb 100644 --- a/Context/IWaitForFrameworkInitialization.cs +++ b/Context/IWaitForFrameworkInitialization.cs @@ -1,5 +1,3 @@ -using System; - namespace Svelto.Context { public interface IWaitForFrameworkInitialization diff --git a/Context/UnityContext.cs b/Context/UnityContext.cs index 9591861..925a147 100644 --- a/Context/UnityContext.cs +++ b/Context/UnityContext.cs @@ -13,6 +13,11 @@ public abstract class UnityContext:MonoBehaviour } } +//a Unity context is a platform specific context wrapper. +//Unity will drive the ICompositionRoot interface. +//OnContextCreated is called during the Awake of this MB +//OnContextInitialized is called one frame after the MB started +//OnContextDestroyed is called when the MB is destroyed public class UnityContext: UnityContext where T:class, ICompositionRoot, new() { protected override void OnAwake() diff --git a/DataStructures/FasterList.cs b/DataStructures/FasterList.cs index 384683c..bc4c4f1 100644 --- a/DataStructures/FasterList.cs +++ b/DataStructures/FasterList.cs @@ -120,17 +120,20 @@ namespace Svelto.DataStructures public struct FasterReadOnlyList : IList { - public static FasterReadOnlyList DefaultList = new FasterReadOnlyList(new FasterList()); - + public static FasterReadOnlyList DefaultList = new FasterReadOnlyList(FasterList.DefaultList); + public int Count { get { return _list.Count; } } public bool IsReadOnly { get { return true; } } public FasterReadOnlyList(FasterList list) { _list = list; + + int count; + _buffer = FasterList.NoVirt.ToArrayFast(list, out count); } - public T this[int index] { get { return _list[index]; } set { throw new NotImplementedException(); } } + public T this[int index] { get { return _buffer[index]; } set { throw new NotImplementedException(); } } public FasterListEnumerator GetEnumerator() { @@ -188,6 +191,7 @@ namespace Svelto.DataStructures } readonly FasterList _list; + private readonly T[] _buffer; } public struct FasterListThreadSafe : IList @@ -396,7 +400,7 @@ namespace Svelto.DataStructures public struct FasterReadOnlyListCast : IList where U:T { - public static FasterReadOnlyListCast DefaultList = new FasterReadOnlyListCast(new FasterList()); + public static readonly FasterReadOnlyListCast DefaultList = new FasterReadOnlyListCast(new FasterList()); public int Count { get { return _list.Count; } } public bool IsReadOnly { get { return true; } } @@ -471,6 +475,8 @@ namespace Svelto.DataStructures public class FasterList : IList, IFasterList { + public static readonly FasterList DefaultList = new FasterList(); + const int MIN_SIZE = 4; public int Count @@ -631,7 +637,7 @@ namespace Svelto.DataStructures { var comp = EqualityComparer.Default; - for (var index = _count - 1; index >= 0; --index) + for (var index = 0; index < _count; index++) if (comp.Equals(_buffer[index], item)) return index; diff --git a/DataStructures/IGraphNode.cs b/DataStructures/IGraphNode.cs index 05a8c8e..e1fc894 100644 --- a/DataStructures/IGraphNode.cs +++ b/DataStructures/IGraphNode.cs @@ -9,7 +9,7 @@ //------------------------------------------------------------------------------ using System; -public interface IGraphNode +public interface IGraphEntityView { void VisitNeighbours(System.Action onVisiting); } diff --git a/DataStructures/LeftLeaningKeyedRedBlackTree.cs b/DataStructures/LeftLeaningKeyedRedBlackTree.cs index 0de1ae1..94f285b 100644 --- a/DataStructures/LeftLeaningKeyedRedBlackTree.cs +++ b/DataStructures/LeftLeaningKeyedRedBlackTree.cs @@ -1,6 +1,6 @@ // Uncomment this to enable the following debugging aids: // LeftLeaningRedBlackTree.HtmlFragment -// LeftLeaningRedBlackTree.Node.HtmlFragment +// LeftLeaningRedBlackTree.EntityView.HtmlFragment // LeftLeaningRedBlackTree.AssertInvariants // #define DEBUGGING @@ -21,42 +21,42 @@ using System.Diagnostics; public class LeftLeaningKeyedRedBlackTree where TKey: IComparable { /// - /// Stores the root node of the tree. + /// Stores the root entityView of the tree. /// - private Node _rootNode; + private EntityView _rootEntityView; /// - /// Represents a node of the tree. + /// Represents a entityView of the tree. /// /// /// Using fields instead of properties drops execution time by about 40%. /// [DebuggerDisplay("Key={Key}")] - private class Node + private class EntityView { /// - /// Gets or sets the node's key. + /// Gets or sets the entityView's key. /// public TKey Key; /// - /// Gets or sets the left node. + /// Gets or sets the left entityView. /// - public Node Left; + public EntityView Left; /// - /// Gets or sets the right node. + /// Gets or sets the right entityView. /// - public Node Right; + public EntityView Right; /// - /// Gets or sets the color of the node. + /// Gets or sets the color of the entityView. /// public bool IsBlack; #if DEBUGGING /// - /// Gets an HTML fragment representing the node and its children. + /// Gets an HTML fragment representing the entityView and its children. /// public string HtmlFragment { @@ -83,8 +83,8 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable /// Key to add. public void Add(TKey key) { - _rootNode = Add(_rootNode, key); - _rootNode.IsBlack = true; + _rootEntityView = Add(_rootEntityView, key); + _rootEntityView.IsBlack = true; #if DEBUGGING AssertInvariants(); #endif @@ -98,12 +98,12 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable public bool Remove(TKey key) { int initialCount = Count; - if (null != _rootNode) + if (null != _rootEntityView) { - _rootNode = Remove(_rootNode, key); - if (null != _rootNode) + _rootEntityView = Remove(_rootEntityView, key); + if (null != _rootEntityView) { - _rootNode.IsBlack = true; + _rootEntityView.IsBlack = true; } } #if DEBUGGING @@ -113,11 +113,11 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable } /// - /// Removes all nodes in the tree. + /// Removes all entityViews in the tree. /// public void Clear() { - _rootNode = null; + _rootEntityView = null; Count = 0; #if DEBUGGING AssertInvariants(); @@ -133,7 +133,7 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable TKey lastKey = default(TKey); bool lastKeyValid = false; return Traverse( - _rootNode, + _rootEntityView, n => !lastKeyValid || !object.Equals(lastKey, n.Key), n => { @@ -153,7 +153,7 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable /// public TKey MinimumKey { - get { return GetExtreme(_rootNode, n => n.Left, n => n.Key); } + get { return GetExtreme(_rootEntityView, n => n.Left, n => n.Key); } } /// @@ -161,310 +161,310 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable /// public TKey MaximumKey { - get { return GetExtreme(_rootNode, n => n.Right, n => n.Key); } + get { return GetExtreme(_rootEntityView, n => n.Right, n => n.Key); } } /// - /// Returns true if the specified node is red. + /// Returns true if the specified entityView is red. /// - /// Specified node. - /// True if specified node is red. - private static bool IsRed(Node node) + /// Specified entityView. + /// True if specified entityView is red. + private static bool IsRed(EntityView entityView) { - if (null == node) + if (null == entityView) { - // "Virtual" leaf nodes are always black + // "Virtual" leaf entityViews are always black return false; } - return !node.IsBlack; + return !entityView.IsBlack; } /// - /// Adds the specified key/value pair below the specified root node. + /// Adds the specified key/value pair below the specified root entityView. /// - /// Specified node. + /// Specified entityView. /// Key to add. /// Value to add. - /// New root node. - private Node Add(Node node, TKey key) + /// New root entityView. + private EntityView Add(EntityView entityView, TKey key) { - if (null == node) + if (null == entityView) { - // Insert new node + // Insert new entityView Count++; - return new Node { Key = key }; + return new EntityView { Key = key }; } - if (IsRed(node.Left) && IsRed(node.Right)) + if (IsRed(entityView.Left) && IsRed(entityView.Right)) { - // Split node with two red children - FlipColor(node); + // Split entityView with two red children + FlipColor(entityView); } - // Find right place for new node - int comparisonResult = KeyComparison(key, node.Key); + // Find right place for new entityView + int comparisonResult = KeyComparison(key, entityView.Key); if (comparisonResult < 0) { - node.Left = Add(node.Left, key); + entityView.Left = Add(entityView.Left, key); } else if (0 < comparisonResult) { - node.Right = Add(node.Right, key); + entityView.Right = Add(entityView.Right, key); } - if (IsRed(node.Right)) + if (IsRed(entityView.Right)) { - // Rotate to prevent red node on right - node = RotateLeft(node); + // Rotate to prevent red entityView on right + entityView = RotateLeft(entityView); } - if (IsRed(node.Left) && IsRed(node.Left.Left)) + if (IsRed(entityView.Left) && IsRed(entityView.Left.Left)) { - // Rotate to prevent consecutive red nodes - node = RotateRight(node); + // Rotate to prevent consecutive red entityViews + entityView = RotateRight(entityView); } - return node; + return entityView; } /// - /// Removes the specified key/value pair from below the specified node. + /// Removes the specified key/value pair from below the specified entityView. /// - /// Specified node. + /// Specified entityView. /// Key to remove. /// True if key/value present and removed. - private Node Remove(Node node, TKey key) + private EntityView Remove(EntityView entityView, TKey key) { - int comparisonResult = KeyComparison(key, node.Key); + int comparisonResult = KeyComparison(key, entityView.Key); if (comparisonResult < 0) { // * Continue search if left is present - if (null != node.Left) + if (null != entityView.Left) { - if (!IsRed(node.Left) && !IsRed(node.Left.Left)) + if (!IsRed(entityView.Left) && !IsRed(entityView.Left.Left)) { - // Move a red node over - node = MoveRedLeft(node); + // Move a red entityView over + entityView = MoveRedLeft(entityView); } // Remove from left - node.Left = Remove(node.Left, key); + entityView.Left = Remove(entityView.Left, key); } } else { - if (IsRed(node.Left)) + if (IsRed(entityView.Left)) { - // Flip a 3 node or unbalance a 4 node - node = RotateRight(node); + // Flip a 3 entityView or unbalance a 4 entityView + entityView = RotateRight(entityView); } - if ((0 == KeyComparison(key, node.Key)) && (null == node.Right)) + if ((0 == KeyComparison(key, entityView.Key)) && (null == entityView.Right)) { - // Remove leaf node - Debug.Assert(null == node.Left, "About to remove an extra node."); + // Remove leaf entityView + Debug.Assert(null == entityView.Left, "About to remove an extra entityView."); Count--; - // Leaf node is gone + // Leaf entityView is gone return null; } // * Continue search if right is present - if (null != node.Right) + if (null != entityView.Right) { - if (!IsRed(node.Right) && !IsRed(node.Right.Left)) + if (!IsRed(entityView.Right) && !IsRed(entityView.Right.Left)) { - // Move a red node over - node = MoveRedRight(node); + // Move a red entityView over + entityView = MoveRedRight(entityView); } - if (0 == KeyComparison(key, node.Key)) + if (0 == KeyComparison(key, entityView.Key)) { - // Remove leaf node + // Remove leaf entityView Count--; - // Find the smallest node on the right, swap, and remove it - Node m = GetExtreme(node.Right, n => n.Left, n => n); - node.Key = m.Key; - node.Right = DeleteMinimum(node.Right); + // Find the smallest entityView on the right, swap, and remove it + EntityView m = GetExtreme(entityView.Right, n => n.Left, n => n); + entityView.Key = m.Key; + entityView.Right = DeleteMinimum(entityView.Right); } else { // Remove from right - node.Right = Remove(node.Right, key); + entityView.Right = Remove(entityView.Right, key); } } } // Maintain invariants - return FixUp(node); + return FixUp(entityView); } /// - /// Flip the colors of the specified node and its direct children. + /// Flip the colors of the specified entityView and its direct children. /// - /// Specified node. - private static void FlipColor(Node node) + /// Specified entityView. + private static void FlipColor(EntityView entityView) { - node.IsBlack = !node.IsBlack; - node.Left.IsBlack = !node.Left.IsBlack; - node.Right.IsBlack = !node.Right.IsBlack; + entityView.IsBlack = !entityView.IsBlack; + entityView.Left.IsBlack = !entityView.Left.IsBlack; + entityView.Right.IsBlack = !entityView.Right.IsBlack; } /// - /// Rotate the specified node "left". + /// Rotate the specified entityView "left". /// - /// Specified node. - /// New root node. - private static Node RotateLeft(Node node) + /// Specified entityView. + /// New root entityView. + private static EntityView RotateLeft(EntityView entityView) { - Node x = node.Right; - node.Right = x.Left; - x.Left = node; - x.IsBlack = node.IsBlack; - node.IsBlack = false; + EntityView x = entityView.Right; + entityView.Right = x.Left; + x.Left = entityView; + x.IsBlack = entityView.IsBlack; + entityView.IsBlack = false; return x; } /// - /// Rotate the specified node "right". + /// Rotate the specified entityView "right". /// - /// Specified node. - /// New root node. - private static Node RotateRight(Node node) + /// Specified entityView. + /// New root entityView. + private static EntityView RotateRight(EntityView entityView) { - Node x = node.Left; - node.Left = x.Right; - x.Right = node; - x.IsBlack = node.IsBlack; - node.IsBlack = false; + EntityView x = entityView.Left; + entityView.Left = x.Right; + x.Right = entityView; + x.IsBlack = entityView.IsBlack; + entityView.IsBlack = false; return x; } /// - /// Moves a red node from the right child to the left child. + /// Moves a red entityView from the right child to the left child. /// - /// Parent node. - /// New root node. - private static Node MoveRedLeft(Node node) + /// Parent entityView. + /// New root entityView. + private static EntityView MoveRedLeft(EntityView entityView) { - FlipColor(node); - if (IsRed(node.Right.Left)) + FlipColor(entityView); + if (IsRed(entityView.Right.Left)) { - node.Right = RotateRight(node.Right); - node = RotateLeft(node); - FlipColor(node); + entityView.Right = RotateRight(entityView.Right); + entityView = RotateLeft(entityView); + FlipColor(entityView); - // * Avoid creating right-leaning nodes - if (IsRed(node.Right.Right)) + // * Avoid creating right-leaning entityViews + if (IsRed(entityView.Right.Right)) { - node.Right = RotateLeft(node.Right); + entityView.Right = RotateLeft(entityView.Right); } } - return node; + return entityView; } /// - /// Moves a red node from the left child to the right child. + /// Moves a red entityView from the left child to the right child. /// - /// Parent node. - /// New root node. - private static Node MoveRedRight(Node node) + /// Parent entityView. + /// New root entityView. + private static EntityView MoveRedRight(EntityView entityView) { - FlipColor(node); - if (IsRed(node.Left.Left)) + FlipColor(entityView); + if (IsRed(entityView.Left.Left)) { - node = RotateRight(node); - FlipColor(node); + entityView = RotateRight(entityView); + FlipColor(entityView); } - return node; + return entityView; } /// - /// Deletes the minimum node under the specified node. + /// Deletes the minimum entityView under the specified entityView. /// - /// Specified node. - /// New root node. - private Node DeleteMinimum(Node node) + /// Specified entityView. + /// New root entityView. + private EntityView DeleteMinimum(EntityView entityView) { - if (null == node.Left) + if (null == entityView.Left) { // Nothing to do return null; } - if (!IsRed(node.Left) && !IsRed(node.Left.Left)) + if (!IsRed(entityView.Left) && !IsRed(entityView.Left.Left)) { - // Move red node left - node = MoveRedLeft(node); + // Move red entityView left + entityView = MoveRedLeft(entityView); } // Recursively delete - node.Left = DeleteMinimum(node.Left); + entityView.Left = DeleteMinimum(entityView.Left); // Maintain invariants - return FixUp(node); + return FixUp(entityView); } /// - /// Maintains invariants by adjusting the specified nodes children. + /// Maintains invariants by adjusting the specified entityViews children. /// - /// Specified node. - /// New root node. - private static Node FixUp(Node node) + /// Specified entityView. + /// New root entityView. + private static EntityView FixUp(EntityView entityView) { - if (IsRed(node.Right)) + if (IsRed(entityView.Right)) { - // Avoid right-leaning node - node = RotateLeft(node); + // Avoid right-leaning entityView + entityView = RotateLeft(entityView); } - if (IsRed(node.Left) && IsRed(node.Left.Left)) + if (IsRed(entityView.Left) && IsRed(entityView.Left.Left)) { - // Balance 4-node - node = RotateRight(node); + // Balance 4-entityView + entityView = RotateRight(entityView); } - if (IsRed(node.Left) && IsRed(node.Right)) + if (IsRed(entityView.Left) && IsRed(entityView.Right)) { // Push red up - FlipColor(node); + FlipColor(entityView); } - // * Avoid leaving behind right-leaning nodes - if ((null != node.Left) && IsRed(node.Left.Right) && !IsRed(node.Left.Left)) + // * Avoid leaving behind right-leaning entityViews + if ((null != entityView.Left) && IsRed(entityView.Left.Right) && !IsRed(entityView.Left.Left)) { - node.Left = RotateLeft(node.Left); - if (IsRed(node.Left)) + entityView.Left = RotateLeft(entityView.Left); + if (IsRed(entityView.Left)) { - // Balance 4-node - node = RotateRight(node); + // Balance 4-entityView + entityView = RotateRight(entityView); } } - return node; + return entityView; } /// - /// Gets the (first) node corresponding to the specified key. + /// Gets the (first) entityView corresponding to the specified key. /// /// Key to search for. - /// Corresponding node or null if none found. - private Node GetNodeForKey(TKey key) + /// Corresponding entityView or null if none found. + private EntityView GetEntityViewForKey(TKey key) { // Initialize - Node node = _rootNode; - while (null != node) + EntityView entityView = _rootEntityView; + while (null != entityView) { // Compare keys and go left/right - int comparisonResult = key.CompareTo(node.Key); + int comparisonResult = key.CompareTo(entityView.Key); if (comparisonResult < 0) { - node = node.Left; + entityView = entityView.Left; } else if (0 < comparisonResult) { - node = node.Right; + entityView = entityView.Right; } else { - // Match; return node - return node; + // Match; return entityView + return entityView; } } @@ -476,15 +476,15 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable /// Gets an extreme (ex: minimum/maximum) value. /// /// Type of value. - /// Node to start from. + /// EntityView to start from. /// Successor function. /// Selector function. /// Extreme value. - private static T GetExtreme(Node node, Func successor, Func selector) + private static T GetExtreme(EntityView entityView, Func successor, Func selector) { // Initialize T extreme = default(T); - Node current = node; + EntityView current = entityView; while (null != current) { // Go to extreme @@ -495,18 +495,18 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable } /// - /// Traverses a subset of the sequence of nodes in order and selects the specified nodes. + /// Traverses a subset of the sequence of entityViews in order and selects the specified entityViews. /// /// Type of elements. - /// Starting node. + /// Starting entityView. /// Condition method. /// Selector method. - /// Sequence of selected nodes. - private IEnumerable Traverse(Node node, Func condition, Func selector) + /// Sequence of selected entityViews. + private IEnumerable Traverse(EntityView entityView, Func condition, Func selector) { // Create a stack to avoid recursion - Stack stack = new Stack(); - Node current = node; + Stack stack = new Stack(); + EntityView current = entityView; while (null != current) { if (null != current.Left) @@ -519,7 +519,7 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable { do { - // Select current node if relevant + // Select current entityView if relevant if (condition(current)) { yield return selector(current); @@ -552,29 +552,29 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable private void AssertInvariants() { // Root is black - Debug.Assert((null == _rootNode) || _rootNode.IsBlack, "Root is not black"); - // Every path contains the same number of black nodes - Dictionary parents = new Dictionary.Node, LeftLeaningRedBlackTree.Node>(); - foreach (Node node in Traverse(_rootNode, n => true, n => n)) + Debug.Assert((null == _rootEntityView) || _rootEntityView.IsBlack, "Root is not black"); + // Every path contains the same number of black entityViews + Dictionary parents = new Dictionary.EntityView, LeftLeaningRedBlackTree.EntityView>(); + foreach (EntityView entityView in Traverse(_rootEntityView, n => true, n => n)) { - if (null != node.Left) + if (null != entityView.Left) { - parents[node.Left] = node; + parents[entityView.Left] = entityView; } - if (null != node.Right) + if (null != entityView.Right) { - parents[node.Right] = node; + parents[entityView.Right] = entityView; } } - if (null != _rootNode) + if (null != _rootEntityView) { - parents[_rootNode] = null; + parents[_rootEntityView] = null; } int treeCount = -1; - foreach (Node node in Traverse(_rootNode, n => (null == n.Left) || (null == n.Right), n => n)) + foreach (EntityView entityView in Traverse(_rootEntityView, n => (null == n.Left) || (null == n.Right), n => n)) { int pathCount = 0; - Node current = node; + EntityView current = entityView; while (null != current) { if (current.IsBlack) @@ -583,28 +583,28 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable } current = parents[current]; } - Debug.Assert((-1 == treeCount) || (pathCount == treeCount), "Not all paths have the same number of black nodes."); + Debug.Assert((-1 == treeCount) || (pathCount == treeCount), "Not all paths have the same number of black entityViews."); treeCount = pathCount; } - // Verify node properties... - foreach (Node node in Traverse(_rootNode, n => true, n => n)) + // Verify entityView properties... + foreach (EntityView entityView in Traverse(_rootEntityView, n => true, n => n)) { - // Left node is less - if (null != node.Left) + // Left entityView is less + if (null != entityView.Left) { - Debug.Assert(0 > KeyAndValueComparison(node.Left.Key, node.Left.Value, node.Key, node.Value), "Left node is greater than its parent."); + Debug.Assert(0 > KeyAndValueComparison(entityView.Left.Key, entityView.Left.Value, entityView.Key, entityView.Value), "Left entityView is greater than its parent."); } - // Right node is greater - if (null != node.Right) + // Right entityView is greater + if (null != entityView.Right) { - Debug.Assert(0 < KeyAndValueComparison(node.Right.Key, node.Right.Value, node.Key, node.Value), "Right node is less than its parent."); + Debug.Assert(0 < KeyAndValueComparison(entityView.Right.Key, entityView.Right.Value, entityView.Key, entityView.Value), "Right entityView is less than its parent."); } - // Both children of a red node are black - Debug.Assert(!IsRed(node) || (!IsRed(node.Left) && !IsRed(node.Right)), "Red node has a red child."); + // Both children of a red entityView are black + Debug.Assert(!IsRed(entityView) || (!IsRed(entityView.Left) && !IsRed(entityView.Right)), "Red entityView has a red child."); // Always left-leaning - Debug.Assert(!IsRed(node.Right) || IsRed(node.Left), "Node is not left-leaning."); + Debug.Assert(!IsRed(entityView.Right) || IsRed(entityView.Left), "EntityView is not left-leaning."); // No consecutive reds (subset of previous rule) - //Debug.Assert(!(IsRed(node) && IsRed(node.Left))); + //Debug.Assert(!(IsRed(entityView) && IsRed(entityView.Left))); } } @@ -618,7 +618,7 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable return "" + "" + - (null != _rootNode ? _rootNode.HtmlFragment : "[null]") + + (null != _rootEntityView ? _rootEntityView.HtmlFragment : "[null]") + "" + ""; } diff --git a/DataStructures/LeftLeaningRedBlackTree.cs b/DataStructures/LeftLeaningRedBlackTree.cs index b6e3712..f109135 100644 --- a/DataStructures/LeftLeaningRedBlackTree.cs +++ b/DataStructures/LeftLeaningRedBlackTree.cs @@ -1,6 +1,6 @@ // Uncomment this to enable the following debugging aids: // LeftLeaningRedBlackTree.HtmlFragment -// LeftLeaningRedBlackTree.Node.HtmlFragment +// LeftLeaningRedBlackTree.EntityView.HtmlFragment // LeftLeaningRedBlackTree.AssertInvariants // #define DEBUGGING @@ -32,52 +32,52 @@ public class LeftLeaningRedBlackTree private Comparison _valueComparison; /// - /// Stores the root node of the tree. + /// Stores the root entityView of the tree. /// - private Node _rootNode; + private EntityView _rootEntityView; /// - /// Represents a node of the tree. + /// Represents a entityView of the tree. /// /// /// Using fields instead of properties drops execution time by about 40%. /// [DebuggerDisplay("Key={Key}, Value={Value}, Siblings={Siblings}")] - private class Node + private class EntityView { /// - /// Gets or sets the node's key. + /// Gets or sets the entityView's key. /// public TKey Key; /// - /// Gets or sets the node's value. + /// Gets or sets the entityView's value. /// public TValue Value; /// - /// Gets or sets the left node. + /// Gets or sets the left entityView. /// - public Node Left; + public EntityView Left; /// - /// Gets or sets the right node. + /// Gets or sets the right entityView. /// - public Node Right; + public EntityView Right; /// - /// Gets or sets the color of the node. + /// Gets or sets the color of the entityView. /// public bool IsBlack; /// - /// Gets or sets the number of "siblings" (nodes with the same key/value). + /// Gets or sets the number of "siblings" (entityViews with the same key/value). /// public int Siblings; #if DEBUGGING /// - /// Gets an HTML fragment representing the node and its children. + /// Gets an HTML fragment representing the entityView and its children. /// public string HtmlFragment { @@ -141,8 +141,8 @@ public class LeftLeaningRedBlackTree /// Value to add. public void Add(TKey key, TValue value) { - _rootNode = Add(_rootNode, key, value); - _rootNode.IsBlack = true; + _rootEntityView = Add(_rootEntityView, key, value); + _rootEntityView.IsBlack = true; #if DEBUGGING AssertInvariants(); #endif @@ -171,12 +171,12 @@ public class LeftLeaningRedBlackTree public bool Remove(TKey key, TValue value) { int initialCount = Count; - if (null != _rootNode) + if (null != _rootEntityView) { - _rootNode = Remove(_rootNode, key, value); - if (null != _rootNode) + _rootEntityView = Remove(_rootEntityView, key, value); + if (null != _rootEntityView) { - _rootNode.IsBlack = true; + _rootEntityView.IsBlack = true; } } #if DEBUGGING @@ -186,11 +186,11 @@ public class LeftLeaningRedBlackTree } /// - /// Removes all nodes in the tree. + /// Removes all entityViews in the tree. /// public void Clear() { - _rootNode = null; + _rootEntityView = null; Count = 0; #if DEBUGGING AssertInvariants(); @@ -206,7 +206,7 @@ public class LeftLeaningRedBlackTree TKey lastKey = default(TKey); bool lastKeyValid = false; return Traverse( - _rootNode, + _rootEntityView, n => !lastKeyValid || !object.Equals(lastKey, n.Key), n => { @@ -227,10 +227,10 @@ public class LeftLeaningRedBlackTree { throw new InvalidOperationException("GetValueForKey is only supported when acting as a normal (non-multi) dictionary."); } - Node node = GetNodeForKey(key); - if (null != node) + EntityView entityView = GetEntityViewForKey(key); + if (null != entityView) { - return node.Value; + return entityView.Value; } else { @@ -245,7 +245,7 @@ public class LeftLeaningRedBlackTree /// Sequence of values. public IEnumerable GetValuesForKey(TKey key) { - return Traverse(GetNodeForKey(key), n => 0 == _keyComparison(n.Key, key), n => n.Value); + return Traverse(GetEntityViewForKey(key), n => 0 == _keyComparison(n.Key, key), n => n.Value); } /// @@ -254,7 +254,7 @@ public class LeftLeaningRedBlackTree /// Sequence of all values. public IEnumerable GetValuesForAllKeys() { - return Traverse(_rootNode, n => true, n => n.Value); + return Traverse(_rootEntityView, n => true, n => n.Value); } /// @@ -267,7 +267,7 @@ public class LeftLeaningRedBlackTree /// public TKey MinimumKey { - get { return GetExtreme(_rootNode, n => n.Left, n => n.Key); } + get { return GetExtreme(_rootEntityView, n => n.Left, n => n.Key); } } /// @@ -275,346 +275,346 @@ public class LeftLeaningRedBlackTree /// public TKey MaximumKey { - get { return GetExtreme(_rootNode, n => n.Right, n => n.Key); } + get { return GetExtreme(_rootEntityView, n => n.Right, n => n.Key); } } /// - /// Returns true if the specified node is red. + /// Returns true if the specified entityView is red. /// - /// Specified node. - /// True if specified node is red. - private static bool IsRed(Node node) + /// Specified entityView. + /// True if specified entityView is red. + private static bool IsRed(EntityView entityView) { - if (null == node) + if (null == entityView) { - // "Virtual" leaf nodes are always black + // "Virtual" leaf entityViews are always black return false; } - return !node.IsBlack; + return !entityView.IsBlack; } /// - /// Adds the specified key/value pair below the specified root node. + /// Adds the specified key/value pair below the specified root entityView. /// - /// Specified node. + /// Specified entityView. /// Key to add. /// Value to add. - /// New root node. - private Node Add(Node node, TKey key, TValue value) + /// New root entityView. + private EntityView Add(EntityView entityView, TKey key, TValue value) { - if (null == node) + if (null == entityView) { - // Insert new node + // Insert new entityView Count++; - return new Node { Key = key, Value = value }; + return new EntityView { Key = key, Value = value }; } - if (IsRed(node.Left) && IsRed(node.Right)) + if (IsRed(entityView.Left) && IsRed(entityView.Right)) { - // Split node with two red children - FlipColor(node); + // Split entityView with two red children + FlipColor(entityView); } - // Find right place for new node - int comparisonResult = KeyAndValueComparison(key, value, node.Key, node.Value); + // Find right place for new entityView + int comparisonResult = KeyAndValueComparison(key, value, entityView.Key, entityView.Value); if (comparisonResult < 0) { - node.Left = Add(node.Left, key, value); + entityView.Left = Add(entityView.Left, key, value); } else if (0 < comparisonResult) { - node.Right = Add(node.Right, key, value); + entityView.Right = Add(entityView.Right, key, value); } else { if (IsMultiDictionary) { - // Store the presence of a "duplicate" node - node.Siblings++; + // Store the presence of a "duplicate" entityView + entityView.Siblings++; Count++; } else { - // Replace the value of the existing node - node.Value = value; + // Replace the value of the existing entityView + entityView.Value = value; } } - if (IsRed(node.Right)) + if (IsRed(entityView.Right)) { - // Rotate to prevent red node on right - node = RotateLeft(node); + // Rotate to prevent red entityView on right + entityView = RotateLeft(entityView); } - if (IsRed(node.Left) && IsRed(node.Left.Left)) + if (IsRed(entityView.Left) && IsRed(entityView.Left.Left)) { - // Rotate to prevent consecutive red nodes - node = RotateRight(node); + // Rotate to prevent consecutive red entityViews + entityView = RotateRight(entityView); } - return node; + return entityView; } /// - /// Removes the specified key/value pair from below the specified node. + /// Removes the specified key/value pair from below the specified entityView. /// - /// Specified node. + /// Specified entityView. /// Key to remove. /// Value to remove. /// True if key/value present and removed. - private Node Remove(Node node, TKey key, TValue value) + private EntityView Remove(EntityView entityView, TKey key, TValue value) { - int comparisonResult = KeyAndValueComparison(key, value, node.Key, node.Value); + int comparisonResult = KeyAndValueComparison(key, value, entityView.Key, entityView.Value); if (comparisonResult < 0) { // * Continue search if left is present - if (null != node.Left) + if (null != entityView.Left) { - if (!IsRed(node.Left) && !IsRed(node.Left.Left)) + if (!IsRed(entityView.Left) && !IsRed(entityView.Left.Left)) { - // Move a red node over - node = MoveRedLeft(node); + // Move a red entityView over + entityView = MoveRedLeft(entityView); } // Remove from left - node.Left = Remove(node.Left, key, value); + entityView.Left = Remove(entityView.Left, key, value); } } else { - if (IsRed(node.Left)) + if (IsRed(entityView.Left)) { - // Flip a 3 node or unbalance a 4 node - node = RotateRight(node); + // Flip a 3 entityView or unbalance a 4 entityView + entityView = RotateRight(entityView); } - if ((0 == KeyAndValueComparison(key, value, node.Key, node.Value)) && (null == node.Right)) + if ((0 == KeyAndValueComparison(key, value, entityView.Key, entityView.Value)) && (null == entityView.Right)) { - // Remove leaf node - Debug.Assert(null == node.Left, "About to remove an extra node."); + // Remove leaf entityView + Debug.Assert(null == entityView.Left, "About to remove an extra entityView."); Count--; - if (0 < node.Siblings) + if (0 < entityView.Siblings) { - // Record the removal of the "duplicate" node + // Record the removal of the "duplicate" entityView Debug.Assert(IsMultiDictionary, "Should not have siblings if tree is not a multi-dictionary."); - node.Siblings--; - return node; + entityView.Siblings--; + return entityView; } else { - // Leaf node is gone + // Leaf entityView is gone return null; } } // * Continue search if right is present - if (null != node.Right) + if (null != entityView.Right) { - if (!IsRed(node.Right) && !IsRed(node.Right.Left)) + if (!IsRed(entityView.Right) && !IsRed(entityView.Right.Left)) { - // Move a red node over - node = MoveRedRight(node); + // Move a red entityView over + entityView = MoveRedRight(entityView); } - if (0 == KeyAndValueComparison(key, value, node.Key, node.Value)) + if (0 == KeyAndValueComparison(key, value, entityView.Key, entityView.Value)) { - // Remove leaf node + // Remove leaf entityView Count--; - if (0 < node.Siblings) + if (0 < entityView.Siblings) { - // Record the removal of the "duplicate" node + // Record the removal of the "duplicate" entityView Debug.Assert(IsMultiDictionary, "Should not have siblings if tree is not a multi-dictionary."); - node.Siblings--; + entityView.Siblings--; } else { - // Find the smallest node on the right, swap, and remove it - Node m = GetExtreme(node.Right, n => n.Left, n => n); - node.Key = m.Key; - node.Value = m.Value; - node.Siblings = m.Siblings; - node.Right = DeleteMinimum(node.Right); + // Find the smallest entityView on the right, swap, and remove it + EntityView m = GetExtreme(entityView.Right, n => n.Left, n => n); + entityView.Key = m.Key; + entityView.Value = m.Value; + entityView.Siblings = m.Siblings; + entityView.Right = DeleteMinimum(entityView.Right); } } else { // Remove from right - node.Right = Remove(node.Right, key, value); + entityView.Right = Remove(entityView.Right, key, value); } } } // Maintain invariants - return FixUp(node); + return FixUp(entityView); } /// - /// Flip the colors of the specified node and its direct children. + /// Flip the colors of the specified entityView and its direct children. /// - /// Specified node. - private static void FlipColor(Node node) + /// Specified entityView. + private static void FlipColor(EntityView entityView) { - node.IsBlack = !node.IsBlack; - node.Left.IsBlack = !node.Left.IsBlack; - node.Right.IsBlack = !node.Right.IsBlack; + entityView.IsBlack = !entityView.IsBlack; + entityView.Left.IsBlack = !entityView.Left.IsBlack; + entityView.Right.IsBlack = !entityView.Right.IsBlack; } /// - /// Rotate the specified node "left". + /// Rotate the specified entityView "left". /// - /// Specified node. - /// New root node. - private static Node RotateLeft(Node node) + /// Specified entityView. + /// New root entityView. + private static EntityView RotateLeft(EntityView entityView) { - Node x = node.Right; - node.Right = x.Left; - x.Left = node; - x.IsBlack = node.IsBlack; - node.IsBlack = false; + EntityView x = entityView.Right; + entityView.Right = x.Left; + x.Left = entityView; + x.IsBlack = entityView.IsBlack; + entityView.IsBlack = false; return x; } /// - /// Rotate the specified node "right". + /// Rotate the specified entityView "right". /// - /// Specified node. - /// New root node. - private static Node RotateRight(Node node) + /// Specified entityView. + /// New root entityView. + private static EntityView RotateRight(EntityView entityView) { - Node x = node.Left; - node.Left = x.Right; - x.Right = node; - x.IsBlack = node.IsBlack; - node.IsBlack = false; + EntityView x = entityView.Left; + entityView.Left = x.Right; + x.Right = entityView; + x.IsBlack = entityView.IsBlack; + entityView.IsBlack = false; return x; } /// - /// Moves a red node from the right child to the left child. + /// Moves a red entityView from the right child to the left child. /// - /// Parent node. - /// New root node. - private static Node MoveRedLeft(Node node) + /// Parent entityView. + /// New root entityView. + private static EntityView MoveRedLeft(EntityView entityView) { - FlipColor(node); - if (IsRed(node.Right.Left)) + FlipColor(entityView); + if (IsRed(entityView.Right.Left)) { - node.Right = RotateRight(node.Right); - node = RotateLeft(node); - FlipColor(node); + entityView.Right = RotateRight(entityView.Right); + entityView = RotateLeft(entityView); + FlipColor(entityView); - // * Avoid creating right-leaning nodes - if (IsRed(node.Right.Right)) + // * Avoid creating right-leaning entityViews + if (IsRed(entityView.Right.Right)) { - node.Right = RotateLeft(node.Right); + entityView.Right = RotateLeft(entityView.Right); } } - return node; + return entityView; } /// - /// Moves a red node from the left child to the right child. + /// Moves a red entityView from the left child to the right child. /// - /// Parent node. - /// New root node. - private static Node MoveRedRight(Node node) + /// Parent entityView. + /// New root entityView. + private static EntityView MoveRedRight(EntityView entityView) { - FlipColor(node); - if (IsRed(node.Left.Left)) + FlipColor(entityView); + if (IsRed(entityView.Left.Left)) { - node = RotateRight(node); - FlipColor(node); + entityView = RotateRight(entityView); + FlipColor(entityView); } - return node; + return entityView; } /// - /// Deletes the minimum node under the specified node. + /// Deletes the minimum entityView under the specified entityView. /// - /// Specified node. - /// New root node. - private Node DeleteMinimum(Node node) + /// Specified entityView. + /// New root entityView. + private EntityView DeleteMinimum(EntityView entityView) { - if (null == node.Left) + if (null == entityView.Left) { // Nothing to do return null; } - if (!IsRed(node.Left) && !IsRed(node.Left.Left)) + if (!IsRed(entityView.Left) && !IsRed(entityView.Left.Left)) { - // Move red node left - node = MoveRedLeft(node); + // Move red entityView left + entityView = MoveRedLeft(entityView); } // Recursively delete - node.Left = DeleteMinimum(node.Left); + entityView.Left = DeleteMinimum(entityView.Left); // Maintain invariants - return FixUp(node); + return FixUp(entityView); } /// - /// Maintains invariants by adjusting the specified nodes children. + /// Maintains invariants by adjusting the specified entityViews children. /// - /// Specified node. - /// New root node. - private static Node FixUp(Node node) + /// Specified entityView. + /// New root entityView. + private static EntityView FixUp(EntityView entityView) { - if (IsRed(node.Right)) + if (IsRed(entityView.Right)) { - // Avoid right-leaning node - node = RotateLeft(node); + // Avoid right-leaning entityView + entityView = RotateLeft(entityView); } - if (IsRed(node.Left) && IsRed(node.Left.Left)) + if (IsRed(entityView.Left) && IsRed(entityView.Left.Left)) { - // Balance 4-node - node = RotateRight(node); + // Balance 4-entityView + entityView = RotateRight(entityView); } - if (IsRed(node.Left) && IsRed(node.Right)) + if (IsRed(entityView.Left) && IsRed(entityView.Right)) { // Push red up - FlipColor(node); + FlipColor(entityView); } - // * Avoid leaving behind right-leaning nodes - if ((null != node.Left) && IsRed(node.Left.Right) && !IsRed(node.Left.Left)) + // * Avoid leaving behind right-leaning entityViews + if ((null != entityView.Left) && IsRed(entityView.Left.Right) && !IsRed(entityView.Left.Left)) { - node.Left = RotateLeft(node.Left); - if (IsRed(node.Left)) + entityView.Left = RotateLeft(entityView.Left); + if (IsRed(entityView.Left)) { - // Balance 4-node - node = RotateRight(node); + // Balance 4-entityView + entityView = RotateRight(entityView); } } - return node; + return entityView; } /// - /// Gets the (first) node corresponding to the specified key. + /// Gets the (first) entityView corresponding to the specified key. /// /// Key to search for. - /// Corresponding node or null if none found. - private Node GetNodeForKey(TKey key) + /// Corresponding entityView or null if none found. + private EntityView GetEntityViewForKey(TKey key) { // Initialize - Node node = _rootNode; - while (null != node) + EntityView entityView = _rootEntityView; + while (null != entityView) { // Compare keys and go left/right - int comparisonResult = _keyComparison(key, node.Key); + int comparisonResult = _keyComparison(key, entityView.Key); if (comparisonResult < 0) { - node = node.Left; + entityView = entityView.Left; } else if (0 < comparisonResult) { - node = node.Right; + entityView = entityView.Right; } else { - // Match; return node - return node; + // Match; return entityView + return entityView; } } @@ -626,15 +626,15 @@ public class LeftLeaningRedBlackTree /// Gets an extreme (ex: minimum/maximum) value. /// /// Type of value. - /// Node to start from. + /// EntityView to start from. /// Successor function. /// Selector function. /// Extreme value. - private static T GetExtreme(Node node, Func successor, Func selector) + private static T GetExtreme(EntityView entityView, Func successor, Func selector) { // Initialize T extreme = default(T); - Node current = node; + EntityView current = entityView; while (null != current) { // Go to extreme @@ -645,18 +645,18 @@ public class LeftLeaningRedBlackTree } /// - /// Traverses a subset of the sequence of nodes in order and selects the specified nodes. + /// Traverses a subset of the sequence of entityViews in order and selects the specified entityViews. /// /// Type of elements. - /// Starting node. + /// Starting entityView. /// Condition method. /// Selector method. - /// Sequence of selected nodes. - private IEnumerable Traverse(Node node, Func condition, Func selector) + /// Sequence of selected entityViews. + private IEnumerable Traverse(EntityView entityView, Func condition, Func selector) { // Create a stack to avoid recursion - Stack stack = new Stack(); - Node current = node; + Stack stack = new Stack(); + EntityView current = entityView; while (null != current) { if (null != current.Left) @@ -671,7 +671,7 @@ public class LeftLeaningRedBlackTree { for (int i = 0; i <= current.Siblings; i++) { - // Select current node if relevant + // Select current entityView if relevant if (condition(current)) { yield return selector(current); @@ -714,29 +714,29 @@ public class LeftLeaningRedBlackTree private void AssertInvariants() { // Root is black - Debug.Assert((null == _rootNode) || _rootNode.IsBlack, "Root is not black"); - // Every path contains the same number of black nodes - Dictionary parents = new Dictionary.Node, LeftLeaningRedBlackTree.Node>(); - foreach (Node node in Traverse(_rootNode, n => true, n => n)) + Debug.Assert((null == _rootEntityView) || _rootEntityView.IsBlack, "Root is not black"); + // Every path contains the same number of black entityViews + Dictionary parents = new Dictionary.EntityView, LeftLeaningRedBlackTree.EntityView>(); + foreach (EntityView entityView in Traverse(_rootEntityView, n => true, n => n)) { - if (null != node.Left) + if (null != entityView.Left) { - parents[node.Left] = node; + parents[entityView.Left] = entityView; } - if (null != node.Right) + if (null != entityView.Right) { - parents[node.Right] = node; + parents[entityView.Right] = entityView; } } - if (null != _rootNode) + if (null != _rootEntityView) { - parents[_rootNode] = null; + parents[_rootEntityView] = null; } int treeCount = -1; - foreach (Node node in Traverse(_rootNode, n => (null == n.Left) || (null == n.Right), n => n)) + foreach (EntityView entityView in Traverse(_rootEntityView, n => (null == n.Left) || (null == n.Right), n => n)) { int pathCount = 0; - Node current = node; + EntityView current = entityView; while (null != current) { if (current.IsBlack) @@ -745,28 +745,28 @@ public class LeftLeaningRedBlackTree } current = parents[current]; } - Debug.Assert((-1 == treeCount) || (pathCount == treeCount), "Not all paths have the same number of black nodes."); + Debug.Assert((-1 == treeCount) || (pathCount == treeCount), "Not all paths have the same number of black entityViews."); treeCount = pathCount; } - // Verify node properties... - foreach (Node node in Traverse(_rootNode, n => true, n => n)) + // Verify entityView properties... + foreach (EntityView entityView in Traverse(_rootEntityView, n => true, n => n)) { - // Left node is less - if (null != node.Left) + // Left entityView is less + if (null != entityView.Left) { - Debug.Assert(0 > KeyAndValueComparison(node.Left.Key, node.Left.Value, node.Key, node.Value), "Left node is greater than its parent."); + Debug.Assert(0 > KeyAndValueComparison(entityView.Left.Key, entityView.Left.Value, entityView.Key, entityView.Value), "Left entityView is greater than its parent."); } - // Right node is greater - if (null != node.Right) + // Right entityView is greater + if (null != entityView.Right) { - Debug.Assert(0 < KeyAndValueComparison(node.Right.Key, node.Right.Value, node.Key, node.Value), "Right node is less than its parent."); + Debug.Assert(0 < KeyAndValueComparison(entityView.Right.Key, entityView.Right.Value, entityView.Key, entityView.Value), "Right entityView is less than its parent."); } - // Both children of a red node are black - Debug.Assert(!IsRed(node) || (!IsRed(node.Left) && !IsRed(node.Right)), "Red node has a red child."); + // Both children of a red entityView are black + Debug.Assert(!IsRed(entityView) || (!IsRed(entityView.Left) && !IsRed(entityView.Right)), "Red entityView has a red child."); // Always left-leaning - Debug.Assert(!IsRed(node.Right) || IsRed(node.Left), "Node is not left-leaning."); + Debug.Assert(!IsRed(entityView.Right) || IsRed(entityView.Left), "EntityView is not left-leaning."); // No consecutive reds (subset of previous rule) - //Debug.Assert(!(IsRed(node) && IsRed(node.Left))); + //Debug.Assert(!(IsRed(entityView) && IsRed(entityView.Left))); } } @@ -780,7 +780,7 @@ public class LeftLeaningRedBlackTree return "" + "" + - (null != _rootNode ? _rootNode.HtmlFragment : "[null]") + + (null != _rootEntityView ? _rootEntityView.HtmlFragment : "[null]") + "" + ""; } diff --git a/DataStructures/LockFreeQueue.cs b/DataStructures/LockFreeQueue.cs index 4c55f39..4b936be 100644 --- a/DataStructures/LockFreeQueue.cs +++ b/DataStructures/LockFreeQueue.cs @@ -1,14 +1,13 @@ -using System.Collections.Generic; using System.Threading; //from unify wiki namespace Svelto.DataStructures { - public class SingleLinkNode + public class SingleLinkEntityView { // Note; the Next member cannot be a property since // it participates in many CAS operations - public SingleLinkNode Next; + public SingleLinkEntityView Next; public T Item; } @@ -24,33 +23,33 @@ namespace Svelto.DataStructures public class LockFreeLinkPool { - private SingleLinkNode head; + private SingleLinkEntityView head; public LockFreeLinkPool() { - head = new SingleLinkNode(); + head = new SingleLinkEntityView(); } - public void Push(SingleLinkNode newNode) + public void Push(SingleLinkEntityView newEntityView) { - newNode.Item = default(T); + newEntityView.Item = default(T); do { - newNode.Next = head.Next; - } while (!SyncMethods.CAS>(ref head.Next, newNode.Next, newNode)); + newEntityView.Next = head.Next; + } while (!SyncMethods.CAS>(ref head.Next, newEntityView.Next, newEntityView)); return; } - public bool Pop(out SingleLinkNode node) + public bool Pop(out SingleLinkEntityView entityView) { do { - node = head.Next; - if (node == null) + entityView = head.Next; + if (entityView == null) { return false; } - } while (!SyncMethods.CAS>(ref head.Next, node, node.Next)); + } while (!SyncMethods.CAS>(ref head.Next, entityView, entityView.Next)); return true; } } @@ -58,35 +57,35 @@ namespace Svelto.DataStructures public class LockFreeQueue { - SingleLinkNode head; - SingleLinkNode tail; + SingleLinkEntityView head; + SingleLinkEntityView tail; LockFreeLinkPool trash; public LockFreeQueue() { - head = new SingleLinkNode(); + head = new SingleLinkEntityView(); tail = head; trash = new LockFreeLinkPool(); } public void Enqueue(T item) { - SingleLinkNode oldTail = null; - SingleLinkNode oldTailNext; + SingleLinkEntityView oldTail = null; + SingleLinkEntityView oldTailNext; - SingleLinkNode newNode; - if (!trash.Pop(out newNode)) + SingleLinkEntityView newEntityView; + if (!trash.Pop(out newEntityView)) { - newNode = new SingleLinkNode(); + newEntityView = new SingleLinkEntityView(); } else { - newNode.Next = null; + newEntityView.Next = null; } - newNode.Item = item; + newEntityView.Item = item; - bool newNodeWasAdded = false; - while (!newNodeWasAdded) + bool newEntityViewWasAdded = false; + while (!newEntityViewWasAdded) { oldTail = tail; oldTailNext = oldTail.Next; @@ -94,26 +93,26 @@ namespace Svelto.DataStructures if (tail == oldTail) { if (oldTailNext == null) - newNodeWasAdded = SyncMethods.CAS>(ref tail.Next, null, newNode); + newEntityViewWasAdded = SyncMethods.CAS>(ref tail.Next, null, newEntityView); else - SyncMethods.CAS>(ref tail, oldTail, oldTailNext); + SyncMethods.CAS>(ref tail, oldTail, oldTailNext); } } - SyncMethods.CAS>(ref tail, oldTail, newNode); + SyncMethods.CAS>(ref tail, oldTail, newEntityView); } public bool Dequeue(out T item) { item = default(T); - SingleLinkNode oldHead = null; + SingleLinkEntityView oldHead = null; bool haveAdvancedHead = false; while (!haveAdvancedHead) { oldHead = head; - SingleLinkNode oldTail = tail; - SingleLinkNode oldHeadNext = oldHead.Next; + SingleLinkEntityView oldTail = tail; + SingleLinkEntityView oldHeadNext = oldHead.Next; if (oldHead == head) { @@ -123,12 +122,12 @@ namespace Svelto.DataStructures { return false; } - SyncMethods.CAS>(ref tail, oldTail, oldHeadNext); + SyncMethods.CAS>(ref tail, oldTail, oldHeadNext); } else { item = oldHeadNext.Item; - haveAdvancedHead = SyncMethods.CAS>(ref head, oldHead, oldHeadNext); + haveAdvancedHead = SyncMethods.CAS>(ref head, oldHead, oldHeadNext); if (haveAdvancedHead) { trash.Push(oldHead); diff --git a/DataStructures/PriorityQueue/HeapPriorityQueue.cs b/DataStructures/PriorityQueue/HeapPriorityQueue.cs index 606acd5..bd8764b 100644 --- a/DataStructures/PriorityQueue/HeapPriorityQueue.cs +++ b/DataStructures/PriorityQueue/HeapPriorityQueue.cs @@ -1,7 +1,5 @@ using System.Collections; using System.Collections.Generic; -using System.Runtime.CompilerServices; -using Svelto.DataStructures; namespace Svelto.DataStructures { @@ -9,40 +7,40 @@ namespace Svelto.DataStructures /// An implementation of a min-Priority Queue using a heap. Has O(1) .Contains()! /// See https://bitbucket.org/BlueRaja/high-speed-priority-queue-for-c/wiki/Getting%20Started for more information /// - /// The values in the queue. Must implement the PriorityQueueNode interface + /// The values in the queue. Must implement the PriorityQueueEntityView interface public sealed class HeapPriorityQueue : IPriorityQueue - where T : PriorityQueueNode + where T : PriorityQueueEntityView { - private int _numNodes; - private readonly FasterList _nodes; - private long _numNodesEverEnqueued; + private int _numEntityViews; + private readonly FasterList _entityViews; + private long _numEntityViewsEverEnqueued; /// /// Instantiate a new Priority Queue /// - /// The max nodes ever allowed to be enqueued (going over this will cause an exception) + /// The max entityViews ever allowed to be enqueued (going over this will cause an exception) public HeapPriorityQueue() { - _numNodes = 0; - _nodes = new FasterList(); - _numNodesEverEnqueued = 0; + _numEntityViews = 0; + _entityViews = new FasterList(); + _numEntityViewsEverEnqueued = 0; } public HeapPriorityQueue(int initialSize) { - _numNodes = 0; - _nodes = new FasterList(initialSize); - _numNodesEverEnqueued = 0; + _numEntityViews = 0; + _entityViews = new FasterList(initialSize); + _numEntityViewsEverEnqueued = 0; } /// - /// Returns the number of nodes in the queue. O(1) + /// Returns the number of entityViews in the queue. O(1) /// public int Count { get { - return _numNodes; + return _numEntityViews; } } @@ -54,119 +52,119 @@ namespace Svelto.DataStructures { get { - return _nodes.Count - 1; + return _entityViews.Count - 1; } } /// - /// Removes every node from the queue. O(n) (So, don't do this often!) + /// Removes every entityView from the queue. O(n) (So, don't do this often!) /// #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif public void Clear() { - _nodes.FastClear(); + _entityViews.FastClear(); - _numNodes = 0; + _numEntityViews = 0; } /// - /// Returns (in O(1)!) whether the given node is in the queue. O(1) + /// Returns (in O(1)!) whether the given entityView is in the queue. O(1) /// #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - public bool Contains(T node) + public bool Contains(T entityView) { - return (_nodes[node.QueueIndex] == node); + return (_entityViews[entityView.QueueIndex] == entityView); } /// - /// Enqueue a node - .Priority must be set beforehand! O(log n) + /// Enqueue a entityView - .Priority must be set beforehand! O(log n) /// #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - public void Enqueue(T node, double priority) + public void Enqueue(T entityView, double priority) { - node.Priority = priority; - _numNodes++; - if (_nodes.Count < _numNodes) - _nodes.Resize(_numNodes + 1); - - _nodes[_numNodes] = node; - node.QueueIndex = _numNodes; - node.InsertionIndex = _numNodesEverEnqueued++; - CascadeUp(_nodes[_numNodes]); + entityView.Priority = priority; + _numEntityViews++; + if (_entityViews.Count < _numEntityViews) + _entityViews.Resize(_numEntityViews + 1); + + _entityViews[_numEntityViews] = entityView; + entityView.QueueIndex = _numEntityViews; + entityView.InsertionIndex = _numEntityViewsEverEnqueued++; + CascadeUp(_entityViews[_numEntityViews]); } #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - private void Swap(T node1, T node2) + private void Swap(T entityView1, T entityView2) { - //Swap the nodes - _nodes[node1.QueueIndex] = node2; - _nodes[node2.QueueIndex] = node1; + //Swap the entityViews + _entityViews[entityView1.QueueIndex] = entityView2; + _entityViews[entityView2.QueueIndex] = entityView1; //Swap their indicies - int temp = node1.QueueIndex; - node1.QueueIndex = node2.QueueIndex; - node2.QueueIndex = temp; + int temp = entityView1.QueueIndex; + entityView1.QueueIndex = entityView2.QueueIndex; + entityView2.QueueIndex = temp; } //Performance appears to be slightly better when this is NOT inlined o_O - private void CascadeUp(T node) + private void CascadeUp(T entityView) { //aka Heapify-up - int parent = node.QueueIndex / 2; + int parent = entityView.QueueIndex / 2; while(parent >= 1) { - T parentNode = _nodes[parent]; - if(HasHigherPriority(parentNode, node)) + T parentEntityView = _entityViews[parent]; + if(HasHigherPriority(parentEntityView, entityView)) break; - //Node has lower priority value, so move it up the heap - Swap(node, parentNode); //For some reason, this is faster with Swap() rather than (less..?) individual operations, like in CascadeDown() + //EntityView has lower priority value, so move it up the heap + Swap(entityView, parentEntityView); //For some reason, this is faster with Swap() rather than (less..?) individual operations, like in CascadeDown() - parent = node.QueueIndex / 2; + parent = entityView.QueueIndex / 2; } } #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - private void CascadeDown(T node) + private void CascadeDown(T entityView) { //aka Heapify-down T newParent; - int finalQueueIndex = node.QueueIndex; + int finalQueueIndex = entityView.QueueIndex; while(true) { - newParent = node; + newParent = entityView; int childLeftIndex = 2 * finalQueueIndex; - //Check if the left-child is higher-priority than the current node - if(childLeftIndex > _numNodes) + //Check if the left-child is higher-priority than the current entityView + if(childLeftIndex > _numEntityViews) { - //This could be placed outside the loop, but then we'd have to check newParent != node twice - node.QueueIndex = finalQueueIndex; - _nodes[finalQueueIndex] = node; + //This could be placed outside the loop, but then we'd have to check newParent != entityView twice + entityView.QueueIndex = finalQueueIndex; + _entityViews[finalQueueIndex] = entityView; break; } - T childLeft = _nodes[childLeftIndex]; + T childLeft = _entityViews[childLeftIndex]; if(HasHigherPriority(childLeft, newParent)) { newParent = childLeft; } - //Check if the right-child is higher-priority than either the current node or the left child + //Check if the right-child is higher-priority than either the current entityView or the left child int childRightIndex = childLeftIndex + 1; - if(childRightIndex <= _numNodes) + if(childRightIndex <= _numEntityViews) { - T childRight = _nodes[childRightIndex]; + T childRight = _entityViews[childRightIndex]; if(HasHigherPriority(childRight, newParent)) { newParent = childRight; @@ -174,11 +172,11 @@ namespace Svelto.DataStructures } //If either of the children has higher (smaller) priority, swap and continue cascading - if(newParent != node) + if(newParent != entityView) { - //Move new parent to its new index. node will be moved once, at the end + //Move new parent to its new index. entityView will be moved once, at the end //Doing it this way is one less assignment operation than calling Swap() - _nodes[finalQueueIndex] = newParent; + _entityViews[finalQueueIndex] = newParent; int temp = newParent.QueueIndex; newParent.QueueIndex = finalQueueIndex; @@ -187,8 +185,8 @@ namespace Svelto.DataStructures else { //See note above - node.QueueIndex = finalQueueIndex; - _nodes[finalQueueIndex] = node; + entityView.QueueIndex = finalQueueIndex; + _entityViews[finalQueueIndex] = entityView; break; } } @@ -196,7 +194,7 @@ namespace Svelto.DataStructures /// /// Returns true if 'higher' has higher priority than 'lower', false otherwise. - /// Note that calling HasHigherPriority(node, node) (ie. both arguments the same node) will return false + /// Note that calling HasHigherPriority(entityView, entityView) (ie. both arguments the same entityView) will return false /// #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -208,11 +206,11 @@ namespace Svelto.DataStructures } /// - /// Removes the head of the queue (node with highest priority; ties are broken by order of insertion), and returns it. O(log n) + /// Removes the head of the queue (entityView with highest priority; ties are broken by order of insertion), and returns it. O(log n) /// public T Dequeue() { - T returnMe = _nodes[1]; + T returnMe = _entityViews[1]; Remove(returnMe); return returnMe; } @@ -224,77 +222,77 @@ namespace Svelto.DataStructures { get { - return _nodes[1]; + return _entityViews[1]; } } /// - /// This method must be called on a node every time its priority changes while it is in the queue. + /// This method must be called on a entityView every time its priority changes while it is in the queue. /// Forgetting to call this method will result in a corrupted queue! /// O(log n) /// #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - public void UpdatePriority(T node, double priority) + public void UpdatePriority(T entityView, double priority) { - node.Priority = priority; - OnNodeUpdated(node); + entityView.Priority = priority; + OnEntityViewUpdated(entityView); } - private void OnNodeUpdated(T node) + private void OnEntityViewUpdated(T entityView) { - //Bubble the updated node up or down as appropriate - int parentIndex = node.QueueIndex / 2; - T parentNode = _nodes[parentIndex]; + //Bubble the updated entityView up or down as appropriate + int parentIndex = entityView.QueueIndex / 2; + T parentEntityView = _entityViews[parentIndex]; - if(parentIndex > 0 && HasHigherPriority(node, parentNode)) + if(parentIndex > 0 && HasHigherPriority(entityView, parentEntityView)) { - CascadeUp(node); + CascadeUp(entityView); } else { - //Note that CascadeDown will be called if parentNode == node (that is, node is the root) - CascadeDown(node); + //Note that CascadeDown will be called if parentEntityView == entityView (that is, entityView is the root) + CascadeDown(entityView); } } /// - /// Removes a node from the queue. Note that the node does not need to be the head of the queue. O(log n) + /// Removes a entityView from the queue. Note that the entityView does not need to be the head of the queue. O(log n) /// - public void Remove(T node) + public void Remove(T entityView) { - if(_numNodes <= 1) + if(_numEntityViews <= 1) { - _nodes[1] = null; - _numNodes = 0; + _entityViews[1] = null; + _numEntityViews = 0; return; } - //Make sure the node is the last node in the queue + //Make sure the entityView is the last entityView in the queue bool wasSwapped = false; - T formerLastNode = _nodes[_numNodes]; - if(node.QueueIndex != _numNodes) + T formerLastEntityView = _entityViews[_numEntityViews]; + if(entityView.QueueIndex != _numEntityViews) { - //Swap the node with the last node - Swap(node, formerLastNode); + //Swap the entityView with the last entityView + Swap(entityView, formerLastEntityView); wasSwapped = true; } - _numNodes--; - _nodes[node.QueueIndex] = null; + _numEntityViews--; + _entityViews[entityView.QueueIndex] = null; if(wasSwapped) { - //Now bubble formerLastNode (which is no longer the last node) up or down as appropriate - OnNodeUpdated(formerLastNode); + //Now bubble formerLastEntityView (which is no longer the last entityView) up or down as appropriate + OnEntityViewUpdated(formerLastEntityView); } } public IEnumerator GetEnumerator() { - for(int i = 1; i <= _numNodes; i++) - yield return _nodes[i]; + for(int i = 1; i <= _numEntityViews; i++) + yield return _entityViews[i]; } IEnumerator IEnumerable.GetEnumerator() @@ -308,16 +306,16 @@ namespace Svelto.DataStructures /// public bool IsValidQueue() { - for(int i = 1; i < _nodes.Count; i++) + for(int i = 1; i < _entityViews.Count; i++) { - if(_nodes[i] != null) + if(_entityViews[i] != null) { int childLeftIndex = 2 * i; - if(childLeftIndex < _nodes.Count && _nodes[childLeftIndex] != null && HasHigherPriority(_nodes[childLeftIndex], _nodes[i])) + if(childLeftIndex < _entityViews.Count && _entityViews[childLeftIndex] != null && HasHigherPriority(_entityViews[childLeftIndex], _entityViews[i])) return false; int childRightIndex = childLeftIndex + 1; - if(childRightIndex < _nodes.Count && _nodes[childRightIndex] != null && HasHigherPriority(_nodes[childRightIndex], _nodes[i])) + if(childRightIndex < _entityViews.Count && _entityViews[childRightIndex] != null && HasHigherPriority(_entityViews[childRightIndex], _entityViews[i])) return false; } } diff --git a/DataStructures/PriorityQueue/IPriorityQueue.cs b/DataStructures/PriorityQueue/IPriorityQueue.cs index 632820e..58997ff 100644 --- a/DataStructures/PriorityQueue/IPriorityQueue.cs +++ b/DataStructures/PriorityQueue/IPriorityQueue.cs @@ -8,16 +8,16 @@ namespace Svelto.DataStructures /// (theoretically?) optimize method calls from concrete-types slightly better. /// public interface IPriorityQueue : IEnumerable - where T : PriorityQueueNode + where T : PriorityQueueEntityView { - void Remove(T node); - void UpdatePriority(T node, double priority); - void Enqueue(T node, double priority); + void Remove(T entityView); + void UpdatePriority(T entityView, double priority); + void Enqueue(T entityView, double priority); T Dequeue(); T First { get; } int Count { get; } int MaxSize { get; } void Clear(); - bool Contains(T node); + bool Contains(T entityView); } } diff --git a/DataStructures/PriorityQueue/PriorityQueueNode.cs b/DataStructures/PriorityQueue/PriorityQueueNode.cs index b09f3a4..48c5491 100644 --- a/DataStructures/PriorityQueue/PriorityQueueNode.cs +++ b/DataStructures/PriorityQueue/PriorityQueueNode.cs @@ -1,9 +1,9 @@ namespace Svelto.DataStructures { - public class PriorityQueueNode + public class PriorityQueueEntityView { /// - /// The Priority to insert this node at. Must be set BEFORE adding a node to the queue + /// The Priority to insert this entityView at. Must be set BEFORE adding a entityView to the queue /// public double Priority { get; set; @@ -11,7 +11,7 @@ /// /// Used by the priority queue - do not edit this value. - /// Represents the order the node was inserted in + /// Represents the order the entityView was inserted in /// public long InsertionIndex { get; set; } diff --git a/ECS/DataStructures/TypeSafeDictionary.cs b/ECS/DataStructures/TypeSafeDictionary.cs index e399ba1..c7cdc14 100644 --- a/ECS/DataStructures/TypeSafeDictionary.cs +++ b/ECS/DataStructures/TypeSafeDictionary.cs @@ -1,6 +1,5 @@ using Svelto.DataStructures; using System.Collections.Generic; -using Svelto.ECS.Internal; namespace Svelto.ECS.Internal { @@ -14,35 +13,37 @@ namespace Svelto.ECS.Internal public interface ITypeSafeDictionary { - void FillWithIndexedNodes(ITypeSafeList nodes); - void Remove(int entityId); - NodeWithID GetIndexedNode(int entityID); + void FillWithIndexedEntityViews(ITypeSafeList entityViews); + bool Remove(int entityId); + IEntityView GetIndexedEntityView(int entityID); } - class TypeSafeDictionary : Dictionary, ITypeSafeDictionary where TValue:NodeWithID + class TypeSafeDictionary : Dictionary, ITypeSafeDictionary where TValue:IEntityView { internal static readonly ReadOnlyDictionary Default = new ReadOnlyDictionary(new Dictionary()); - public void FillWithIndexedNodes(ITypeSafeList nodes) + public void FillWithIndexedEntityViews(ITypeSafeList entityViews) { int count; - var buffer = FasterList.NoVirt.ToArrayFast((FasterList) nodes, out count); + var buffer = FasterList.NoVirt.ToArrayFast((FasterList) entityViews, out count); for (int i = 0; i < count; i++) { - var node = buffer[i]; + var entityView = buffer[i]; - Add(node.ID, node); + Add(entityView.ID, entityView); } } - public void Remove(int entityId) + new public bool Remove(int entityId) { - throw new System.NotImplementedException(); + base.Remove(entityId); + + return this.Count > 0; } - public NodeWithID GetIndexedNode(int entityID) + public IEntityView GetIndexedEntityView(int entityID) { return this[entityID]; } diff --git a/ECS/DataStructures/TypeSafeFasterListForECS.cs b/ECS/DataStructures/TypeSafeFasterListForECS.cs index e6e47a3..6241937 100644 --- a/ECS/DataStructures/TypeSafeFasterListForECS.cs +++ b/ECS/DataStructures/TypeSafeFasterListForECS.cs @@ -7,51 +7,57 @@ namespace Svelto.ECS.Internal { public interface ITypeSafeList: IEnumerable { - void AddRange(ITypeSafeList nodeListValue); + void AddRange(ITypeSafeList entityViewListValue); ITypeSafeList Create(); - bool isQueryiableNode { get; } - void UnorderedRemove(int index); + bool isQueryiableEntityView { get; } + bool UnorderedRemove(int entityID); ITypeSafeDictionary CreateIndexedDictionary(); + IEntityView[] ToArrayFast(out int count); } - class TypeSafeFasterListForECS: FasterList where T:INode + class TypeSafeFasterListForECS: FasterList where T:IEntityView { protected TypeSafeFasterListForECS() { _mappedIndices = new Dictionary(); } - public void UnorderedRemove(int mappedIndex) + public bool UnorderedRemove(int entityID) { - var index = _mappedIndices[mappedIndex]; - _mappedIndices.Remove(mappedIndex); + var index = _mappedIndices[entityID]; + + DesignByContract.Check.Assert(entityID == this[index].ID, "Something went wrong with the Svelto.ECS code, please contact the author"); + + _mappedIndices.Remove(entityID); if (UnorderedRemoveAt(index)) _mappedIndices[this[index].ID] = index; + + return this.Count > 0; } - public void AddRange(ITypeSafeList nodeListValue) + public void AddRange(ITypeSafeList entityViewListValue) { var index = this.Count; - AddRange(nodeListValue as FasterList); + AddRange(entityViewListValue as FasterList); for (int i = index; i < Count; ++i) - _mappedIndices[this[i].ID] = this.Count; + _mappedIndices[this[i].ID] = i; } readonly Dictionary _mappedIndices; } - class TypeSafeFasterListForECSForStructs : TypeSafeFasterListForECS, ITypeSafeList where T:struct, INode + class TypeSafeFasterListForECSForStructs : TypeSafeFasterListForECS, ITypeSafeList where T:struct, IEntityStruct { public ITypeSafeList Create() { return new TypeSafeFasterListForECSForStructs(); } - public bool isQueryiableNode + public bool isQueryiableEntityView { get { return false; } } @@ -60,16 +66,21 @@ namespace Svelto.ECS.Internal { throw new Exception("Not Allowed"); } + + public IEntityView[] ToArrayFast(out int count) + { + throw new Exception("Not Allowed"); + } } - class TypeSafeFasterListForECSForClasses : TypeSafeFasterListForECS, ITypeSafeList where T:NodeWithID + class TypeSafeFasterListForECSForClasses : TypeSafeFasterListForECS, ITypeSafeList where T:EntityView, new() { public ITypeSafeList Create() { return new TypeSafeFasterListForECSForClasses(); } - public bool isQueryiableNode + public bool isQueryiableEntityView { get { return true; } } @@ -78,5 +89,12 @@ namespace Svelto.ECS.Internal { return new TypeSafeDictionary(); } + + public IEntityView[] ToArrayFast(out int count) + { + count = this.Count; + + return this.ToArrayFast(); + } } } diff --git a/ECS/EngineNodeDB.cs b/ECS/EngineNodeDB.cs index 126dd46..103275f 100644 --- a/ECS/EngineNodeDB.cs +++ b/ECS/EngineNodeDB.cs @@ -5,137 +5,164 @@ using Svelto.ECS.Internal; namespace Svelto.ECS { - public class EngineNodeDB : IEngineNodeDB + public class EngineEntityViewDB : IEngineEntityViewDB { - internal EngineNodeDB( Dictionary nodesDB, - Dictionary nodesDBdic, - Dictionary metaNodesDB, - Dictionary> groupNodesDB) + internal EngineEntityViewDB( Dictionary entityViewsDB, + Dictionary entityViewsDBdic, + Dictionary metaEntityViewsDB, + Dictionary> groupEntityViewsDB) { - _nodesDB = nodesDB; - _nodesDBdic = nodesDBdic; - _metaNodesDB = metaNodesDB; - _groupNodesDB = groupNodesDB; + _entityViewsDB = entityViewsDB; + _entityViewsDBdic = entityViewsDBdic; + _metaEntityViewsDB = metaEntityViewsDB; + _groupEntityViewsDB = groupEntityViewsDB; } - public FasterReadOnlyList QueryNodes() + public FasterReadOnlyList QueryEntityViews() where T:EntityView, new() { var type = typeof(T); - ITypeSafeList nodes; + ITypeSafeList entityViews; - if (_nodesDB.TryGetValue(type, out nodes) == false) - return RetrieveEmptyNodeList(); + if (_entityViewsDB.TryGetValue(type, out entityViews) == false) + return RetrieveEmptyEntityViewList(); - return new FasterReadOnlyList((FasterList)nodes); + return new FasterReadOnlyList((FasterList)entityViews); } - public FasterReadOnlyList QueryGroupedNodes(int @group) + public FasterReadOnlyList QueryGroupedEntityViews(int @group) where T:EntityView, new() { - return new FasterReadOnlyList(_groupNodesDB[group] as FasterList); + Dictionary entityViews; + + if (_groupEntityViewsDB.TryGetValue(group, out entityViews) == false) + return RetrieveEmptyEntityViewList(); + + return new FasterReadOnlyList(entityViews as FasterList); } - public T[] QueryNodesAsArray(out int count) where T : struct + public T[] QueryEntityViewsAsArray(out int count) where T : IEntityView { var type = typeof(T); count = 0; - ITypeSafeList nodes; + ITypeSafeList entityViews; - if (_nodesDB.TryGetValue(type, out nodes) == false) - return null; + if (_entityViewsDB.TryGetValue(type, out entityViews) == false) + return RetrieveEmptyEntityViewArray(); - var castedNodes = (FasterList)nodes; + var castedEntityViews = (FasterList)entityViews; - count = castedNodes.Count; + count = castedEntityViews.Count; - return castedNodes.ToArrayFast(); + return castedEntityViews.ToArrayFast(); } - - public ReadOnlyDictionary QueryIndexableNodes() where T:NodeWithID + + public T[] QueryGroupedEntityViewsAsArray(int @group, out int count) where T : IEntityView { var type = typeof(T); + count = 0; + + Dictionary entityViews; + + if (_groupEntityViewsDB.TryGetValue(group, out entityViews) == false) + return RetrieveEmptyEntityViewArray(); + + var castedEntityViews = (FasterList)entityViews[type]; - ITypeSafeDictionary nodes; - - if (_nodesDBdic.TryGetValue(type, out nodes) == false) - return TypeSafeDictionary.Default; - - return new ReadOnlyDictionary(nodes as Dictionary); - } - - public T QueryMetaNode(int metaEntityID) where T:NodeWithID - { - return QueryNode(metaEntityID); - } + count = castedEntityViews.Count; - public bool TryQueryMetaNode(int metaEntityID, out T node) where T:NodeWithID - { - return TryQueryNode(metaEntityID, out node); + return castedEntityViews.ToArrayFast(); } - public FasterReadOnlyList QueryMetaNodes() + public ReadOnlyDictionary QueryIndexableEntityViews() where T:IEntityView { var type = typeof(T); - ITypeSafeList nodes; + ITypeSafeDictionary entityViews; - if (_metaNodesDB.TryGetValue(type, out nodes) == false) - return RetrieveEmptyNodeList(); + if (_entityViewsDBdic.TryGetValue(type, out entityViews) == false) + return TypeSafeDictionary.Default; - return new FasterReadOnlyList((FasterList)nodes); + return new ReadOnlyDictionary(entityViews as Dictionary); } - public bool TryQueryNode(int ID, out T node) where T:NodeWithID + public bool TryQueryEntityView(int ID, out T entityView) where T : IEntityView { var type = typeof(T); - T internalNode; + T internalEntityView; - ITypeSafeDictionary nodes; + ITypeSafeDictionary entityViews; TypeSafeDictionary casted; - _nodesDBdic.TryGetValue(type, out nodes); - casted = nodes as TypeSafeDictionary; + _entityViewsDBdic.TryGetValue(type, out entityViews); + casted = entityViews as TypeSafeDictionary; if (casted != null && - casted.TryGetValue(ID, out internalNode)) + casted.TryGetValue(ID, out internalEntityView)) { - node = (T) internalNode; + entityView = (T)internalEntityView; return true; } - - node = default(T); + + entityView = default(T); return false; } - public T QueryNode(int ID) where T:NodeWithID + public T QueryEntityView(int ID) where T : IEntityView { var type = typeof(T); - T internalNode; ITypeSafeDictionary nodes; + T internalEntityView; ITypeSafeDictionary entityViews; TypeSafeDictionary casted; - _nodesDBdic.TryGetValue(type, out nodes); - casted = nodes as TypeSafeDictionary; + _entityViewsDBdic.TryGetValue(type, out entityViews); + casted = entityViews as TypeSafeDictionary; if (casted != null && - casted.TryGetValue(ID, out internalNode)) - return (T)internalNode; + casted.TryGetValue(ID, out internalEntityView)) + return (T)internalEntityView; - throw new Exception("Node Not Found"); + throw new Exception("EntityView Not Found"); } - static FasterReadOnlyList RetrieveEmptyNodeList() + public T QueryMetaEntityView(int metaEntityID) where T:EntityView, new() + { + return QueryEntityView(metaEntityID); + } + + public bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T:EntityView, new() + { + return TryQueryEntityView(metaEntityID, out entityView); + } + + public FasterReadOnlyList QueryMetaEntityViews() where T:EntityView, new() + { + var type = typeof(T); + + ITypeSafeList entityViews; + + if (_metaEntityViewsDB.TryGetValue(type, out entityViews) == false) + return RetrieveEmptyEntityViewList(); + + return new FasterReadOnlyList((FasterList)entityViews); + } + + static FasterReadOnlyList RetrieveEmptyEntityViewList() { return FasterReadOnlyList.DefaultList; } - readonly Dictionary _nodesDB; - readonly Dictionary _nodesDBdic; - readonly Dictionary _metaNodesDB; - readonly Dictionary> _groupNodesDB; + static T[] RetrieveEmptyEntityViewArray() + { + return FasterList.DefaultList.ToArrayFast(); + } + + readonly Dictionary _entityViewsDB; + readonly Dictionary _entityViewsDBdic; + readonly Dictionary _metaEntityViewsDB; + readonly Dictionary> _groupEntityViewsDB; } } diff --git a/ECS/EnginesRoot.cs b/ECS/EnginesRoot.cs index 7602238..882e57b 100644 --- a/ECS/EnginesRoot.cs +++ b/ECS/EnginesRoot.cs @@ -1,167 +1,200 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Linq; using Svelto.DataStructures; using Svelto.ECS.Internal; -using Svelto.ECS.Legacy; -using Svelto.ECS.NodeSchedulers; -using Svelto.ECS.Profiler; +using Svelto.ECS.Schedulers; using Svelto.Utilities; +using Svelto.WeakEvents; + +#if EXPERIMENTAL +using Svelto.ECS.Experimental; +using Svelto.ECS.Experimental.Internal; +#endif #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR using Svelto.ECS.Profiler; #endif -namespace Svelto.ECS.Internal -{ - struct BuildNodeCallbackStruct - { - public Action, int> internalRemove; - public Action, int> internalEnable; - public Action, int> internalDisable; - } -} - namespace Svelto.ECS { - public sealed class EnginesRoot : IEnginesRoot, IEntityFactory + public sealed class EnginesRoot : IEntityFunctions, IEntityFactory, IDisposable { - public EnginesRoot(NodeSubmissionScheduler nodeScheduler) + public EnginesRoot(EntityViewSubmissionScheduler entityViewScheduler) { - _nodeEngines = new Dictionary>(); - _activableEngines = new Dictionary>(); + _entityViewEngines = new Dictionary>(); _otherEngines = new FasterList(); - _engineRootWeakReference = new DataStructures.WeakReference(this); - - _nodesDB = new Dictionary(); - _metaNodesDB = new Dictionary(); - _groupNodesDB = new Dictionary>(); - _nodesDBdic = new Dictionary(); - - _sharedStructNodeLists = new SharedStructNodeLists(); - _sharedGroupedStructNodeLists = new SharedGroupedStructNodesLists(); - - _nodesToAdd = new DoubleBufferedNodes>(); - _metaNodesToAdd = new DoubleBufferedNodes>(); - _groupedNodesToAdd = new DoubleBufferedNodes>>(); - - _callBackStructForBuiltGroupedNodes = new BuildNodeCallbackStruct(); - - _callBackStructForBuiltGroupedNodes.internalRemove = InternalRemove; - _callBackStructForBuiltGroupedNodes.internalDisable = InternalDisable; - _callBackStructForBuiltGroupedNodes.internalEnable = InternalEnable; + _entityViewsDB = new Dictionary(); + _metaEntityViewsDB = new Dictionary(); + _groupEntityViewsDB = new Dictionary>(); + _entityViewsDBdic = new Dictionary(); - _callBackStructForBuiltNodes = new BuildNodeCallbackStruct(); - - _callBackStructForBuiltNodes.internalRemove = InternalGroupedRemove; - _callBackStructForBuiltNodes.internalDisable = InternalDisable; - _callBackStructForBuiltNodes.internalEnable = InternalEnable; - - _callBackStructForBuiltMetaNodes = new BuildNodeCallbackStruct(); - - _callBackStructForBuiltMetaNodes.internalRemove = InternalMetaRemove; - _callBackStructForBuiltMetaNodes.internalDisable = InternalDisable; - _callBackStructForBuiltMetaNodes.internalEnable = InternalEnable; - - _scheduler = nodeScheduler; - _scheduler.Schedule(SubmitNodes); - - _structNodeEngineType = typeof(IStructNodeEngine<>); - _groupedStructNodesEngineType = typeof(IGroupedStructNodesEngine<>); - _activableNodeEngineType = typeof(IActivableNodeEngine<>); + _entityViewsToAdd = new DoubleBufferedEntityViews>(); + _metaEntityViewsToAdd = new DoubleBufferedEntityViews>(); + _groupedEntityViewsToAdd = new DoubleBufferedEntityViews>>(); +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + _addEntityViewToEngine = AddEntityViewToEngine; + _removeEntityViewFromEngine = RemoveEntityViewFromEngine; +#endif + _engineEntityViewDB = new EngineEntityViewDB(_entityViewsDB, _entityViewsDBdic, _metaEntityViewsDB, _groupEntityViewsDB); + + _scheduler = entityViewScheduler; + _scheduler.Schedule(new WeakAction(SubmitEntityViews)); +#if EXPERIMENTAL + _sharedStructEntityViewLists = new SharedStructEntityViewLists(); + _sharedGroupedStructEntityViewLists = new SharedGroupedStructEntityViewsLists(); + + _structEntityViewEngineType = typeof(IStructEntityViewEngine<>); + _groupedStructEntityViewsEngineType = typeof(IGroupedStructEntityViewsEngine<>); _implementedInterfaceTypes = new Dictionary(); - -#if UNITY_EDITOR +#endif +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); debugEngineObject.gameObject.AddComponent(); #endif } - public void BuildEntity(int ID, EntityDescriptor ed) + public IEntityFactory GenerateEntityFactory() + { + return new GenericEntityFactory(new DataStructures.WeakReference(this)); + } + + public IEntityFunctions GenerateEntityFunctions() { - ed.BuildNodes(ID, _nodesToAdd.other, ref _callBackStructForBuiltNodes); + return new GenericEntityFunctions(new DataStructures.WeakReference(this)); + } + + public void BuildEntity(int entityID, object[] implementors = null) where T:IEntityDescriptor, new() + { + EntityFactory.BuildEntityViews + (entityID, _entityViewsToAdd.current, EntityDescriptorTemplate.Default, implementors); + } + + public void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) + { + EntityFactory.BuildEntityViews + (entityID, _entityViewsToAdd.current, entityDescriptor, implementors); } /// /// A meta entity is a way to manage a set of entitites that are not easily /// queriable otherwise. For example you may want to group existing entities - /// by size and type and then use the meta entity node to manage the data + /// by size and type and then use the meta entity entityView to manage the data /// shared among the single entities of the same type and size. This will /// prevent the scenario where the coder is forced to parse all the entities to /// find the ones of the same size and type. - /// Since the entities are managed through the shared node, the same - /// shared node must be found on the single entities of the same type and size. - /// The shared node of the meta entity is then used by engines that are meant - /// to manage a group of entities through a single node. - /// The same engine can manage several meta entities nodes too. - /// The Engine manages the logic of the Meta Node data and other engines - /// can read back this data through the normal entity as the shared node + /// Since the entities are managed through the shared entityView, the same + /// shared entityView must be found on the single entities of the same type and size. + /// The shared entityView of the meta entity is then used by engines that are meant + /// to manage a group of entities through a single entityView. + /// The same engine can manage several meta entities entityViews too. + /// The Engine manages the logic of the Meta EntityView data and other engines + /// can read back this data through the normal entity as the shared entityView /// will be present in their descriptor too. - /// It's a way to control a group of Entities through a node only. - /// This set of entities can share exactly the same node reference if + /// It's a way to control a group of Entities through a entityView only. + /// This set of entities can share exactly the same entityView reference if /// built through this function. In this way, if you need to set a variable - /// on a group of entities, instead to inject N nodes and iterate over - /// them to set the same value, you can inject just one node, set the value + /// on a group of entities, instead to inject N entityViews and iterate over + /// them to set the same value, you can inject just one entityView, set the value /// and be sure that the value is shared between entities. /// /// /// - public void BuildMetaEntity(int metaEntityID, EntityDescriptor ed) + /// + public void BuildMetaEntity(int metaEntityID, object[] implementors) where T:IEntityDescriptor, new() { - ed.BuildNodes(metaEntityID, _metaNodesToAdd.other, ref _callBackStructForBuiltMetaNodes); + EntityFactory.BuildEntityViews(metaEntityID, _entityViewsToAdd.current, + EntityDescriptorTemplate.Default, implementors); } /// - /// Using this function is like building a normal entity, but the nodes + /// Using this function is like building a normal entity, but the entityViews /// are grouped by groupID to be better processed inside engines and - /// improve cache locality. Only IGroupStructNodeWithID nodes are grouped - /// other nodes are managed as usual. + /// improve cache locality. Only IGroupStructEntityViewWithID entityViews are grouped + /// other entityViews are managed as usual. /// /// /// /// - public void BuildEntityInGroup(int entityID, int groupID, - EntityDescriptor ed) + /// + public void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T:IEntityDescriptor, new() { - ed.BuildGroupedNodes(entityID, groupID, _groupedNodesToAdd.other, ref _callBackStructForBuiltGroupedNodes); + EntityFactory.BuildGroupedEntityViews(entityID, groupID, + _groupedEntityViewsToAdd.current, + EntityDescriptorTemplate.Default, + implementors); } - public void AddEngine(IEngine engine) + public void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) { -#if UNITY_EDITOR - EngineProfiler.AddEngine(engine); -#endif - var queryableNodeEngine = engine as IQueryableNodeEngine; - if (queryableNodeEngine != null) - queryableNodeEngine.nodesDB = - new EngineNodeDB(_nodesDB, _nodesDBdic, _metaNodesDB, _groupNodesDB); + EntityFactory.BuildGroupedEntityViews(entityID, groupID, + _groupedEntityViewsToAdd.current, + entityDescriptor, implementors); + } - var engineType = engine.GetType(); - var implementedInterfaces = engineType.GetInterfaces(); + public void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) + { + var removeEntityImplementor = removeInfo as RemoveEntityImplementor; - CollectImplementedInterfaces(implementedInterfaces); + if (removeEntityImplementor.removeEntityInfo.isInAGroup) + InternalRemove(removeEntityImplementor.removeEntityInfo.descriptor.entityViewsToBuild, entityID, removeEntityImplementor.removeEntityInfo.groupID, _entityViewsDB); + else + InternalRemove(removeEntityImplementor.removeEntityInfo.descriptor.entityViewsToBuild, entityID, _entityViewsDB); + } - var engineAdded = CheckGenericEngines(engine); + public void RemoveEntity(int entityID) where T : IEntityDescriptor, new() + { + InternalRemove(EntityDescriptorTemplate.Default.descriptor.entityViewsToBuild, entityID, _entityViewsDB); + } - if (CheckLegacyNodesEngine(engine, ref engineAdded) == false) - CheckNodesEngine(engine, engineType, ref engineAdded); + public void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() + { + InternalRemove(EntityDescriptorTemplate.Default.descriptor.entityViewsToBuild, metaEntityID, _metaEntityViewsDB); + } - if (engineAdded == false) + public void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() + { + InternalRemove(EntityDescriptorTemplate.Default.descriptor.entityViewsToBuild, entityID, _groupEntityViewsDB[groupID]); + } + + public void AddEngine(IEngine engine) + { +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + Profiler.EngineProfiler.AddEngine(engine); +#endif + var engineType = engine.GetType(); +#if EXPERIMENTAL + bool engineAdded; + + var implementedInterfaces = engineType.GetInterfaces(); + + CollectImplementedInterfaces(implementedInterfaces); + + engineAdded = CheckSpecialEngine(engine); +#endif + var viewEngine = engine as IHandleEntityViewEngine; + + if (viewEngine != null) + CheckEntityViewsEngine(viewEngine, engineType); + else _otherEngines.Add(engine); - - var callBackOnAddEngine = engine as ICallBackOnAddEngine; - if (callBackOnAddEngine != null) - callBackOnAddEngine.Ready(); + + var queryableEntityViewEngine = engine as IQueryingEntityViewEngine; + if (queryableEntityViewEngine != null) + { + queryableEntityViewEngine.entityViewsDB = _engineEntityViewDB; + queryableEntityViewEngine.Ready(); + } } - - void CollectImplementedInterfaces(Type[] implementedInterfaces) + +#if EXPERIMENTAL + void CollectImplementedInterfaces(Type[] implementedInterfaces) { _implementedInterfaceTypes.Clear(); - var type = typeof(IEngine); + var type = typeof(IHandleEntityViewEngine); for (int index = 0; index < implementedInterfaces.Length; index++) { @@ -180,81 +213,60 @@ namespace Svelto.ECS _implementedInterfaceTypes.Add(genericTypeDefinition, interfaceType.GetGenericArguments()); } } - - bool CheckGenericEngines(IEngine engine) + + bool CheckSpecialEngine(IEngine engine) { if (_implementedInterfaceTypes.Count == 0) return false; bool engineAdded = false; - if (_implementedInterfaceTypes.ContainsKey(_structNodeEngineType)) - { - ((IStructNodeEngine)engine).CreateStructNodes - (_sharedStructNodeLists); - } - - if (_implementedInterfaceTypes.ContainsKey(_groupedStructNodesEngineType)) + if (_implementedInterfaceTypes.ContainsKey(_structEntityViewEngineType)) { - ((IGroupedStructNodesEngine)engine).CreateStructNodes - (_sharedGroupedStructNodeLists); + ((IStructEntityViewEngine)engine).CreateStructEntityViews + (_sharedStructEntityViewLists); } - Type[] arguments; - if (_implementedInterfaceTypes.TryGetValue(_activableNodeEngineType, - out arguments)) + if (_implementedInterfaceTypes.ContainsKey(_groupedStructEntityViewsEngineType)) { - AddEngine(engine, arguments, _activableEngines); - - engineAdded = true; + ((IGroupedStructEntityViewsEngine)engine).CreateStructEntityViews + (_sharedGroupedStructEntityViewLists); } return engineAdded; } - - bool CheckLegacyNodesEngine(IEngine engine, ref bool engineAdded) - { - var nodesEngine = engine as INodesEngine; - if (nodesEngine != null) - { - AddEngine(nodesEngine, nodesEngine.AcceptedNodes(), _nodeEngines); - - engineAdded = true; - - return true; - } - - return false; - } - - bool CheckNodesEngine(IEngine engine, Type engineType, ref bool engineAdded) +#endif + void CheckEntityViewsEngine(IEngine engine, Type engineType) { var baseType = engineType.GetBaseType(); - - if (baseType.IsGenericTypeEx() - && engine is INodeEngine) - { - AddEngine(engine as INodeEngine, baseType.GetGenericArguments(), _nodeEngines); - engineAdded = true; + if (baseType.IsGenericTypeEx()) + { + var genericArguments = baseType.GetGenericArguments(); + AddEngine(engine as IHandleEntityViewEngine, genericArguments, _entityViewEngines); +#if EXPERIMENTAL + var activableEngine = engine as IHandleActivableEntityEngine; + if (activableEngine != null) + AddEngine(activableEngine, genericArguments, _activableViewEntitiesEngines); +#endif - return true; + return; } - return false; + throw new Exception("Not Supported Engine"); } - static void AddEngine(IEngine engine, Type[] types, - Dictionary> engines) + static void AddEngine(T engine, Type[] types, + Dictionary> engines) { for (int i = 0; i < types.Length; i++) { - FasterList list; + FasterList list; var type = types[i]; if (engines.TryGetValue(type, out list) == false) { - list = new FasterList(); + list = new FasterList(); engines.Add(type, list); } @@ -263,309 +275,362 @@ namespace Svelto.ECS } } - static void AddNodesToTheDBAndSuitableEngines(Dictionary nodesToAdd, - Dictionary> nodeEngines, - Dictionary nodesDBdic, - Dictionary nodesDB) + void AddEntityViewsToTheDBAndSuitableEngines(Dictionary entityViewsToAdd, + Dictionary entityViewsDB) { - foreach (var nodeList in nodesToAdd) + foreach (var entityViewList in entityViewsToAdd) { - AddNodeToDB(nodesDB, nodeList); + AddEntityViewToDB(entityViewsDB, entityViewList); + + if (entityViewList.Value.isQueryiableEntityView) + { + AddEntityViewToEntityViewsDictionary(_entityViewsDBdic, entityViewList.Value, entityViewList.Key); + } + } - if (nodeList.Value.isQueryiableNode) + foreach (var entityViewList in entityViewsToAdd) + { + if (entityViewList.Value.isQueryiableEntityView) { - AddNodeToNodesDictionary(nodesDBdic, nodeList.Value, nodeList.Key); - - foreach (var node in nodeList.Value) - AddNodeToTheSuitableEngines(nodeEngines, node as NodeWithID, nodeList.Key); + AddEntityViewToTheSuitableEngines(_entityViewEngines, entityViewList.Value, + entityViewList.Key); } } } - static void AddGroupNodesToTheDBAndSuitableEngines(Dictionary> groupedNodesToAdd, - Dictionary> nodeEngines, - Dictionary nodesDBdic, - Dictionary> groupNodesDB, - Dictionary nodesDB) + void AddGroupEntityViewsToTheDBAndSuitableEngines(Dictionary> groupedEntityViewsToAdd, + Dictionary> groupEntityViewsDB, + Dictionary entityViewsDB) { - foreach (var group in groupedNodesToAdd) + foreach (var group in groupedEntityViewsToAdd) { - AddNodesToTheDBAndSuitableEngines(group.Value, nodeEngines, nodesDBdic, nodesDB); + AddEntityViewsToTheDBAndSuitableEngines(group.Value, entityViewsDB); - AddNodesToGroupDB(groupNodesDB, @group); + AddEntityViewsToGroupDB(groupEntityViewsDB, @group); } } - static void AddNodesToGroupDB(Dictionary> groupNodesDB, + static void AddEntityViewsToGroupDB(Dictionary> groupEntityViewsDB, KeyValuePair> @group) { - Dictionary groupedNodesByType; + Dictionary groupedEntityViewsByType; - if (groupNodesDB.TryGetValue(@group.Key, out groupedNodesByType) == false) - groupedNodesByType = groupNodesDB[@group.Key] = new Dictionary(); + if (groupEntityViewsDB.TryGetValue(@group.Key, out groupedEntityViewsByType) == false) + groupedEntityViewsByType = groupEntityViewsDB[@group.Key] = new Dictionary(); - foreach (var node in @group.Value) + foreach (var entityView in @group.Value) { - groupedNodesByType.Add(node.Key, node.Value); + groupedEntityViewsByType.Add(entityView.Key, entityView.Value); } } - static void AddNodeToDB(Dictionary nodesDB, KeyValuePair nodeList) + static void AddEntityViewToDB(Dictionary entityViewsDB, KeyValuePair entityViewList) { ITypeSafeList dbList; - if (nodesDB.TryGetValue(nodeList.Key, out dbList) == false) - dbList = nodesDB[nodeList.Key] = nodeList.Value.Create(); + if (entityViewsDB.TryGetValue(entityViewList.Key, out dbList) == false) + dbList = entityViewsDB[entityViewList.Key] = entityViewList.Value.Create(); - dbList.AddRange(nodeList.Value); + dbList.AddRange(entityViewList.Value); } - static void AddNodeToNodesDictionary(Dictionary nodesDBdic, - ITypeSafeList nodes, Type nodeType) + static void AddEntityViewToEntityViewsDictionary(Dictionary entityViewsDBdic, + ITypeSafeList entityViews, Type entityViewType) { - ITypeSafeDictionary nodesDic; + ITypeSafeDictionary entityViewsDic; - if (nodesDBdic.TryGetValue(nodeType, out nodesDic) == false) - nodesDic = nodesDBdic[nodeType] = nodes.CreateIndexedDictionary(); + if (entityViewsDBdic.TryGetValue(entityViewType, out entityViewsDic) == false) + entityViewsDic = entityViewsDBdic[entityViewType] = entityViews.CreateIndexedDictionary(); - nodesDic.FillWithIndexedNodes(nodes); + entityViewsDic.FillWithIndexedEntityViews(entityViews); } - static void AddNodeToTheSuitableEngines(Dictionary> nodeEngines, NodeWithID node, Type nodeType) + static void AddEntityViewToTheSuitableEngines(Dictionary> entityViewEngines, ITypeSafeList entityViewsList, Type entityViewType) { - FasterList enginesForNode; + FasterList enginesForEntityView; - if (nodeEngines.TryGetValue(nodeType, out enginesForNode)) + if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) { - for (int j = 0; j < enginesForNode.Count; j++) + int viewsCount; + + var entityViews = entityViewsList.ToArrayFast(out viewsCount); + + for (int i = 0; i < viewsCount; i++) { + int count; + var fastList = FasterList.NoVirt.ToArrayFast(enginesForEntityView, out count); + IEntityView entityView = entityViews[i]; + for (int j = 0; j < count; j++) + { #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, (enginesForNode[j] as INodeEngine), node); + EngineProfiler.MonitorAddDuration(_addEntityViewToEngine, fastList[j], entityView); #else - (enginesForNode[j] as INodeEngine).Add(node); + fastList[j].Add(entityView); #endif + } } } } -/* - void DisableNodeFromEngines(INode node, Type nodeType) - { - ITypeSafeList enginesForNode; - if (_activableEngines.TryGetValue(nodeType, out enginesForNode)) + void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, + Dictionary entityViewsDB) + { + int entityViewBuildersCount = entityViewBuilders.Length; + + for (int i = 0; i < entityViewBuildersCount; i++) { - for (int j = 0; j < enginesForNode.Count; j++) - { - (enginesForNode[j] as IActivableNodeEngine).Disable(node); - } - } - } + Type entityViewType = entityViewBuilders[i].GetEntityViewType(); - void EnableNodeFromEngines(INode node, Type nodeType) - { - ITypeSafeList enginesForNode; + ITypeSafeList entityViews = entityViewsDB[entityViewType]; + if (entityViews.UnorderedRemove(entityID) == false) + entityViewsDB.Remove(entityViewType); - if (_activableEngines.TryGetValue(nodeType, out enginesForNode)) - { - for (int j = 0; j < enginesForNode.Count; j++) + if (entityViews.isQueryiableEntityView) { - (enginesForNode[j] as IActivableNodeEngine).Enable(node); + var typeSafeDictionary = _entityViewsDBdic[entityViewType]; + var entityView = typeSafeDictionary.GetIndexedEntityView(entityID); + + if (typeSafeDictionary.Remove(entityID) == false) + _entityViewsDBdic.Remove(entityViewType); + + RemoveEntityViewFromEngines(_entityViewEngines, entityView, entityViewType); } } - }*/ -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - void AddNodeToEngine(IEngine engine, INode node) - { - (engine as INodeEngine).Add(node); - } - - void RemoveNodeFromEngine(IEngine engine, INode node) - { - (engine as INodeEngine).Remove(node); } -#endif - void InternalDisable(FasterList nodeBuilders, int entityID) + void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID, + Dictionary entityViewsDB) { -/* if (_engineRootWeakReference.IsValid == false) - return; + int entityViewBuildersCount = entityViewBuilders.Length; - for (int i = 0; i < nodes.Count; i++) + for (int i = 0; i < entityViewBuildersCount; i++) { - var node = nodes[i]; - Type nodeType = node.GetType(); - - DisableNodeFromEngines(node, nodeType); - }*/ - } + Type entityViewType = entityViewBuilders[i].GetEntityViewType(); + Dictionary dictionary = _groupEntityViewsDB[groupID]; - void InternalEnable(FasterList nodeBuilders, int entityID) - {/* - if (_engineRootWeakReference.IsValid == false) - return; + if (dictionary[entityViewType].UnorderedRemove(entityID) == false) + dictionary.Remove(entityViewType); - for (int i = 0; i < nodes.Count; i++) - { - var node = nodes[i]; - Type nodeType = node.GetType(); - EnableNodeFromEngines(node, nodeType); - }*/ + if (dictionary.Count == 0) _groupEntityViewsDB.Remove(groupID); + } + + InternalRemove(entityViewBuilders, entityID, entityViewsDB); } - void InternalRemove(FasterList nodeBuilders, int entityID) + static void RemoveEntityViewFromEngines(Dictionary> entityViewEngines, + IEntityView entityView, Type entityViewType) { - if (_engineRootWeakReference.IsValid == false) - return; + FasterList enginesForEntityView; - int nodeBuildersCount = nodeBuilders.Count; - for (int i = 0; i < nodeBuildersCount; i++) + if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) { - Type nodeType = nodeBuilders[i].GetType(); - - ITypeSafeList nodes; - if (_nodesDB.TryGetValue(nodeType, out nodes) == true) - nodes.UnorderedRemove(entityID); - - if (nodes.isQueryiableNode) + int count; + var fastList = FasterList.NoVirt.ToArrayFast(enginesForEntityView, out count); + + for (int j = 0; j < count; j++) { - var node = _nodesDBdic[nodeType].GetIndexedNode(entityID); - - _nodesDBdic[nodeType].Remove(entityID); - - RemoveNodeFromEngines(_nodeEngines, node, nodeType); +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + EngineProfiler.MonitorRemoveDuration(_removeEntityViewFromEngine, fastList[j], entityView); +#else + fastList[j].Remove(entityView); +#endif } } } - - void InternalGroupedRemove(FasterList nodeBuilders, int entityID) + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + static void AddEntityViewToEngine(IHandleEntityViewEngine engine, IEntityView entityView) { + engine.Add(entityView); } - void InternalMetaRemove(FasterList nodeBuilders, int entityID) + static void RemoveEntityViewFromEngine(IHandleEntityViewEngine engine, IEntityView entityView) { + engine.Remove(entityView); } - - static void RemoveNodeFromEngines(Dictionary> nodeEngines, NodeWithID node, Type nodeType) - { - FasterList enginesForNode; - - if (nodeEngines.TryGetValue(nodeType, out enginesForNode)) - { - for (int j = 0; j < enginesForNode.Count; j++) - { -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, (enginesForNode[j] as INodeEngine), node); -#else - (enginesForNode[j] as INodeEngine).Remove(node); #endif - } - } - } - void SubmitNodes() + void SubmitEntityViews() { - _nodesToAdd.Swap(); - _metaNodesToAdd.Swap(); - _groupedNodesToAdd.Swap(); - - bool newNodesHaveBeenAddedWhileIterating = - _metaNodesToAdd.Count > 0 - || _nodesToAdd.Count > 0 - || _groupedNodesToAdd.Count > 0; + bool newEntityViewsHaveBeenAddedWhileIterating = + _metaEntityViewsToAdd.current.Count > 0 + || _entityViewsToAdd.current.Count > 0 + || _groupedEntityViewsToAdd.current.Count > 0; int numberOfReenteringLoops = 0; - while (newNodesHaveBeenAddedWhileIterating) + while (newEntityViewsHaveBeenAddedWhileIterating) { - if ( _nodesToAdd.Count > 0) - AddNodesToTheDBAndSuitableEngines(_nodesToAdd.current, _nodeEngines, _nodesDBdic, _nodesDB); + //use other as source from now on + //current will be use to write new entityViews + _entityViewsToAdd.Swap(); + _metaEntityViewsToAdd.Swap(); + _groupedEntityViewsToAdd.Swap(); + + if ( _entityViewsToAdd.other.Count > 0) + AddEntityViewsToTheDBAndSuitableEngines(_entityViewsToAdd.other, _entityViewsDB); - if ( _metaNodesToAdd.Count > 0) - AddNodesToTheDBAndSuitableEngines(_metaNodesToAdd.current, _nodeEngines, _nodesDBdic, _metaNodesDB); + if ( _metaEntityViewsToAdd.other.Count > 0) + AddEntityViewsToTheDBAndSuitableEngines(_metaEntityViewsToAdd.other, _metaEntityViewsDB); - if (_groupedNodesToAdd.Count > 0) - AddGroupNodesToTheDBAndSuitableEngines(_groupedNodesToAdd.current, _nodeEngines, _nodesDBdic, _groupNodesDB, _nodesDB); + if (_groupedEntityViewsToAdd.other.Count > 0) + AddGroupEntityViewsToTheDBAndSuitableEngines(_groupedEntityViewsToAdd.other, _groupEntityViewsDB, _entityViewsDB); - _nodesToAdd.Clear(); - _metaNodesToAdd.Clear(); - _groupedNodesToAdd.Clear(); + //other can be cleared now + _entityViewsToAdd.other.Clear(); + _metaEntityViewsToAdd.other.Clear(); + _groupedEntityViewsToAdd.other.Clear(); - _nodesToAdd.Swap(); - _metaNodesToAdd.Swap(); - _groupedNodesToAdd.Swap(); - - newNodesHaveBeenAddedWhileIterating = - _metaNodesToAdd.Count > 0 - || _nodesToAdd.Count > 0 - || _groupedNodesToAdd.Count > 0; + //has current new entityViews? + newEntityViewsHaveBeenAddedWhileIterating = + _metaEntityViewsToAdd.current.Count > 0 + || _entityViewsToAdd.current.Count > 0 + || _groupedEntityViewsToAdd.current.Count > 0; if (numberOfReenteringLoops > 5) - throw new Exception("possible infinite loop found creating Entities inside INodesEngine Add method, please consider building entities outside INodesEngine Add method"); + throw new Exception("possible infinite loop found creating Entities inside IEntityViewsEngine Add method, please consider building entities outside IEntityViewsEngine Add method"); numberOfReenteringLoops++; } } - readonly Dictionary> _nodeEngines; - readonly Dictionary> _activableEngines; + readonly Dictionary> _entityViewEngines; readonly FasterList _otherEngines; - readonly Dictionary _nodesDB; - readonly Dictionary _metaNodesDB; - readonly Dictionary> _groupNodesDB; + readonly Dictionary _entityViewsDB; + readonly Dictionary _metaEntityViewsDB; + readonly Dictionary> _groupEntityViewsDB; - readonly Dictionary _nodesDBdic; + readonly Dictionary _entityViewsDBdic; - readonly DoubleBufferedNodes> _nodesToAdd; - readonly DoubleBufferedNodes> _metaNodesToAdd; - readonly DoubleBufferedNodes>> _groupedNodesToAdd; + readonly DoubleBufferedEntityViews> _entityViewsToAdd; + readonly DoubleBufferedEntityViews> _metaEntityViewsToAdd; + readonly DoubleBufferedEntityViews>> _groupedEntityViewsToAdd; - readonly NodeSubmissionScheduler _scheduler; - - readonly Type _structNodeEngineType; - readonly Type _groupedStructNodesEngineType; - readonly Type _activableNodeEngineType; + readonly EntityViewSubmissionScheduler _scheduler; +#if EXPERIMENTAL + readonly Type _structEntityViewEngineType; + readonly Type _groupedStructEntityViewsEngineType; - readonly SharedStructNodeLists _sharedStructNodeLists; - readonly SharedGroupedStructNodesLists _sharedGroupedStructNodeLists; - - readonly Dictionary _implementedInterfaceTypes; - readonly DataStructures.WeakReference _engineRootWeakReference; - - BuildNodeCallbackStruct _callBackStructForBuiltNodes; - BuildNodeCallbackStruct _callBackStructForBuiltGroupedNodes; - BuildNodeCallbackStruct _callBackStructForBuiltMetaNodes; + readonly SharedStructEntityViewLists _sharedStructEntityViewLists; + readonly SharedGroupedStructEntityViewsLists _sharedGroupedStructEntityViewLists; + + readonly Dictionary _implementedInterfaceTypes; +#endif + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + static Action _addEntityViewToEngine; + static Action _removeEntityViewFromEngine; +#endif + readonly EngineEntityViewDB _engineEntityViewDB; - class DoubleBufferedNodes where T : class, IDictionary, new() + class DoubleBufferedEntityViews where T : class, IDictionary, new() { - readonly T _nodesToAddBufferA = new T(); - readonly T _nodesToAddBufferB = new T(); + readonly T _entityViewsToAddBufferA = new T(); + readonly T _entityViewsToAddBufferB = new T(); - public DoubleBufferedNodes() + public DoubleBufferedEntityViews() { - this.other = _nodesToAddBufferA; - this.current = _nodesToAddBufferB; + this.other = _entityViewsToAddBufferA; + this.current = _entityViewsToAddBufferB; } public T other { get; private set; } public T current { get; private set; } + + public void Swap() + { + var toSwap = other; + other = current; + current = toSwap; + } + } + + class GenericEntityFactory : IEntityFactory + { + DataStructures.WeakReference _weakEngine; - public int Count + public GenericEntityFactory(DataStructures.WeakReference weakReference) { - get { return current.Count; } + _weakEngine = weakReference; } - - public void Clear() + + public void BuildEntity(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() { - current.Clear(); + _weakEngine.Target.BuildEntity(entityID, implementors); } - public void Swap() + public void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) { - var toSwap = other; - other = current; - current = toSwap; + _weakEngine.Target.BuildEntity(entityID, entityDescriptor, implementors); + } + + public void BuildMetaEntity(int metaEntityID, object[] implementors = null) where T : IEntityDescriptor, new() + { + _weakEngine.Target.BuildMetaEntity(metaEntityID, implementors); + } + + public void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() + { + _weakEngine.Target.BuildEntityInGroup(entityID, groupID, implementors); + } + + public void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) + { + _weakEngine.Target.BuildEntityInGroup(entityID, groupID, entityDescriptor, implementors); + } + } + + class GenericEntityFunctions : IEntityFunctions + { + public GenericEntityFunctions(DataStructures.WeakReference weakReference) + { + _weakReference = weakReference; + } + + public void RemoveEntity(int entityID, IRemoveEntityComponent entityTemplate) + { + _weakReference.Target.RemoveEntity(entityID, entityTemplate); + } + + public void RemoveEntity(int entityID) where T : IEntityDescriptor, new() + { + _weakReference.Target.RemoveEntity(entityID); + } + + public void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() + { + _weakReference.Target.RemoveEntity(metaEntityID); + } + + public void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() + { + _weakReference.Target.RemoveEntity(entityID); + } + + readonly DataStructures.WeakReference _weakReference; + } + + public void Dispose() + { + foreach (var entity in _entityViewsDB) + { + if (entity.Value.isQueryiableEntityView == true) + { + foreach (var entityView in entity.Value) + { + RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); + } + } + } + + foreach (var entity in _metaEntityViewsDB) + { + foreach (var entityView in entity.Value) + { + RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); + } } } } diff --git a/ECS/EntityDescriptor.cs b/ECS/EntityDescriptor.cs deleted file mode 100644 index 6202eac..0000000 --- a/ECS/EntityDescriptor.cs +++ /dev/null @@ -1,220 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using Svelto.DataStructures; -using Svelto.ECS.Internal; - -namespace Svelto.ECS -{ - public class EntityDescriptor - { - public void AddImplementors(params object[] componentsImplementor) - { - ProcessImplementors(componentsImplementor); - } - - public void AddNodes(params INodeBuilder[] nodesWithID) - { - _nodesToBuild.AddRange(nodesWithID); - } - - internal void BuildGroupedNodes - (int entityID, int groupID, - Dictionary> groupNodesByType, - ref BuildNodeCallbackStruct callBackstruct) - { - for (int index = 0; index < _nodesToBuild.Count; index++) - { - var nodeBuilder = _nodesToBuild[index]; - var nodeType = nodeBuilder.GetNodeType(); - - Dictionary groupedNodesTyped; - - if (groupNodesByType.TryGetValue(groupID, out groupedNodesTyped) == false) - { - groupedNodesTyped = new Dictionary(); - - groupNodesByType.Add(groupID, groupedNodesTyped); - }; - - BuildAndFillNode(entityID, groupedNodesTyped, nodeType, nodeBuilder); - } - - SetupImplementors(ref callBackstruct, entityID); - } - - internal void BuildNodes(int entityID, - Dictionary nodesByType, - ref BuildNodeCallbackStruct callBackstruct) - { - int count = _nodesToBuild.Count; - - for (int index = 0; index < count; index++) - { - var nodeBuilder = _nodesToBuild[index]; - var nodeType = nodeBuilder.GetNodeType(); - - BuildAndFillNode(entityID, nodesByType, nodeType, nodeBuilder); - } - - SetupImplementors(ref callBackstruct, entityID); - } - - void BuildAndFillNode(int entityID, Dictionary groupedNodesTyped, Type nodeType, INodeBuilder nodeBuilder) - { - ITypeSafeList nodes; - - var nodesPoolWillBeCreated = groupedNodesTyped.TryGetValue(nodeType, out nodes) == false; - var nodeObjectToFill = nodeBuilder.BuildNodeAndAddToList(ref nodes, entityID); - - if (nodesPoolWillBeCreated) - groupedNodesTyped.Add(nodeType, nodes); - - //the semantic of this code must still be improved - //but only classes can be filled, so I am aware - //it's a NodeWithID - if (nodeObjectToFill != null) - FillNode(nodeObjectToFill as NodeWithID); - } - - /// - /// if you want to avoid allocation in run-time, you can prebuild - /// EntityDescriptors and use them to build entities at different - /// times - /// - protected EntityDescriptor(INodeBuilder[] nodesToBuild) - { - _nodesToBuild = new FasterList(nodesToBuild); - } - protected EntityDescriptor(INodeBuilder[] nodesToBuild, - params object[] componentsImplementor):this(nodesToBuild) - { - ProcessImplementors(componentsImplementor); - } - - void ProcessImplementors(object[] implementors) - { - for (int index = 0; index < implementors.Length; index++) - { - var implementor = implementors[index]; - - if (implementor != null) - { - if (implementor is IRemoveEntityComponent) - _removingImplementors.Add(new DataStructures.WeakReference(implementor as IRemoveEntityComponent)); - if (implementor is IDisableEntityComponent) - _disablingImplementors.Add(new DataStructures.WeakReference(implementor as IDisableEntityComponent)); - if (implementor is IEnableEntityComponent) - _enablingImplementors.Add(new DataStructures.WeakReference(implementor as IEnableEntityComponent)); - - var interfaces = implementor.GetType().GetInterfaces(); - var weakReference = new DataStructures.WeakReference(implementor); - - for (int iindex = 0; iindex < interfaces.Length; iindex++) - { - var componentType = interfaces[iindex]; - - _implementorsByType[componentType] = weakReference; -#if DEBUG && !PROFILER - if (_implementorCounterByType.ContainsKey(componentType) == false) - _implementorCounterByType[componentType] = 1; - else - _implementorCounterByType[componentType]++; -#endif - } - } -#if DEBUG && !PROFILER - else - Utility.Console.LogError(NULL_IMPLEMENTOR_ERROR.FastConcat(ToString())); -#endif - } - } - - void SetupImplementors( - ref BuildNodeCallbackStruct callBackstruct, - int entityID) - { - var RemoveEntity = callBackstruct.internalRemove; - var DisableEntity = callBackstruct.internalDisable; - var EnableEntity = callBackstruct.internalEnable; - - int removingImplementorsCount = _removingImplementors.Count; - if (removingImplementorsCount > 0) - { - Action removeEntityAction = () => RemoveEntity(_nodesToBuild, entityID); - - for (int index = 0; index < removingImplementorsCount; index++) - _removingImplementors[index].Target.removeEntity = removeEntityAction; - } - - int disablingImplementorsCount = _disablingImplementors.Count; - if (disablingImplementorsCount > 0) - { - Action disableEntityAction = () => DisableEntity(_nodesToBuild, entityID); - - for (int index = 0; index < disablingImplementorsCount; index++) - _disablingImplementors[index].Target.disableEntity = disableEntityAction; - } - - int enablingImplementorsCount = _enablingImplementors.Count; - if (enablingImplementorsCount > 0) - { - Action enableEntityAction = () => EnableEntity(_nodesToBuild, entityID); - - for (int index = 0; index < enablingImplementorsCount; index++) - _enablingImplementors[index].Target.enableEntity = enableEntityAction; - } - } - - void FillNode(TNode node) where TNode : NodeWithID - { - var fields = node.GetType().GetFields(BindingFlags.Public | - BindingFlags.Instance); - - for (int i = fields.Length - 1; i >= 0; --i) - { - var field = fields[i]; - Type fieldType = field.FieldType; - DataStructures.WeakReference component; - - if (_implementorsByType.TryGetValue(fieldType, out component) == false) - { - Exception e = - new Exception(NOT_FOUND_EXCEPTION + - field.FieldType.Name + " - Node: " + node.GetType().Name + - " - EntityDescriptor " + this); - - throw e; - } - else - field.SetValue(node, component.Target); - -#if DEBUG && !PROFILER - { - if (_implementorCounterByType[fieldType] != 1) - { - Utility.Console.LogError( - DUPLICATE_IMPLEMENTOR_ERROR.FastConcat("component: ", fieldType.ToString(), - " implementor: ", component.Target.ToString())); - } - } -#endif - - } - } - - readonly FasterList> _disablingImplementors = new FasterList>(); - readonly FasterList> _removingImplementors = new FasterList>(); - readonly FasterList> _enablingImplementors = new FasterList>(); - - readonly Dictionary> _implementorsByType = new Dictionary>(); -#if DEBUG && !PROFILER - readonly Dictionary _implementorCounterByType = new Dictionary(); -#endif - readonly FasterList _nodesToBuild; - - const string DUPLICATE_IMPLEMENTOR_ERROR = "the same component is implemented with more than one implementor. This is considered an error and MUST be fixed. "; - const string NULL_IMPLEMENTOR_ERROR = "Null implementor, are you using a wild GetComponents to fetch it? "; - const string NOT_FOUND_EXCEPTION = "Svelto.ECS: Implementor not found for a Node. Implementor Type: "; - } -} diff --git a/ECS/EntityDescriptorTemplate.cs b/ECS/EntityDescriptorTemplate.cs new file mode 100644 index 0000000..cceb87d --- /dev/null +++ b/ECS/EntityDescriptorTemplate.cs @@ -0,0 +1,221 @@ +using System; +using System.Collections.Generic; + +namespace Svelto.ECS +{ + public interface IEntityDescriptor + { + IEntityViewBuilder[] entityViewsToBuild { get; } + } + + static class EntityDescriptorTemplate where TType : IEntityDescriptor, new() + { + public static readonly EntityDescriptorInfo Default = new EntityDescriptorInfo(new TType()); + } + + public class EntityDescriptorInfo + { + public readonly IEntityDescriptor descriptor; + public readonly string name; + + public EntityDescriptorInfo(IEntityDescriptor entityDescriptor) + { + descriptor = entityDescriptor; + name = descriptor.ToString(); + } + } +} + +namespace Svelto.ECS.Internal +{ + static class EntityFactory + { + internal static void BuildGroupedEntityViews(int entityID, int groupID, + Dictionary> groupEntityViewsByType, + EntityDescriptorInfo entityViewsToBuildDescriptor, + object[] implementors) + { + var entityViewsToBuild = entityViewsToBuildDescriptor.descriptor.entityViewsToBuild; + int count = entityViewsToBuild.Length; + + RemoveEntityImplementor removeEntityImplementor = null; + + for (int index = 0; index < count; index++) + { + var entityViewBuilder = entityViewsToBuild[index]; + var entityViewType = entityViewBuilder.GetEntityViewType(); + + Dictionary groupedEntityViewsTyped; + + if (groupEntityViewsByType.TryGetValue(groupID, out groupedEntityViewsTyped) == false) + { + groupedEntityViewsTyped = new Dictionary(); + groupEntityViewsByType.Add(groupID, groupedEntityViewsTyped); + } + + var entityViewObjectToFill = + BuildEntityView(entityID, groupedEntityViewsTyped, entityViewType, entityViewBuilder); + + //the semantic of this code must still be improved + //but only classes can be filled, so I am aware + //it's a EntityViewWithID + if (entityViewObjectToFill != null) + { + if (removeEntityImplementor == null) + removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.descriptor, groupID); + + FillEntityView(entityViewObjectToFill as EntityView, implementors, removeEntityImplementor, + entityViewsToBuildDescriptor.name); + } + } + } + + internal static void BuildEntityViews(int entityID, Dictionary entityViewsByType, + EntityDescriptorInfo entityViewsToBuildDescriptor, + object[] implementors) + { + var entityViewsToBuild = entityViewsToBuildDescriptor.descriptor.entityViewsToBuild; + int count = entityViewsToBuild.Length; + + RemoveEntityImplementor removeEntityImplementor = null; + + for (int index = 0; index < count; index++) + { + var entityViewBuilder = entityViewsToBuild[index]; + var entityViewType = entityViewBuilder.GetEntityViewType(); + + var entityViewObjectToFill = + BuildEntityView(entityID, entityViewsByType, entityViewType, entityViewBuilder); + + //the semantic of this code must still be improved + //but only classes can be filled, so I am aware + //it's a EntityView + if (entityViewObjectToFill != null) + { + if (removeEntityImplementor == null) + removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.descriptor); + + FillEntityView(entityViewObjectToFill as EntityView, implementors, removeEntityImplementor, + entityViewsToBuildDescriptor.name); + } + } + } + + static IEntityView BuildEntityView(int entityID, Dictionary groupedEntityViewsTyped, + Type entityViewType, IEntityViewBuilder entityViewBuilderId) + { + ITypeSafeList entityViews; + + var entityViewsPoolWillBeCreated = + groupedEntityViewsTyped.TryGetValue(entityViewType, out entityViews) == false; + var entityViewObjectToFill = entityViewBuilderId.BuildEntityViewAndAddToList(ref entityViews, entityID); + + if (entityViewsPoolWillBeCreated) + groupedEntityViewsTyped.Add(entityViewType, entityViews); + + return entityViewObjectToFill as IEntityView; + } + + static void FillEntityView(EntityView entityView, object[] implementors, RemoveEntityImplementor removeEntity, + string entityDescriptorName) + { + for (int index = 0; index < implementors.Length; index++) + { + var implementor = implementors[index]; + + if (implementor != null) + { + var type = implementor.GetType(); + + Type[] interfaces; + if (_cachedTypes.TryGetValue(type, out interfaces) == false) + interfaces = _cachedTypes[type] = type.GetInterfaces(); + + for (int iindex = 0; iindex < interfaces.Length; iindex++) + { + var componentType = interfaces[iindex]; +#if DEBUG && !PROFILER + Tuple implementorHolder; + if (implementorsByType.TryGetValue(componentType, out implementorHolder) == true) + implementorHolder.item2++; + else +#endif + + implementorsByType[componentType] = new Tuple(implementor, 0); + } + } +#if DEBUG && !PROFILER + else + Utility.Console.LogError(NULL_IMPLEMENTOR_ERROR.FastConcat(entityView.ToString())); +#endif + } + + int count; + + //Very efficent way to collect the fields of every EntityViewType + KeyValuePair>[] setters = + entityView.EntityViewBlazingFastReflection(out count); + + var removeEntityComponentType = typeof(IRemoveEntityComponent); + + for (int i = 0; i < count; i++) + { + var keyValuePair = setters[i]; + Type fieldType = keyValuePair.Key; + + if (fieldType == removeEntityComponentType) + { + keyValuePair.Value(entityView, removeEntity); + } + else + { + Tuple component; + + if (implementorsByType.TryGetValue(fieldType, out component) == false) + { + Exception e = new Exception(NOT_FOUND_EXCEPTION + " Component Type: " + fieldType.Name + " - EntityView: " + + entityView.GetType().Name + " - EntityDescriptor " + entityDescriptorName); + + throw e; + } + + if (component.item2 > 1) + Utility.Console.LogError(DUPLICATE_IMPLEMENTOR_ERROR.FastConcat( + "Component Type: ", fieldType.Name, " implementor: ", + component.item1.ToString()) + " - EntityView: " + + entityView.GetType().Name + " - EntityDescriptor " + entityDescriptorName); + + keyValuePair.Value(entityView, component.item1); + } + + } + + implementorsByType.Clear(); + } + + struct Tuple + { + public T1 item1; + public T2 item2; + + public Tuple(T1 implementor, T2 v) + { + item1 = implementor; + item2 = v; + } + } + + //this is used to avoid newing a dictionary every time, but it's used locally only + static readonly Dictionary> implementorsByType = new Dictionary>(); + static Dictionary _cachedTypes = new Dictionary(); + + const string DUPLICATE_IMPLEMENTOR_ERROR = + "Svelto.ECS the same component is implemented with more than one implementor. This is considered an error and MUST be fixed."; + + const string NULL_IMPLEMENTOR_ERROR = + "Svelto.ECS Null implementor, please be careful about the implementors passed to avoid performance loss"; + + const string NOT_FOUND_EXCEPTION = "Svelto.ECS Implementor not found for an EntityView."; + } +} + diff --git a/ECS/Experimental/StructNodeCollections.cs b/ECS/Experimental/StructNodeCollections.cs new file mode 100644 index 0000000..e9e76e2 --- /dev/null +++ b/ECS/Experimental/StructNodeCollections.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using Svelto.DataStructures; +using Svelto.ECS.Experimental.Internal; + +namespace Svelto.ECS.Experimental.Internal +{ + public interface IStructEntityViewEngine : IEngine + { + void CreateStructEntityViews(SharedStructEntityViewLists sharedStructEntityViewLists); + } + + public interface IGroupedStructEntityViewsEngine : IEngine + { + void CreateStructEntityViews(SharedGroupedStructEntityViewsLists sharedStructEntityViewLists); + } +} + +namespace Svelto.ECS.Experimental +{ + public interface IGroupedEntityView + { + int groupID { get; set; } + } + + /// + /// The engines can receive and store IEntityViews structs + /// Unboxing will happen during the Add, but the + /// data will then be stored and processed as stucts + /// + public interface IStructEntityViewEngine : IStructEntityViewEngine where T:struct, IEntityStruct + { } + + /// + /// same as above, but the entityViews are grouped by ID + /// usually the ID is the owner of the entityViews of that + /// group + /// + public interface IGroupedStructEntityViewsEngine : IGroupedStructEntityViewsEngine where T : struct, IGroupedEntityView + { + void Add(ref T entityView); + void Remove(ref T entityView); + } + + public sealed class StructEntityViews where T:struct, IEntityStruct + { + public T[] GetList(out int numberOfItems) + { + numberOfItems = _internalList.Count; + return _internalList.ToArrayFast(); + } + + public StructEntityViews(SharedStructEntityViewLists container) + { + _internalList = SharedStructEntityViewLists.NoVirt.GetList(container); + } + + public void Add(T entityView) + { + T convert = (T)entityView; + + _internalList.Add(convert); + } + + readonly FasterList _internalList; + } + + public struct StructGroupEntityViews + where T : struct, IEntityView + { + public StructGroupEntityViews(SharedGroupedStructEntityViewsLists container) + { + _container = container; + indices = new Dictionary(); + } + + public void Add(int groupID, T entityView) + { + T convert = (T)entityView; + + var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList(_container, groupID) as FasterList); + indices[entityView.ID] = fasterList.Count; + + fasterList.Add(convert); + } + + public void Remove(int groupID, T entityView) + { + var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList(_container, groupID) as FasterList); + var index = indices[entityView.ID]; + indices.Remove(entityView.ID); + + if (fasterList.UnorderedRemoveAt(index)) + indices[fasterList[index].ID] = index; + } + + public T[] GetList(int groupID, out int numberOfItems) + { + var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList(_container, groupID) as FasterList); + + return FasterList.NoVirt.ToArrayFast(fasterList, out numberOfItems); + } + + readonly SharedGroupedStructEntityViewsLists _container; + readonly Dictionary indices; + } + + public class SharedStructEntityViewLists + { + internal SharedStructEntityViewLists() + { + _collection = new Dictionary(); + } + + internal static class NoVirt + { + internal static FasterList GetList(SharedStructEntityViewLists obj) where T : struct + { + IFasterList list; + if (obj._collection.TryGetValue(typeof(T), out list)) + { + return list as FasterList; + } + + list = new FasterList(); + + obj._collection.Add(typeof(T), list); + + return (FasterList)list; + } + } + + readonly Dictionary _collection; + } + + public class SharedGroupedStructEntityViewsLists + { + internal SharedGroupedStructEntityViewsLists() + { + _collection = new Dictionary>(); + } + + internal static class NoVirt + { + internal static IFasterList GetList(SharedGroupedStructEntityViewsLists list, int groupID) where T : struct + { + Dictionary dic = GetGroup(list); + IFasterList localList; + + if (dic.TryGetValue(groupID, out localList)) + return localList; + + localList = new FasterList(); + dic.Add(groupID, localList); + + return localList; + } + + internal static Dictionary GetGroup(SharedGroupedStructEntityViewsLists list) where T : struct + { + Dictionary dic; + + if (list._collection.TryGetValue(typeof(T), out dic)) + { + return dic; + } + + dic = new Dictionary(); + + list._collection.Add(typeof(T), dic); + + return dic; + } + } + + readonly Dictionary> _collection; + } +} \ No newline at end of file diff --git a/ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs b/ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs new file mode 100644 index 0000000..9a21176 --- /dev/null +++ b/ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs @@ -0,0 +1,14 @@ +#if UNITY_5 || UNITY_5_3_OR_NEWER +namespace Svelto.ECS +{ + public class GenericEntityDescriptorHolder: + UnityEngine.MonoBehaviour, IEntityDescriptorHolder + where T: class, IEntityDescriptor, new() + { + public EntityDescriptorInfo RetrieveDescriptor() + { + return EntityDescriptorTemplate.Default; + } + } +} +#endif \ No newline at end of file diff --git a/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs b/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs index 5e0d363..8a6c173 100644 --- a/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs +++ b/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs @@ -1,30 +1,30 @@ #if UNITY_5 || UNITY_5_3_OR_NEWER -using System; using System.Collections; +using Svelto.WeakEvents; using UnityEngine; -namespace Svelto.ECS.NodeSchedulers +namespace Svelto.ECS.Schedulers { - //The NodeSubmissionScheduler has been introduced to make - //the node submission logic platform indipendent. + //The EntityViewSubmissionScheduler has been introduced to make + //the entityView submission logic platform indipendent. //Please don't be tempted to create your own submission to //adapt to your game level code design. For example, //you may be tempted to write a submission logic to submit - //the nodes immediatly just because convenient for your game + //the entityViews immediatly just because convenient for your game //logic. This is not how it works. - public class UnitySumbmissionNodeScheduler : NodeSubmissionScheduler + public class UnitySumbmissionEntityViewScheduler : EntityViewSubmissionScheduler { - public UnitySumbmissionNodeScheduler() + public UnitySumbmissionEntityViewScheduler() { GameObject go = new GameObject("ECSScheduler"); _scheduler = go.AddComponent(); } - public override void Schedule(Action submitNodes) + public override void Schedule(WeakAction submitEntityViews) { - _scheduler.OnTick += submitNodes; + _scheduler.OnTick = submitEntityViews; } class Scheduler : MonoBehaviour @@ -35,11 +35,15 @@ namespace Svelto.ECS.NodeSchedulers { yield return _wait; - OnTick(); + if (OnTick.IsValid) + OnTick.Invoke(); + else + yield break; } } - internal Action OnTick; + internal WeakAction OnTick; + WaitForEndOfFrame _wait = new WaitForEndOfFrame(); } diff --git a/ECS/GenericEntityDescriptor.cs b/ECS/GenericEntityDescriptor.cs index f0c87ff..da643e9 100644 --- a/ECS/GenericEntityDescriptor.cs +++ b/ECS/GenericEntityDescriptor.cs @@ -1,258 +1,110 @@ +using System.Runtime.InteropServices; + namespace Svelto.ECS { - public class GenericEntityDescriptor : EntityDescriptor - where T : NodeWithID, new() + public class GenericEntityDescriptor:IEntityDescriptor where T : EntityView, new() { static GenericEntityDescriptor() { - _nodesToBuild = new INodeBuilder[] { new NodeBuilder() }; + entityViewBuilders = new IEntityViewBuilder[] { new EntityViewBuilder() }; } - public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - {} - - static readonly INodeBuilder[] _nodesToBuild; - } - - public class GenericEntityDescriptor : EntityDescriptor - where T : NodeWithID, new() - where U : NodeWithID, new() - { - static GenericEntityDescriptor() + + public IEntityViewBuilder[] entityViewsToBuild { - _nodesToBuild = new INodeBuilder[] - { - new NodeBuilder(), - new NodeBuilder() - }; + get { return entityViewBuilders; } } - public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - {} - - static readonly INodeBuilder[] _nodesToBuild; + public static readonly IEntityViewBuilder[] entityViewBuilders; + } - public class GenericEntityDescriptor : EntityDescriptor - where T : NodeWithID, new() - where U : NodeWithID, new() - where V : NodeWithID, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() { static GenericEntityDescriptor() { - _nodesToBuild = new INodeBuilder[] - { - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder() - }; + entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder(), new EntityViewBuilder()}; } - public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - {} - - static readonly INodeBuilder[] _nodesToBuild; - } - public class GenericEntityDescriptor : EntityDescriptor - where T : NodeWithID, new() - where U : NodeWithID, new() - where V : NodeWithID, new() - where W : NodeWithID, new() - { - static GenericEntityDescriptor() + public IEntityViewBuilder[] entityViewsToBuild { - _nodesToBuild = new INodeBuilder[] - { - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder() - }; + get { return entityViewBuilders; } } - public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - {} - - static readonly INodeBuilder[] _nodesToBuild; + + public static readonly IEntityViewBuilder[] entityViewBuilders; } - public class GenericEntityDescriptor : EntityDescriptor - where T : NodeWithID, new() - where U : NodeWithID, new() - where V : NodeWithID, new() - where W : NodeWithID, new() - where X : NodeWithID, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() { static GenericEntityDescriptor() { - _nodesToBuild = new INodeBuilder[] - { - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder() - }; + entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder()}; } - public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - {} - static readonly INodeBuilder[] _nodesToBuild; - } - - public class GenericEntityDescriptor : EntityDescriptor - where T : NodeWithID, new() - where U : NodeWithID, new() - where V : NodeWithID, new() - where W : NodeWithID, new() - where X : NodeWithID, new() - where Y : NodeWithID, new() - { - static GenericEntityDescriptor() + public IEntityViewBuilder[] entityViewsToBuild { - _nodesToBuild = new INodeBuilder[] - { - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder() - }; + get { return entityViewBuilders; } } - public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - {} - - static readonly INodeBuilder[] _nodesToBuild; + + public static readonly IEntityViewBuilder[] entityViewBuilders; } - public class GenericMixedEntityDescriptor : EntityDescriptor - where T : INodeBuilder, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() + where W : EntityView, new() { - static GenericMixedEntityDescriptor() + static GenericEntityDescriptor() { - _nodesToBuild = new INodeBuilder[] - { - new T(), - }; + entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder()}; } - public GenericMixedEntityDescriptor(params object[] componentsImplementor) : - base(_nodesToBuild, componentsImplementor) - { } - static readonly INodeBuilder[] _nodesToBuild; - } - - public class GenericMixedEntityDescriptor : EntityDescriptor - where T : INodeBuilder, new() - where U : INodeBuilder, new() - { - static GenericMixedEntityDescriptor() + public IEntityViewBuilder[] entityViewsToBuild { - _nodesToBuild = new INodeBuilder[] - { - new T(), - new U(), - }; + get { return entityViewBuilders; } } - public GenericMixedEntityDescriptor(params object[] componentsImplementor) : - base(_nodesToBuild, componentsImplementor) - { } - - static readonly INodeBuilder[] _nodesToBuild; + + public static readonly IEntityViewBuilder[] entityViewBuilders; } - public class GenericMixedEntityDescriptor : EntityDescriptor - where T : INodeBuilder, new() - where U : INodeBuilder, new() - where V : INodeBuilder, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() + where W : EntityView, new() + where X : EntityView, new() { - static GenericMixedEntityDescriptor() + static GenericEntityDescriptor() { - _nodesToBuild = new INodeBuilder[] - { - new T(), - new U(), - new V() - }; + entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder()}; } - public GenericMixedEntityDescriptor(params object[] componentsImplementor) : - base(_nodesToBuild, componentsImplementor) - { } - - static readonly INodeBuilder[] _nodesToBuild; - } - public class GenericMixedEntityDescriptor : EntityDescriptor - where T : INodeBuilder, new() - where U : INodeBuilder, new() - where V : INodeBuilder, new() - where W : INodeBuilder, new() - { - static GenericMixedEntityDescriptor() + public IEntityViewBuilder[] entityViewsToBuild { - _nodesToBuild = new INodeBuilder[] - { - new T(), - new U(), - new V(), - new W() - }; + get { return entityViewBuilders; } } - public GenericMixedEntityDescriptor(params object[] componentsImplementor) : - base(_nodesToBuild, componentsImplementor) - { } - - static readonly INodeBuilder[] _nodesToBuild; + + public static readonly IEntityViewBuilder[] entityViewBuilders; } - public class GenericMixedEntityDescriptor : EntityDescriptor - where T : INodeBuilder, new() - where U : INodeBuilder, new() - where V : INodeBuilder, new() - where W : INodeBuilder, new() - where X : INodeBuilder, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() + where W : EntityView, new() + where X : EntityView, new() + where Y : EntityView, new() { - static GenericMixedEntityDescriptor() + static GenericEntityDescriptor() { - _nodesToBuild = new INodeBuilder[] - { - new T(), - new U(), - new V(), - new W(), - new X() - }; + entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder()}; } - public GenericMixedEntityDescriptor(params object[] componentsImplementor) : - base(_nodesToBuild, componentsImplementor) - { } - static readonly INodeBuilder[] _nodesToBuild; - } - - public class GenericMixedEntityDescriptor : EntityDescriptor - where T : INodeBuilder, new() - where U : INodeBuilder, new() - where V : INodeBuilder, new() - where W : INodeBuilder, new() - where X : INodeBuilder, new() - where Y : INodeBuilder, new() - { - static GenericMixedEntityDescriptor() + public IEntityViewBuilder[] entityViewsToBuild { - _nodesToBuild = new INodeBuilder[] - { - new T(), - new U(), - new V(), - new W(), - new X(), - new Y() - }; + get { return entityViewBuilders; } } - public GenericMixedEntityDescriptor(params object[] componentsImplementor) : - base(_nodesToBuild, componentsImplementor) - { } - - static readonly INodeBuilder[] _nodesToBuild; + + public static readonly IEntityViewBuilder[] entityViewBuilders; } } diff --git a/ECS/GenericEntityDescriptorHolder.cs b/ECS/GenericEntityDescriptorHolder.cs deleted file mode 100644 index 05c8ac5..0000000 --- a/ECS/GenericEntityDescriptorHolder.cs +++ /dev/null @@ -1,31 +0,0 @@ -#if UNITY_5 || UNITY_5_3_OR_NEWER -using System; - -namespace Svelto.ECS -{ - public class GenericEntityDescriptorHolder: - UnityEngine.MonoBehaviour, IEntityDescriptorHolder where T:EntityDescriptor - { - public EntityDescriptor BuildDescriptorType(object[] externalImplentors) - { - I[] implementors; - - if (externalImplentors != null) - { - I[] baseImplentors = gameObject.GetComponents(); - - implementors = new I[externalImplentors.Length + baseImplentors.Length]; - - Array.Copy(baseImplentors, implementors, baseImplentors.Length); - Array.Copy(externalImplentors, 0, implementors, baseImplentors.Length, externalImplentors.Length); - } - else - { - implementors = gameObject.GetComponents(); - } - - return (T)Activator.CreateInstance(typeof(T), implementors); - } - } -} -#endif \ No newline at end of file diff --git a/ECS/ICallBackOnAddEngine.cs b/ECS/ICallBackOnAddEngine.cs deleted file mode 100644 index e77bf6a..0000000 --- a/ECS/ICallBackOnAddEngine.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Svelto.ECS -{ - public interface ICallBackOnAddEngine - { - void Ready(); - } -} diff --git a/ECS/IEngine.cs b/ECS/IEngine.cs index bb4c012..9fb5bec 100644 --- a/ECS/IEngine.cs +++ b/ECS/IEngine.cs @@ -1,36 +1,9 @@ -using Rewired.Utils; -using Svelto.ECS.Internal; - namespace Svelto.ECS.Internal { - public interface IStructNodeEngine : IEngine - { - void CreateStructNodes(SharedStructNodeLists sharedStructNodeLists); - } - - public interface IGroupedStructNodesEngine : IEngine + public interface IHandleEntityViewEngine : IEngine { - void CreateStructNodes(SharedGroupedStructNodesLists sharedStructNodeLists); - } - - public interface IActivableNodeEngine : IEngine - { - void Enable(NodeWithID node); - void Disable(NodeWithID node); - } - - public interface INodeEngine : IEngine - { - void Add(NodeWithID node); - void Remove(NodeWithID node); - } -} - -namespace Svelto.ECS.Legacy -{ - public interface INodesEngine : INodeEngine - { - System.Type[] AcceptedNodes(); + void Add(IEntityView entityView); + void Remove(IEntityView entityView); } } @@ -38,32 +11,17 @@ namespace Svelto.ECS { public interface IEngine {} - - public interface IActivableNodeEngine : IActivableNodeEngine where TNodeType : INode - { } - - public interface IQueryableNodeEngine:IEngine +#if EXPERIMENTAL + public interface IHandleActivableEntityEngine : IEngine { - IEngineNodeDB nodesDB { set; } + void Enable(EntityView entityView); + void Disable(EntityView entityView); } - - /// - /// 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, IGroupedNode +#endif + public interface IQueryingEntityViewEngine : IEngine { - void Add(ref T node); - void Remove(ref T node); + IEngineEntityViewDB entityViewsDB { set; } + + void Ready(); } } - diff --git a/ECS/IEngineNodeDB.cs b/ECS/IEngineNodeDB.cs index 05a2c6f..ddbf011 100644 --- a/ECS/IEngineNodeDB.cs +++ b/ECS/IEngineNodeDB.cs @@ -2,21 +2,21 @@ using Svelto.DataStructures; namespace Svelto.ECS { - public interface IEngineNodeDB + public interface IEngineEntityViewDB { - FasterReadOnlyList QueryNodes(); - FasterReadOnlyList QueryMetaNodes(); - FasterReadOnlyList QueryGroupedNodes(int group); + FasterReadOnlyList QueryEntityViews() where T:EntityView, new(); + FasterReadOnlyList QueryMetaEntityViews() where T: EntityView, new(); + FasterReadOnlyList QueryGroupedEntityViews(int group) where T: EntityView, new(); - T[] QueryNodesAsArray(out int count) where T:struct; + T[] QueryEntityViewsAsArray(out int count) where T: IEntityView; + T[] QueryGroupedEntityViewsAsArray(int @group, out int count) where T: IEntityView; - ReadOnlyDictionary QueryIndexableNodes() where T:NodeWithID; - - bool TryQueryNode(int ID, out T node) where T:NodeWithID; - T QueryNode(int ID) where T:NodeWithID; + ReadOnlyDictionary QueryIndexableEntityViews() where T: IEntityView; + bool TryQueryEntityView(int ID, out T entityView) where T : IEntityView; + T QueryEntityView(int ID) where T: IEntityView; - bool TryQueryMetaNode(int metaEntityID, out T node) where T:NodeWithID; - T QueryMetaNode(int metaEntityID) where T:NodeWithID; + bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T: EntityView, new(); + T QueryMetaEntityView(int metaEntityID) where T: EntityView, new(); } } diff --git a/ECS/IEnginesInterfaces.cs b/ECS/IEnginesInterfaces.cs new file mode 100644 index 0000000..05ed50c --- /dev/null +++ b/ECS/IEnginesInterfaces.cs @@ -0,0 +1,31 @@ +namespace Svelto.ECS +{ + public interface IEntityFactory + { + void BuildEntity(int entityID, object[] implementors = null) where T:IEntityDescriptor, new(); + void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null); + + void BuildMetaEntity(int metaEntityID, object[] implementors = null) where T:IEntityDescriptor, new(); + + void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T:IEntityDescriptor, new(); + void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null); + } + + public interface IEntityFunctions + { + void RemoveEntity(int entityID, IRemoveEntityComponent template); + + void RemoveEntity(int entityID) where T:IEntityDescriptor, new(); + + void RemoveMetaEntity(int metaEntityID) where T:IEntityDescriptor, new(); + + void RemoveEntityFromGroup(int entityID, int groupID) where T:IEntityDescriptor, new(); +#if EXPERIMENTAL + void SetEntityActiveState(int entityID, bool state) where T:IEntityDescriptor, new(); + + void SetMetaEntityActiveState(int metaEntityID, bool state) where T:IEntityDescriptor, new(); + + void SetEntityInGroupActiveState(int entityID, int group, bool state) where T:IEntityDescriptor, new(); +#endif + } +} diff --git a/ECS/IEnginesRoot.cs b/ECS/IEnginesRoot.cs deleted file mode 100644 index 14f5957..0000000 --- a/ECS/IEnginesRoot.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Svelto.ECS -{ - public interface IEnginesRoot - { - void AddEngine(IEngine engine); - } - - public interface IEntityFactory - { - void BuildEntity(int ID, EntityDescriptor ED); - - void BuildMetaEntity(int metaEntityID, EntityDescriptor ED); - - void BuildEntityInGroup(int entityID, int groupID, EntityDescriptor ED); - } -} diff --git a/ECS/IEntityDescriptorHolder.cs b/ECS/IEntityDescriptorHolder.cs index 2c70278..c2a7515 100644 --- a/ECS/IEntityDescriptorHolder.cs +++ b/ECS/IEntityDescriptorHolder.cs @@ -1,11 +1,7 @@ namespace Svelto.ECS { - /// - /// please use [DisallowMultipleComponent] in your monobehaviours that implement IEntityDescriptorHolder - /// public interface IEntityDescriptorHolder { - //I must find a nicer solution for the extraImplentors - EntityDescriptor BuildDescriptorType(object[] extraImplentors = null); + EntityDescriptorInfo RetrieveDescriptor(); } } diff --git a/ECS/INode.cs b/ECS/INode.cs index 4876a86..445781c 100644 --- a/ECS/INode.cs +++ b/ECS/INode.cs @@ -1,29 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using Svelto.DataStructures; +using Svelto.Utilities; + namespace Svelto.ECS -{ - public interface INode +{ + public interface IEntityView { int ID { get; } } - public interface IGroupedNode + public interface IEntityStruct:IEntityView { - int groupID { get; set; } + new int ID { set; } } - - public interface IStructNodeWithID : INode + + public abstract class EntityView : IEntityView { - new int ID { get; set; } + public int ID { get { return _ID; } } + + abstract internal KeyValuePair>[] + EntityViewBlazingFastReflection(out int count); + + protected int _ID; } - public class NodeWithID: INode + public class EntityView: EntityView where T: EntityView { - public static TNodeType BuildNode(int ID) where TNodeType: NodeWithID, new() + internal static TEntityViewType BuildEntityView(int ID) where TEntityViewType: EntityView, new() { - return new TNodeType { _ID = ID }; + if (FieldCache.list.Count == 0) + { + var type = typeof(TEntityViewType); + + var fields = type.GetFields(BindingFlags.Public | + BindingFlags.Instance); + + for (int i = fields.Length - 1; i >= 0; --i) + { + var field = fields[i]; + + Action setter = FastInvoke.MakeSetter(field); + + FieldCache.Add(new KeyValuePair>(field.FieldType, setter)); + } + } + + return new TEntityViewType { _ID = ID }; } - public int ID { get { return _ID; } } + override internal KeyValuePair>[] + EntityViewBlazingFastReflection(out int count) + { + return FasterList>>.NoVirt.ToArrayFast(FieldCache.list, out count); + } - protected int _ID; + static class FieldCache + { + internal static void Add(KeyValuePair> setter) + { + list.Add(setter); + } + + internal static readonly FasterList>> list = new FasterList>>(); + } } } + diff --git a/ECS/IRemoveEntityComponent.cs b/ECS/IRemoveEntityComponent.cs deleted file mode 100644 index 5a3ee3b..0000000 --- a/ECS/IRemoveEntityComponent.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; - -namespace Svelto.ECS -{ - public interface IRemoveEntityComponent - { - Action removeEntity { get; set; } - } - - public interface IDisableEntityComponent - { - Action disableEntity { get; set; } - } - - public interface IEnableEntityComponent - { - Action enableEntity { get; set; } - } -} diff --git a/ECS/MixedEntityDescriptor.cs b/ECS/MixedEntityDescriptor.cs new file mode 100644 index 0000000..f91ad54 --- /dev/null +++ b/ECS/MixedEntityDescriptor.cs @@ -0,0 +1,107 @@ +namespace Svelto.ECS +{ + public class MixedEntityDescriptor:IEntityDescriptor where T : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + where V : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + where V : class, IEntityViewBuilder, new() + where W : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V(), new W()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + where V : class, IEntityViewBuilder, new() + where W : class, IEntityViewBuilder, new() + where X : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V(), new W(), new X()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + where V : class, IEntityViewBuilder, new() + where W : class, IEntityViewBuilder, new() + where X : class, IEntityViewBuilder, new() + where Y : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V(), new W(), new X(), new Y()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } +} diff --git a/ECS/MultiNodesEngine.cs b/ECS/MultiNodesEngine.cs index 3559310..2ba4856 100644 --- a/ECS/MultiNodesEngine.cs +++ b/ECS/MultiNodesEngine.cs @@ -1,85 +1,87 @@ -using Svelto.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS.Internal { - public abstract class MultiNodesEngine:INodeEngine where T:NodeWithID + public abstract class MultiEntityViewsEngine:IHandleEntityViewEngine where T:EntityView, new() { - protected abstract void Add(T node); - protected abstract void Remove(T node); + protected abstract void Add(T entityView); + protected abstract void Remove(T entityView); - public virtual void Add(NodeWithID node) + public virtual void Add(IEntityView entityView) { - Add((T) node); + Add((T) entityView); } - public virtual void Remove(NodeWithID node) + public virtual void Remove(IEntityView entityView) { - Remove((T) node); + Remove((T) entityView); } } } namespace Svelto.ECS { - public abstract class MultiNodesEngine : MultiNodesEngine - where T:NodeWithID where U:NodeWithID + public abstract class MultiEntityViewsEngine : MultiEntityViewsEngine + where T:EntityView, new() + where U:EntityView, new() { - protected abstract void Add(U node); - protected abstract void Remove(U node); + protected abstract void Add(U entityView); + protected abstract void Remove(U entityView); - public override void Add(NodeWithID node) + public override void Add(IEntityView entityView) { - var castedNode = node as U; - if (castedNode != null) + var castedEntityView = entityView as U; + if (castedEntityView != null) { - Add(castedNode); + Add(castedEntityView); } else { - base.Add(node); + base.Add(entityView); } } - public override void Remove(NodeWithID node) + public override void Remove(IEntityView entityView) { - if (node is U) + if (entityView is U) { - Remove((U) node); + Remove((U) entityView); } else { - base.Remove(node); + base.Remove(entityView); } } } - public abstract class MultiNodesEngine : MultiNodesEngine - where T: NodeWithID where U : NodeWithID where V:NodeWithID + public abstract class MultiEntityViewsEngine : MultiEntityViewsEngine + where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() { - protected abstract void Add(V node); - protected abstract void Remove(V node); + protected abstract void Add(V entityView); + protected abstract void Remove(V entityView); - public override void Add(NodeWithID node) + public override void Add(IEntityView entityView) { - var castedNode = node as V; - if (castedNode != null) + var castedEntityView = entityView as V; + if (castedEntityView != null) { - Add(castedNode); + Add(castedEntityView); } else - base.Add(node); + base.Add(entityView); } - public override void Remove(NodeWithID node) + public override void Remove(IEntityView entityView) { - var castedNode = node as V; - if (castedNode != null) + var castedEntityView = entityView as V; + if (castedEntityView != null) { - Remove(castedNode); + Remove(castedEntityView); } else - base.Remove(node); + base.Remove(entityView); } } } \ No newline at end of file diff --git a/ECS/NodeBuilder.cs b/ECS/NodeBuilder.cs index 70deb96..7b4db4b 100644 --- a/ECS/NodeBuilder.cs +++ b/ECS/NodeBuilder.cs @@ -1,58 +1,61 @@ using System; -using Svelto.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS { - public interface INodeBuilder + public interface IEntityViewBuilder { - INode BuildNodeAndAddToList(ref ITypeSafeList list, int entityID); + IEntityView BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID); - Type GetNodeType(); + Type GetEntityViewType(); } - public class NodeBuilder : INodeBuilder where NodeType : NodeWithID, new() + public class EntityViewBuilder : IEntityViewBuilder where EntityViewType : EntityView, new() { - public INode BuildNodeAndAddToList(ref ITypeSafeList list, int entityID) + public IEntityView BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID) { if (list == null) - list = new TypeSafeFasterListForECSForClasses(); + list = new TypeSafeFasterListForECSForClasses(); - var castedList = list as TypeSafeFasterListForECSForClasses; + var castedList = list as TypeSafeFasterListForECSForClasses; - var node = NodeWithID.BuildNode(entityID); + var entityView = EntityView.BuildEntityView(entityID); - castedList.Add(node); + castedList.Add(entityView); - return node; + return entityView; } - public Type GetNodeType() + public Type GetEntityViewType() { - return typeof(NodeType); + return _entityViewType; } + + readonly Type _entityViewType = typeof(EntityViewType); } - public class StructNodeBuilder : INodeBuilder where NodeType : struct, IStructNodeWithID + public class EntityStructBuilder : IEntityViewBuilder where EntityViewType : struct, IEntityStruct { - public INode BuildNodeAndAddToList(ref ITypeSafeList list, int entityID) + public IEntityView BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID) { - var node = default(NodeType); - node.ID = entityID; + var entityView = default(EntityViewType); + entityView.ID = entityID; if (list == null) - list = new TypeSafeFasterListForECSForStructs(); + list = new TypeSafeFasterListForECSForStructs(); - var castedList = list as TypeSafeFasterListForECSForStructs; + var castedList = list as TypeSafeFasterListForECSForStructs; - castedList.Add(node); + castedList.Add(entityView); return null; } - public Type GetNodeType() + public Type GetEntityViewType() { - return typeof(NodeType); + return _entityViewType; } - } + + readonly Type _entityViewType = typeof(EntityViewType); + } } \ No newline at end of file diff --git a/ECS/NodeSubmissionScheduler.cs b/ECS/NodeSubmissionScheduler.cs index dc86bf2..bc62758 100644 --- a/ECS/NodeSubmissionScheduler.cs +++ b/ECS/NodeSubmissionScheduler.cs @@ -1,9 +1,9 @@ -using System; +using Svelto.WeakEvents; -namespace Svelto.ECS.NodeSchedulers +namespace Svelto.ECS.Schedulers { - public abstract class NodeSubmissionScheduler + public abstract class EntityViewSubmissionScheduler { - abstract public void Schedule(Action submitNodes); + abstract public void Schedule(WeakAction submitEntityViews); } } \ No newline at end of file diff --git a/ECS/Profiler/EngineInfo.cs b/ECS/Profiler/EngineInfo.cs index ceffef9..c8fd453 100644 --- a/ECS/Profiler/EngineInfo.cs +++ b/ECS/Profiler/EngineInfo.cs @@ -33,12 +33,12 @@ namespace Svelto.ECS.Profiler double _accumulatedAddDuration; double _minAddDuration; double _maxAddDuration; - int _nodesAddedCount; + int _entityViewsAddedCount; double _accumulatedRemoveDuration; double _minRemoveDuration; double _maxRemoveDuration; - int _nodesRemovedCount; + int _entityViewsRemovedCount; public IEngine engine { get { return _engine; } } public string engineName { get { return _engineName; } } @@ -56,8 +56,8 @@ namespace Svelto.ECS.Profiler public double maxRemoveDuration { get { return _maxRemoveDuration; } } public double maxUpdateDuration { get { return _maxUpdateDuration[(int)UpdateType.Update]; } } - public double averageAddDuration { get { return _nodesAddedCount == 0 ? 0 : _accumulatedAddDuration / _nodesAddedCount; } } - public double averageRemoveDuration { get { return _nodesRemovedCount == 0 ? 0 : _accumulatedRemoveDuration / _nodesRemovedCount; } } + public double averageAddDuration { get { return _entityViewsAddedCount == 0 ? 0 : _accumulatedAddDuration / _entityViewsAddedCount; } } + public double averageRemoveDuration { get { return _entityViewsRemovedCount == 0 ? 0 : _accumulatedRemoveDuration / _entityViewsRemovedCount; } } public double averageUpdateDuration { get { return _updateFrameTimes[(int)UpdateType.Update].Count == 0 ? 0 : _accumulatedUpdateDuration[(int)UpdateType.Update] / _updateFrameTimes[(int)UpdateType.Update].Count; } } public double averageLateUpdateDuration { get { return _updateFrameTimes[(int)UpdateType.LateUpdate].Count == 0 ? 0 : _accumulatedUpdateDuration[(int)UpdateType.LateUpdate] / _updateFrameTimes[(int)UpdateType.LateUpdate].Count; } } public double averageFixedUpdateDuration { get { return _updateFrameTimes[(int)UpdateType.FixedUpdate].Count == 0 ? 0 : _accumulatedUpdateDuration[(int)UpdateType.FixedUpdate] / _updateFrameTimes[(int)UpdateType.FixedUpdate].Count; } } @@ -126,7 +126,7 @@ namespace Svelto.ECS.Profiler _maxAddDuration = duration; } _accumulatedAddDuration += duration; - _nodesAddedCount += 1; + _entityViewsAddedCount += 1; } public void AddRemoveDuration(double duration) @@ -140,7 +140,7 @@ namespace Svelto.ECS.Profiler _maxRemoveDuration = duration; } _accumulatedRemoveDuration += duration; - _nodesRemovedCount += 1; + _entityViewsRemovedCount += 1; } public void ResetDurations() @@ -156,12 +156,12 @@ namespace Svelto.ECS.Profiler _accumulatedAddDuration = 0; _minAddDuration = 0; _maxAddDuration = 0; - _nodesAddedCount = 0; + _entityViewsAddedCount = 0; _accumulatedRemoveDuration = 0; _minRemoveDuration = 0; _maxRemoveDuration = 0; - _nodesRemovedCount = 0; + _entityViewsRemovedCount = 0; } } } diff --git a/ECS/Profiler/EngineProfiler.cs b/ECS/Profiler/EngineProfiler.cs index 14ed4c7..5f0765d 100644 --- a/ECS/Profiler/EngineProfiler.cs +++ b/ECS/Profiler/EngineProfiler.cs @@ -12,27 +12,27 @@ namespace Svelto.ECS.Profiler { static readonly Stopwatch _stopwatch = new Stopwatch(); - public static void MonitorAddDuration(Action addingFunc, INodeEngine engine, INode node) + public static void MonitorAddDuration(Action addingFunc, IHandleEntityViewEngine engine, IEntityView entityView) { EngineInfo info; if (engineInfos.TryGetValue(engine.GetType(), out info)) { _stopwatch.Start(); - addingFunc(engine, node); + addingFunc(engine, entityView); _stopwatch.Reset(); info.AddAddDuration(_stopwatch.Elapsed.TotalMilliseconds); } } - public static void MonitorRemoveDuration(Action removeFunc, INodeEngine engine, NodeWithID node) + public static void MonitorRemoveDuration(Action removeFunc, IHandleEntityViewEngine engine, IEntityView entityView) { EngineInfo info; if (engineInfos.TryGetValue(engine.GetType(), out info)) { _stopwatch.Start(); - removeFunc(engine, node); - engine.Remove(node); + removeFunc(engine, entityView); + engine.Remove(entityView); _stopwatch.Reset(); info.AddRemoveDuration(_stopwatch.Elapsed.TotalMilliseconds); diff --git a/ECS/RemoveEntityImplementor.cs b/ECS/RemoveEntityImplementor.cs new file mode 100644 index 0000000..30f74c5 --- /dev/null +++ b/ECS/RemoveEntityImplementor.cs @@ -0,0 +1,42 @@ +namespace Svelto.ECS.Internal +{ + sealed class RemoveEntityImplementor : IRemoveEntityComponent + { + public RemoveEntityImplementor(IEntityDescriptor descriptor, int groupID) : this(descriptor) + { + removeEntityInfo = new RemoveEntityInfo(descriptor, groupID); + } + + internal RemoveEntityImplementor(IEntityDescriptor descriptor) + { + removeEntityInfo = new RemoveEntityInfo(descriptor); + } + + internal RemoveEntityInfo removeEntityInfo; + } +} + +namespace Svelto.ECS +{ + public interface IRemoveEntityComponent + {} + + public struct RemoveEntityInfo + { + readonly public IEntityDescriptor descriptor; + readonly public int groupID; + readonly public bool isInAGroup; + + public RemoveEntityInfo(IEntityDescriptor descriptor) : this() + { + this.descriptor = descriptor; + } + + public RemoveEntityInfo(IEntityDescriptor descriptor, int groupID) + { + this.descriptor = descriptor; + this.groupID = groupID; + isInAGroup = true; + } + } +} diff --git a/ECS/SingleNodeEngine.cs b/ECS/SingleNodeEngine.cs index 82b6727..a3ac1ad 100644 --- a/ECS/SingleNodeEngine.cs +++ b/ECS/SingleNodeEngine.cs @@ -2,19 +2,19 @@ using Svelto.ECS.Internal; namespace Svelto.ECS { - public abstract class SingleNodeEngine : INodeEngine where T:NodeWithID + public abstract class SingleEntityViewEngine : IHandleEntityViewEngine where T:EntityView, new() { - public void Add(NodeWithID node) + public void Add(IEntityView entityView) { - Add((T)node); //when byref returns will be vailable, this should be passed by reference, not copy! + Add((T)entityView); //when byref returns will be vailable, this should be passed by reference, not copy! } - public void Remove(NodeWithID node) + public void Remove(IEntityView entityView) { - Remove((T)node); + Remove((T)entityView); } - protected abstract void Add(T node); - protected abstract void Remove(T node); + protected abstract void Add(T entityView); + protected abstract void Remove(T entityView); } } diff --git a/ECS/StructNodes.cs b/ECS/StructNodes.cs deleted file mode 100644 index 0ccaf94..0000000 --- a/ECS/StructNodes.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System; -using System.Collections.Generic; -using Svelto.DataStructures; -using Svelto.ECS.Internal; - -namespace Svelto.ECS -{ - public sealed class StructNodes where T:struct, IStructNodeWithID - { - public T[] GetList(out int numberOfItems) - { - numberOfItems = _internalList.Count; - return _internalList.ToArrayFast(); - } - - public StructNodes(SharedStructNodeLists container) - { - _internalList = SharedStructNodeLists.NoVirt.GetList(container); - } - - public void Add(T node) - { - T convert = (T)node; - - _internalList.Add(convert); - } - - readonly FasterList _internalList; - } - - public struct StructGroupNodes - where T : struct, IStructNodeWithID - { - public StructGroupNodes(SharedGroupedStructNodesLists container) - { - _container = container; - indices = new Dictionary(); - } - - public void Add(int groupID, T node) - { - T convert = (T)node; - - var fasterList = (SharedGroupedStructNodesLists.NoVirt.GetList(_container, groupID) as FasterList); - indices[node.ID] = fasterList.Count; - - fasterList.Add(convert); - } - - public void Remove(int groupID, T node) - { - var fasterList = (SharedGroupedStructNodesLists.NoVirt.GetList(_container, groupID) as FasterList); - var index = indices[node.ID]; - indices.Remove(node.ID); - - if (fasterList.UnorderedRemoveAt(index)) - indices[fasterList[index].ID] = index; - } - - public T[] GetList(int groupID, out int numberOfItems) - { - var fasterList = (SharedGroupedStructNodesLists.NoVirt.GetList(_container, groupID) as FasterList); - - return FasterList.NoVirt.ToArrayFast(fasterList, out numberOfItems); - } - - readonly SharedGroupedStructNodesLists _container; - readonly Dictionary indices; - } - - public class SharedStructNodeLists - { - internal SharedStructNodeLists() - { - _collection = new Dictionary(); - } - - internal static class NoVirt - { - internal static FasterList GetList(SharedStructNodeLists obj) where T : struct - { - IFasterList list; - if (obj._collection.TryGetValue(typeof(T), out list)) - { - return list as FasterList; - } - - list = new FasterList(); - - obj._collection.Add(typeof(T), list); - - return (FasterList)list; - } - } - - readonly Dictionary _collection; - } - - public class SharedGroupedStructNodesLists - { - internal SharedGroupedStructNodesLists() - { - _collection = new Dictionary>(); - } - - internal static class NoVirt - { - internal static IFasterList GetList(SharedGroupedStructNodesLists list, int groupID) where T : struct - { - Dictionary dic = GetGroup(list); - IFasterList localList; - - if (dic.TryGetValue(groupID, out localList)) - return localList; - - localList = new FasterList(); - dic.Add(groupID, localList); - - return localList; - } - - internal static Dictionary GetGroup(SharedGroupedStructNodesLists list) where T : struct - { - Dictionary dic; - - if (list._collection.TryGetValue(typeof(T), out dic)) - { - return dic; - } - - dic = new Dictionary(); - - list._collection.Add(typeof(T), dic); - - return dic; - } - } - - readonly Dictionary> _collection; - } -} \ No newline at end of file diff --git a/ECS/note.txt b/ECS/note.txt index c041193..33ca04c 100644 --- a/ECS/note.txt +++ b/ECS/note.txt @@ -27,7 +27,7 @@ producer/consumer has the inconvienent to force check the number of jobs availab Engine can't be removed, they can only be disabled, but the logic of disabling must be handled by the engine itself -Should components have just one element? Should engines use just nodes? Components are ditacted by the entities and Nodes by the engines +Should components have just one element? Should engines use just entityViews? Components are ditacted by the entities and EntityViews by the engines http://thelinuxlich.github.io/artemis_CSharp/ @@ -42,7 +42,7 @@ http://entity-systems.wikidot.com/es-articles http://www.ashframework.org/ -it's very important to give a namespace to the engines. In this way it's impossible to create semantically wrong nodes (PlayerNode Vs TargetNode) +it's very important to give a namespace to the engines. In this way it's impossible to create semantically wrong entityViews (PlayerEntityView Vs TargetEntityView) ToDo: diff --git a/Utilities/FastInvoke.cs b/Utilities/FastInvoke.cs new file mode 100644 index 0000000..48e72f5 --- /dev/null +++ b/Utilities/FastInvoke.cs @@ -0,0 +1,24 @@ +using System; +using System.Reflection; +using System.Reflection.Emit; + +namespace Svelto.Utilities +{ + //https://stackoverflow.com/questions/321650/how-do-i-set-a-field-value-in-an-c-sharp-expression-tree/321686#321686 + public static class FastInvoke where T : class + { + public static Action MakeSetter(FieldInfo field) + { + DynamicMethod m = new DynamicMethod("setter", typeof(void), new Type[] {typeof(T), typeof(object)}); + ILGenerator cg = m.GetILGenerator(); + + // arg0. = arg1 + cg.Emit(OpCodes.Ldarg_0); + cg.Emit(OpCodes.Ldarg_1); + cg.Emit(OpCodes.Stfld, field); + cg.Emit(OpCodes.Ret); + + return (Action) m.CreateDelegate(typeof(Action));; + } + } +} \ No newline at end of file diff --git a/Utilities/Murmur3.cs b/Utilities/Murmur3.cs index 6e83e68..9a0d5d7 100644 --- a/Utilities/Murmur3.cs +++ b/Utilities/Murmur3.cs @@ -1,5 +1,4 @@ using System; -using System.IO; /// /// Murmur hash. diff --git a/Utilities/NetFXCoreWrappers.cs b/Utilities/NetFXCoreWrappers.cs index b172b0b..cde69f8 100644 --- a/Utilities/NetFXCoreWrappers.cs +++ b/Utilities/NetFXCoreWrappers.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; -using System.Threading; using Svelto.DataStructures; namespace Svelto.Utilities diff --git a/WeakEvents/WeakAction.cs b/WeakEvents/WeakAction.cs index 042bf62..e7b6470 100644 --- a/WeakEvents/WeakAction.cs +++ b/WeakEvents/WeakAction.cs @@ -1,6 +1,5 @@ using System; using System.Reflection; -using System.Runtime.CompilerServices; using Svelto.Utilities; namespace Svelto.WeakEvents diff --git a/WeakEvents/WeakActionStruct.cs b/WeakEvents/WeakActionStruct.cs index a073cea..0df2e54 100644 --- a/WeakEvents/WeakActionStruct.cs +++ b/WeakEvents/WeakActionStruct.cs @@ -1,6 +1,5 @@ using System; using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Svelto.Utilities; diff --git a/WeakEvents/WeakEvent.cs b/WeakEvents/WeakEvent.cs index 814f68b..bcef44f 100644 --- a/WeakEvents/WeakEvent.cs +++ b/WeakEvents/WeakEvent.cs @@ -1,7 +1,6 @@ using Svelto.DataStructures; using System; using System.Reflection; -using Svelto.Utilities; namespace Svelto.WeakEvents {