@@ -1,11 +0,0 @@ | |||
#if UNITY_5 || UNITY_5_3_OR_NEWER | |||
namespace Svelto.Context | |||
{ | |||
public interface IUnityCompositionRoot | |||
{ | |||
void OnContextCreated(UnityContext contextHolder); | |||
void OnContextInitialized(); | |||
void OnContextDestroyed(); | |||
} | |||
} | |||
#endif |
@@ -1,16 +0,0 @@ | |||
//------------------------------------------------------------------------------ | |||
// <auto-generated> | |||
// This code was generated by a tool. | |||
// Runtime Version:4.0.30319.18408 | |||
// | |||
// Changes to this file may cause incorrect behavior and will be lost if | |||
// the code is regenerated. | |||
// </auto-generated> | |||
//------------------------------------------------------------------------------ | |||
using System; | |||
public interface IGraphEntityView<T> | |||
{ | |||
void VisitNeighbours(System.Action<T> onVisiting); | |||
} | |||
@@ -1,627 +0,0 @@ | |||
// Uncomment this to enable the following debugging aids: | |||
// LeftLeaningRedBlackTree.HtmlFragment | |||
// LeftLeaningRedBlackTree.EntityView.HtmlFragment | |||
// LeftLeaningRedBlackTree.AssertInvariants | |||
// #define DEBUGGING | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Diagnostics; | |||
/// <summary> | |||
/// Implements a left-leaning red-black tree. | |||
/// </summary> | |||
/// <remarks> | |||
/// Based on the research paper "Left-leaning Red-Black Trees" | |||
/// by Robert Sedgewick. More information available at: | |||
/// http://www.cs.princeton.edu/~rs/talks/LLRB/RedBlack.pdf | |||
/// http://www.cs.princeton.edu/~rs/talks/LLRB/08Penn.pdf | |||
/// </remarks> | |||
/// <typeparam name="TKey">Type of keys.</typeparam> | |||
public class LeftLeaningKeyedRedBlackTree<TKey> where TKey: IComparable<TKey> | |||
{ | |||
/// <summary> | |||
/// Stores the root entityView of the tree. | |||
/// </summary> | |||
private EntityView _rootEntityView; | |||
/// <summary> | |||
/// Represents a entityView of the tree. | |||
/// </summary> | |||
/// <remarks> | |||
/// Using fields instead of properties drops execution time by about 40%. | |||
/// </remarks> | |||
[DebuggerDisplay("Key={Key}")] | |||
private class EntityView | |||
{ | |||
/// <summary> | |||
/// Gets or sets the entityView's key. | |||
/// </summary> | |||
public TKey Key; | |||
/// <summary> | |||
/// Gets or sets the left entityView. | |||
/// </summary> | |||
public EntityView Left; | |||
/// <summary> | |||
/// Gets or sets the right entityView. | |||
/// </summary> | |||
public EntityView Right; | |||
/// <summary> | |||
/// Gets or sets the color of the entityView. | |||
/// </summary> | |||
public bool IsBlack; | |||
#if DEBUGGING | |||
/// <summary> | |||
/// Gets an HTML fragment representing the entityView and its children. | |||
/// </summary> | |||
public string HtmlFragment | |||
{ | |||
get | |||
{ | |||
return | |||
"<table border='1'>" + | |||
"<tr>" + | |||
"<td colspan='2' align='center' bgcolor='" + (IsBlack ? "gray" : "red") + "'>" + Key + ", " + Value + " [" + Siblings + "]</td>" + | |||
"</tr>" + | |||
"<tr>" + | |||
"<td valign='top'>" + (null != Left ? Left.HtmlFragment : "[null]") + "</td>" + | |||
"<td valign='top'>" + (null != Right ? Right.HtmlFragment : "[null]") + "</td>" + | |||
"</tr>" + | |||
"</table>"; | |||
} | |||
} | |||
#endif | |||
} | |||
/// <summary> | |||
/// Adds a key/value pair to the tree. | |||
/// </summary> | |||
/// <param name="key">Key to add.</param> | |||
public void Add(TKey key) | |||
{ | |||
_rootEntityView = Add(_rootEntityView, key); | |||
_rootEntityView.IsBlack = true; | |||
#if DEBUGGING | |||
AssertInvariants(); | |||
#endif | |||
} | |||
/// <summary> | |||
/// Removes a key/value pair from the tree. | |||
/// </summary> | |||
/// <param name="key">Key to remove.</param> | |||
/// <returns>True if key/value present and removed.</returns> | |||
public bool Remove(TKey key) | |||
{ | |||
int initialCount = Count; | |||
if (null != _rootEntityView) | |||
{ | |||
_rootEntityView = Remove(_rootEntityView, key); | |||
if (null != _rootEntityView) | |||
{ | |||
_rootEntityView.IsBlack = true; | |||
} | |||
} | |||
#if DEBUGGING | |||
AssertInvariants(); | |||
#endif | |||
return initialCount != Count; | |||
} | |||
/// <summary> | |||
/// Removes all entityViews in the tree. | |||
/// </summary> | |||
public void Clear() | |||
{ | |||
_rootEntityView = null; | |||
Count = 0; | |||
#if DEBUGGING | |||
AssertInvariants(); | |||
#endif | |||
} | |||
/// <summary> | |||
/// Gets a sorted list of keys in the tree. | |||
/// </summary> | |||
/// <returns>Sorted list of keys.</returns> | |||
public IEnumerable<TKey> GetKeys() | |||
{ | |||
TKey lastKey = default(TKey); | |||
bool lastKeyValid = false; | |||
return Traverse( | |||
_rootEntityView, | |||
n => !lastKeyValid || !object.Equals(lastKey, n.Key), | |||
n => | |||
{ | |||
lastKey = n.Key; | |||
lastKeyValid = true; | |||
return lastKey; | |||
}); | |||
} | |||
/// <summary> | |||
/// Gets the count of key/value pairs in the tree. | |||
/// </summary> | |||
public int Count { get; private set; } | |||
/// <summary> | |||
/// Gets the minimum key in the tree. | |||
/// </summary> | |||
public TKey MinimumKey | |||
{ | |||
get { return GetExtreme(_rootEntityView, n => n.Left, n => n.Key); } | |||
} | |||
/// <summary> | |||
/// Gets the maximum key in the tree. | |||
/// </summary> | |||
public TKey MaximumKey | |||
{ | |||
get { return GetExtreme(_rootEntityView, n => n.Right, n => n.Key); } | |||
} | |||
/// <summary> | |||
/// Returns true if the specified entityView is red. | |||
/// </summary> | |||
/// <param name="entityView">Specified entityView.</param> | |||
/// <returns>True if specified entityView is red.</returns> | |||
private static bool IsRed(EntityView entityView) | |||
{ | |||
if (null == entityView) | |||
{ | |||
// "Virtual" leaf entityViews are always black | |||
return false; | |||
} | |||
return !entityView.IsBlack; | |||
} | |||
/// <summary> | |||
/// Adds the specified key/value pair below the specified root entityView. | |||
/// </summary> | |||
/// <param name="entityView">Specified entityView.</param> | |||
/// <param name="key">Key to add.</param> | |||
/// <param name="value">Value to add.</param> | |||
/// <returns>New root entityView.</returns> | |||
private EntityView Add(EntityView entityView, TKey key) | |||
{ | |||
if (null == entityView) | |||
{ | |||
// Insert new entityView | |||
Count++; | |||
return new EntityView { Key = key }; | |||
} | |||
if (IsRed(entityView.Left) && IsRed(entityView.Right)) | |||
{ | |||
// Split entityView with two red children | |||
FlipColor(entityView); | |||
} | |||
// Find right place for new entityView | |||
int comparisonResult = KeyComparison(key, entityView.Key); | |||
if (comparisonResult < 0) | |||
{ | |||
entityView.Left = Add(entityView.Left, key); | |||
} | |||
else if (0 < comparisonResult) | |||
{ | |||
entityView.Right = Add(entityView.Right, key); | |||
} | |||
if (IsRed(entityView.Right)) | |||
{ | |||
// Rotate to prevent red entityView on right | |||
entityView = RotateLeft(entityView); | |||
} | |||
if (IsRed(entityView.Left) && IsRed(entityView.Left.Left)) | |||
{ | |||
// Rotate to prevent consecutive red entityViews | |||
entityView = RotateRight(entityView); | |||
} | |||
return entityView; | |||
} | |||
/// <summary> | |||
/// Removes the specified key/value pair from below the specified entityView. | |||
/// </summary> | |||
/// <param name="entityView">Specified entityView.</param> | |||
/// <param name="key">Key to remove.</param> | |||
/// <returns>True if key/value present and removed.</returns> | |||
private EntityView Remove(EntityView entityView, TKey key) | |||
{ | |||
int comparisonResult = KeyComparison(key, entityView.Key); | |||
if (comparisonResult < 0) | |||
{ | |||
// * Continue search if left is present | |||
if (null != entityView.Left) | |||
{ | |||
if (!IsRed(entityView.Left) && !IsRed(entityView.Left.Left)) | |||
{ | |||
// Move a red entityView over | |||
entityView = MoveRedLeft(entityView); | |||
} | |||
// Remove from left | |||
entityView.Left = Remove(entityView.Left, key); | |||
} | |||
} | |||
else | |||
{ | |||
if (IsRed(entityView.Left)) | |||
{ | |||
// Flip a 3 entityView or unbalance a 4 entityView | |||
entityView = RotateRight(entityView); | |||
} | |||
if ((0 == KeyComparison(key, entityView.Key)) && (null == entityView.Right)) | |||
{ | |||
// Remove leaf entityView | |||
Debug.Assert(null == entityView.Left, "About to remove an extra entityView."); | |||
Count--; | |||
// Leaf entityView is gone | |||
return null; | |||
} | |||
// * Continue search if right is present | |||
if (null != entityView.Right) | |||
{ | |||
if (!IsRed(entityView.Right) && !IsRed(entityView.Right.Left)) | |||
{ | |||
// Move a red entityView over | |||
entityView = MoveRedRight(entityView); | |||
} | |||
if (0 == KeyComparison(key, entityView.Key)) | |||
{ | |||
// Remove leaf entityView | |||
Count--; | |||
// 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 | |||
entityView.Right = Remove(entityView.Right, key); | |||
} | |||
} | |||
} | |||
// Maintain invariants | |||
return FixUp(entityView); | |||
} | |||
/// <summary> | |||
/// Flip the colors of the specified entityView and its direct children. | |||
/// </summary> | |||
/// <param name="entityView">Specified entityView.</param> | |||
private static void FlipColor(EntityView entityView) | |||
{ | |||
entityView.IsBlack = !entityView.IsBlack; | |||
entityView.Left.IsBlack = !entityView.Left.IsBlack; | |||
entityView.Right.IsBlack = !entityView.Right.IsBlack; | |||
} | |||
/// <summary> | |||
/// Rotate the specified entityView "left". | |||
/// </summary> | |||
/// <param name="entityView">Specified entityView.</param> | |||
/// <returns>New root entityView.</returns> | |||
private static EntityView RotateLeft(EntityView entityView) | |||
{ | |||
EntityView x = entityView.Right; | |||
entityView.Right = x.Left; | |||
x.Left = entityView; | |||
x.IsBlack = entityView.IsBlack; | |||
entityView.IsBlack = false; | |||
return x; | |||
} | |||
/// <summary> | |||
/// Rotate the specified entityView "right". | |||
/// </summary> | |||
/// <param name="entityView">Specified entityView.</param> | |||
/// <returns>New root entityView.</returns> | |||
private static EntityView RotateRight(EntityView entityView) | |||
{ | |||
EntityView x = entityView.Left; | |||
entityView.Left = x.Right; | |||
x.Right = entityView; | |||
x.IsBlack = entityView.IsBlack; | |||
entityView.IsBlack = false; | |||
return x; | |||
} | |||
/// <summary> | |||
/// Moves a red entityView from the right child to the left child. | |||
/// </summary> | |||
/// <param name="entityView">Parent entityView.</param> | |||
/// <returns>New root entityView.</returns> | |||
private static EntityView MoveRedLeft(EntityView entityView) | |||
{ | |||
FlipColor(entityView); | |||
if (IsRed(entityView.Right.Left)) | |||
{ | |||
entityView.Right = RotateRight(entityView.Right); | |||
entityView = RotateLeft(entityView); | |||
FlipColor(entityView); | |||
// * Avoid creating right-leaning entityViews | |||
if (IsRed(entityView.Right.Right)) | |||
{ | |||
entityView.Right = RotateLeft(entityView.Right); | |||
} | |||
} | |||
return entityView; | |||
} | |||
/// <summary> | |||
/// Moves a red entityView from the left child to the right child. | |||
/// </summary> | |||
/// <param name="entityView">Parent entityView.</param> | |||
/// <returns>New root entityView.</returns> | |||
private static EntityView MoveRedRight(EntityView entityView) | |||
{ | |||
FlipColor(entityView); | |||
if (IsRed(entityView.Left.Left)) | |||
{ | |||
entityView = RotateRight(entityView); | |||
FlipColor(entityView); | |||
} | |||
return entityView; | |||
} | |||
/// <summary> | |||
/// Deletes the minimum entityView under the specified entityView. | |||
/// </summary> | |||
/// <param name="entityView">Specified entityView.</param> | |||
/// <returns>New root entityView.</returns> | |||
private EntityView DeleteMinimum(EntityView entityView) | |||
{ | |||
if (null == entityView.Left) | |||
{ | |||
// Nothing to do | |||
return null; | |||
} | |||
if (!IsRed(entityView.Left) && !IsRed(entityView.Left.Left)) | |||
{ | |||
// Move red entityView left | |||
entityView = MoveRedLeft(entityView); | |||
} | |||
// Recursively delete | |||
entityView.Left = DeleteMinimum(entityView.Left); | |||
// Maintain invariants | |||
return FixUp(entityView); | |||
} | |||
/// <summary> | |||
/// Maintains invariants by adjusting the specified entityViews children. | |||
/// </summary> | |||
/// <param name="entityView">Specified entityView.</param> | |||
/// <returns>New root entityView.</returns> | |||
private static EntityView FixUp(EntityView entityView) | |||
{ | |||
if (IsRed(entityView.Right)) | |||
{ | |||
// Avoid right-leaning entityView | |||
entityView = RotateLeft(entityView); | |||
} | |||
if (IsRed(entityView.Left) && IsRed(entityView.Left.Left)) | |||
{ | |||
// Balance 4-entityView | |||
entityView = RotateRight(entityView); | |||
} | |||
if (IsRed(entityView.Left) && IsRed(entityView.Right)) | |||
{ | |||
// Push red up | |||
FlipColor(entityView); | |||
} | |||
// * Avoid leaving behind right-leaning entityViews | |||
if ((null != entityView.Left) && IsRed(entityView.Left.Right) && !IsRed(entityView.Left.Left)) | |||
{ | |||
entityView.Left = RotateLeft(entityView.Left); | |||
if (IsRed(entityView.Left)) | |||
{ | |||
// Balance 4-entityView | |||
entityView = RotateRight(entityView); | |||
} | |||
} | |||
return entityView; | |||
} | |||
/// <summary> | |||
/// Gets the (first) entityView corresponding to the specified key. | |||
/// </summary> | |||
/// <param name="key">Key to search for.</param> | |||
/// <returns>Corresponding entityView or null if none found.</returns> | |||
private EntityView GetEntityViewForKey(TKey key) | |||
{ | |||
// Initialize | |||
EntityView entityView = _rootEntityView; | |||
while (null != entityView) | |||
{ | |||
// Compare keys and go left/right | |||
int comparisonResult = key.CompareTo(entityView.Key); | |||
if (comparisonResult < 0) | |||
{ | |||
entityView = entityView.Left; | |||
} | |||
else if (0 < comparisonResult) | |||
{ | |||
entityView = entityView.Right; | |||
} | |||
else | |||
{ | |||
// Match; return entityView | |||
return entityView; | |||
} | |||
} | |||
// No match found | |||
return null; | |||
} | |||
/// <summary> | |||
/// Gets an extreme (ex: minimum/maximum) value. | |||
/// </summary> | |||
/// <typeparam name="T">Type of value.</typeparam> | |||
/// <param name="entityView">EntityView to start from.</param> | |||
/// <param name="successor">Successor function.</param> | |||
/// <param name="selector">Selector function.</param> | |||
/// <returns>Extreme value.</returns> | |||
private static T GetExtreme<T>(EntityView entityView, Func<EntityView, EntityView> successor, Func<EntityView, T> selector) | |||
{ | |||
// Initialize | |||
T extreme = default(T); | |||
EntityView current = entityView; | |||
while (null != current) | |||
{ | |||
// Go to extreme | |||
extreme = selector(current); | |||
current = successor(current); | |||
} | |||
return extreme; | |||
} | |||
/// <summary> | |||
/// Traverses a subset of the sequence of entityViews in order and selects the specified entityViews. | |||
/// </summary> | |||
/// <typeparam name="T">Type of elements.</typeparam> | |||
/// <param name="entityView">Starting entityView.</param> | |||
/// <param name="condition">Condition method.</param> | |||
/// <param name="selector">Selector method.</param> | |||
/// <returns>Sequence of selected entityViews.</returns> | |||
private IEnumerable<T> Traverse<T>(EntityView entityView, Func<EntityView, bool> condition, Func<EntityView, T> selector) | |||
{ | |||
// Create a stack to avoid recursion | |||
Stack<EntityView> stack = new Stack<EntityView>(); | |||
EntityView current = entityView; | |||
while (null != current) | |||
{ | |||
if (null != current.Left) | |||
{ | |||
// Save current state and go left | |||
stack.Push(current); | |||
current = current.Left; | |||
} | |||
else | |||
{ | |||
do | |||
{ | |||
// Select current entityView if relevant | |||
if (condition(current)) | |||
{ | |||
yield return selector(current); | |||
} | |||
// Go right - or up if nothing to the right | |||
current = current.Right; | |||
} | |||
while ((null == current) && | |||
(0 < stack.Count) && | |||
(null != (current = stack.Pop()))); | |||
} | |||
} | |||
} | |||
/// <summary> | |||
/// Compares the specified keys (primary) and values (secondary). | |||
/// </summary> | |||
/// <param name="leftKey">The left key.</param> | |||
/// <param name="rightKey">The right key.</param> | |||
/// <returns>CompareTo-style results: -1 if left is less, 0 if equal, and 1 if greater than right.</returns> | |||
private int KeyComparison(TKey leftKey, TKey rightKey) | |||
{ | |||
return leftKey.CompareTo(rightKey); | |||
} | |||
#if DEBUGGING | |||
/// <summary> | |||
/// Asserts that tree invariants are not violated. | |||
/// </summary> | |||
private void AssertInvariants() | |||
{ | |||
// Root is black | |||
Debug.Assert((null == _rootEntityView) || _rootEntityView.IsBlack, "Root is not black"); | |||
// Every path contains the same number of black entityViews | |||
Dictionary<EntityView, EntityView> parents = new Dictionary<LeftLeaningRedBlackTree<TKey, TValue>.EntityView, LeftLeaningRedBlackTree<TKey, TValue>.EntityView>(); | |||
foreach (EntityView entityView in Traverse(_rootEntityView, n => true, n => n)) | |||
{ | |||
if (null != entityView.Left) | |||
{ | |||
parents[entityView.Left] = entityView; | |||
} | |||
if (null != entityView.Right) | |||
{ | |||
parents[entityView.Right] = entityView; | |||
} | |||
} | |||
if (null != _rootEntityView) | |||
{ | |||
parents[_rootEntityView] = null; | |||
} | |||
int treeCount = -1; | |||
foreach (EntityView entityView in Traverse(_rootEntityView, n => (null == n.Left) || (null == n.Right), n => n)) | |||
{ | |||
int pathCount = 0; | |||
EntityView current = entityView; | |||
while (null != current) | |||
{ | |||
if (current.IsBlack) | |||
{ | |||
pathCount++; | |||
} | |||
current = parents[current]; | |||
} | |||
Debug.Assert((-1 == treeCount) || (pathCount == treeCount), "Not all paths have the same number of black entityViews."); | |||
treeCount = pathCount; | |||
} | |||
// Verify entityView properties... | |||
foreach (EntityView entityView in Traverse(_rootEntityView, n => true, n => n)) | |||
{ | |||
// Left entityView is less | |||
if (null != entityView.Left) | |||
{ | |||
Debug.Assert(0 > KeyAndValueComparison(entityView.Left.Key, entityView.Left.Value, entityView.Key, entityView.Value), "Left entityView is greater than its parent."); | |||
} | |||
// Right entityView is greater | |||
if (null != entityView.Right) | |||
{ | |||
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 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(entityView.Right) || IsRed(entityView.Left), "EntityView is not left-leaning."); | |||
// No consecutive reds (subset of previous rule) | |||
//Debug.Assert(!(IsRed(entityView) && IsRed(entityView.Left))); | |||
} | |||
} | |||
/// <summary> | |||
/// Gets an HTML fragment representing the tree. | |||
/// </summary> | |||
public string HtmlDocument | |||
{ | |||
get | |||
{ | |||
return | |||
"<html>" + | |||
"<body>" + | |||
(null != _rootEntityView ? _rootEntityView.HtmlFragment : "[null]") + | |||
"</body>" + | |||
"</html>"; | |||
} | |||
} | |||
#endif | |||
} |
@@ -1,789 +0,0 @@ | |||
// Uncomment this to enable the following debugging aids: | |||
// LeftLeaningRedBlackTree.HtmlFragment | |||
// LeftLeaningRedBlackTree.EntityView.HtmlFragment | |||
// LeftLeaningRedBlackTree.AssertInvariants | |||
// #define DEBUGGING | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Diagnostics; | |||
/// <summary> | |||
/// Implements a left-leaning red-black tree. | |||
/// </summary> | |||
/// <remarks> | |||
/// Based on the research paper "Left-leaning Red-Black Trees" | |||
/// by Robert Sedgewick. More information available at: | |||
/// http://www.cs.princeton.edu/~rs/talks/LLRB/RedBlack.pdf | |||
/// http://www.cs.princeton.edu/~rs/talks/LLRB/08Penn.pdf | |||
/// </remarks> | |||
/// <typeparam name="TKey">Type of keys.</typeparam> | |||
/// <typeparam name="TValue">Type of values.</typeparam> | |||
public class LeftLeaningRedBlackTree<TKey, TValue> | |||
{ | |||
/// <summary> | |||
/// Stores the key comparison function. | |||
/// </summary> | |||
private Comparison<TKey> _keyComparison; | |||
/// <summary> | |||
/// Stores the value comparison function. | |||
/// </summary> | |||
private Comparison<TValue> _valueComparison; | |||
/// <summary> | |||
/// Stores the root entityView of the tree. | |||
/// </summary> | |||
private EntityView _rootEntityView; | |||
/// <summary> | |||
/// Represents a entityView of the tree. | |||
/// </summary> | |||
/// <remarks> | |||
/// Using fields instead of properties drops execution time by about 40%. | |||
/// </remarks> | |||
[DebuggerDisplay("Key={Key}, Value={Value}, Siblings={Siblings}")] | |||
private class EntityView | |||
{ | |||
/// <summary> | |||
/// Gets or sets the entityView's key. | |||
/// </summary> | |||
public TKey Key; | |||
/// <summary> | |||
/// Gets or sets the entityView's value. | |||
/// </summary> | |||
public TValue Value; | |||
/// <summary> | |||
/// Gets or sets the left entityView. | |||
/// </summary> | |||
public EntityView Left; | |||
/// <summary> | |||
/// Gets or sets the right entityView. | |||
/// </summary> | |||
public EntityView Right; | |||
/// <summary> | |||
/// Gets or sets the color of the entityView. | |||
/// </summary> | |||
public bool IsBlack; | |||
/// <summary> | |||
/// Gets or sets the number of "siblings" (entityViews with the same key/value). | |||
/// </summary> | |||
public int Siblings; | |||
#if DEBUGGING | |||
/// <summary> | |||
/// Gets an HTML fragment representing the entityView and its children. | |||
/// </summary> | |||
public string HtmlFragment | |||
{ | |||
get | |||
{ | |||
return | |||
"<table border='1'>" + | |||
"<tr>" + | |||
"<td colspan='2' align='center' bgcolor='" + (IsBlack ? "gray" : "red") + "'>" + Key + ", " + Value + " [" + Siblings + "]</td>" + | |||
"</tr>" + | |||
"<tr>" + | |||
"<td valign='top'>" + (null != Left ? Left.HtmlFragment : "[null]") + "</td>" + | |||
"<td valign='top'>" + (null != Right ? Right.HtmlFragment : "[null]") + "</td>" + | |||
"</tr>" + | |||
"</table>"; | |||
} | |||
} | |||
#endif | |||
} | |||
/// <summary> | |||
/// Initializes a new instance of the LeftLeaningRedBlackTree class implementing a normal dictionary. | |||
/// </summary> | |||
/// <param name="keyComparison">The key comparison function.</param> | |||
public LeftLeaningRedBlackTree(Comparison<TKey> keyComparison) | |||
{ | |||
if (null == keyComparison) | |||
{ | |||
throw new ArgumentNullException("keyComparison"); | |||
} | |||
_keyComparison = keyComparison; | |||
} | |||
/// <summary> | |||
/// Initializes a new instance of the LeftLeaningRedBlackTree class implementing an ordered multi-dictionary. | |||
/// </summary> | |||
/// <param name="keyComparison">The key comparison function.</param> | |||
/// <param name="valueComparison">The value comparison function.</param> | |||
public LeftLeaningRedBlackTree(Comparison<TKey> keyComparison, Comparison<TValue> valueComparison) | |||
: this(keyComparison) | |||
{ | |||
if (null == valueComparison) | |||
{ | |||
throw new ArgumentNullException("valueComparison"); | |||
} | |||
_valueComparison = valueComparison; | |||
} | |||
/// <summary> | |||
/// Gets a value indicating whether the tree is acting as an ordered multi-dictionary. | |||
/// </summary> | |||
private bool IsMultiDictionary | |||
{ | |||
get { return null != _valueComparison; } | |||
} | |||
/// <summary> | |||
/// Adds a key/value pair to the tree. | |||
/// </summary> | |||
/// <param name="key">Key to add.</param> | |||
/// <param name="value">Value to add.</param> | |||
public void Add(TKey key, TValue value) | |||
{ | |||
_rootEntityView = Add(_rootEntityView, key, value); | |||
_rootEntityView.IsBlack = true; | |||
#if DEBUGGING | |||
AssertInvariants(); | |||
#endif | |||
} | |||
/// <summary> | |||
/// Removes a key (and its associated value) from a normal (non-multi) dictionary. | |||
/// </summary> | |||
/// <param name="key">Key to remove.</param> | |||
/// <returns>True if key present and removed.</returns> | |||
public bool Remove(TKey key) | |||
{ | |||
if (IsMultiDictionary) | |||
{ | |||
throw new InvalidOperationException("Remove is only supported when acting as a normal (non-multi) dictionary."); | |||
} | |||
return Remove(key, default(TValue)); | |||
} | |||
/// <summary> | |||
/// Removes a key/value pair from the tree. | |||
/// </summary> | |||
/// <param name="key">Key to remove.</param> | |||
/// <param name="value">Value to remove.</param> | |||
/// <returns>True if key/value present and removed.</returns> | |||
public bool Remove(TKey key, TValue value) | |||
{ | |||
int initialCount = Count; | |||
if (null != _rootEntityView) | |||
{ | |||
_rootEntityView = Remove(_rootEntityView, key, value); | |||
if (null != _rootEntityView) | |||
{ | |||
_rootEntityView.IsBlack = true; | |||
} | |||
} | |||
#if DEBUGGING | |||
AssertInvariants(); | |||
#endif | |||
return initialCount != Count; | |||
} | |||
/// <summary> | |||
/// Removes all entityViews in the tree. | |||
/// </summary> | |||
public void Clear() | |||
{ | |||
_rootEntityView = null; | |||
Count = 0; | |||
#if DEBUGGING | |||
AssertInvariants(); | |||
#endif | |||
} | |||
/// <summary> | |||
/// Gets a sorted list of keys in the tree. | |||
/// </summary> | |||
/// <returns>Sorted list of keys.</returns> | |||
public IEnumerable<TKey> GetKeys() | |||
{ | |||
TKey lastKey = default(TKey); | |||
bool lastKeyValid = false; | |||
return Traverse( | |||
_rootEntityView, | |||
n => !lastKeyValid || !object.Equals(lastKey, n.Key), | |||
n => | |||
{ | |||
lastKey = n.Key; | |||
lastKeyValid = true; | |||
return lastKey; | |||
}); | |||
} | |||
/// <summary> | |||
/// Gets the value associated with the specified key in a normal (non-multi) dictionary. | |||
/// </summary> | |||
/// <param name="key">Specified key.</param> | |||
/// <returns>Value associated with the specified key.</returns> | |||
public TValue GetValueForKey(TKey key) | |||
{ | |||
if (IsMultiDictionary) | |||
{ | |||
throw new InvalidOperationException("GetValueForKey is only supported when acting as a normal (non-multi) dictionary."); | |||
} | |||
EntityView entityView = GetEntityViewForKey(key); | |||
if (null != entityView) | |||
{ | |||
return entityView.Value; | |||
} | |||
else | |||
{ | |||
throw new KeyNotFoundException(); | |||
} | |||
} | |||
/// <summary> | |||
/// Gets a sequence of the values associated with the specified key. | |||
/// </summary> | |||
/// <param name="key">Specified key.</param> | |||
/// <returns>Sequence of values.</returns> | |||
public IEnumerable<TValue> GetValuesForKey(TKey key) | |||
{ | |||
return Traverse(GetEntityViewForKey(key), n => 0 == _keyComparison(n.Key, key), n => n.Value); | |||
} | |||
/// <summary> | |||
/// Gets a sequence of all the values in the tree. | |||
/// </summary> | |||
/// <returns>Sequence of all values.</returns> | |||
public IEnumerable<TValue> GetValuesForAllKeys() | |||
{ | |||
return Traverse(_rootEntityView, n => true, n => n.Value); | |||
} | |||
/// <summary> | |||
/// Gets the count of key/value pairs in the tree. | |||
/// </summary> | |||
public int Count { get; private set; } | |||
/// <summary> | |||
/// Gets the minimum key in the tree. | |||
/// </summary> | |||
public TKey MinimumKey | |||
{ | |||
get { return GetExtreme(_rootEntityView, n => n.Left, n => n.Key); } | |||
} | |||
/// <summary> | |||
/// Gets the maximum key in the tree. | |||
/// </summary> | |||
public TKey MaximumKey | |||
{ | |||
get { return GetExtreme(_rootEntityView, n => n.Right, n => n.Key); } | |||
} | |||
/// <summary> | |||
/// Returns true if the specified entityView is red. | |||
/// </summary> | |||
/// <param name="entityView">Specified entityView.</param> | |||
/// <returns>True if specified entityView is red.</returns> | |||
private static bool IsRed(EntityView entityView) | |||
{ | |||
if (null == entityView) | |||
{ | |||
// "Virtual" leaf entityViews are always black | |||
return false; | |||
} | |||
return !entityView.IsBlack; | |||
} | |||
/// <summary> | |||
/// Adds the specified key/value pair below the specified root entityView. | |||
/// </summary> | |||
/// <param name="entityView">Specified entityView.</param> | |||
/// <param name="key">Key to add.</param> | |||
/// <param name="value">Value to add.</param> | |||
/// <returns>New root entityView.</returns> | |||
private EntityView Add(EntityView entityView, TKey key, TValue value) | |||
{ | |||
if (null == entityView) | |||
{ | |||
// Insert new entityView | |||
Count++; | |||
return new EntityView { Key = key, Value = value }; | |||
} | |||
if (IsRed(entityView.Left) && IsRed(entityView.Right)) | |||
{ | |||
// Split entityView with two red children | |||
FlipColor(entityView); | |||
} | |||
// Find right place for new entityView | |||
int comparisonResult = KeyAndValueComparison(key, value, entityView.Key, entityView.Value); | |||
if (comparisonResult < 0) | |||
{ | |||
entityView.Left = Add(entityView.Left, key, value); | |||
} | |||
else if (0 < comparisonResult) | |||
{ | |||
entityView.Right = Add(entityView.Right, key, value); | |||
} | |||
else | |||
{ | |||
if (IsMultiDictionary) | |||
{ | |||
// Store the presence of a "duplicate" entityView | |||
entityView.Siblings++; | |||
Count++; | |||
} | |||
else | |||
{ | |||
// Replace the value of the existing entityView | |||
entityView.Value = value; | |||
} | |||
} | |||
if (IsRed(entityView.Right)) | |||
{ | |||
// Rotate to prevent red entityView on right | |||
entityView = RotateLeft(entityView); | |||
} | |||
if (IsRed(entityView.Left) && IsRed(entityView.Left.Left)) | |||
{ | |||
// Rotate to prevent consecutive red entityViews | |||
entityView = RotateRight(entityView); | |||
} | |||
return entityView; | |||
} | |||
/// <summary> | |||
/// Removes the specified key/value pair from below the specified entityView. | |||
/// </summary> | |||
/// <param name="entityView">Specified entityView.</param> | |||
/// <param name="key">Key to remove.</param> | |||
/// <param name="value">Value to remove.</param> | |||
/// <returns>True if key/value present and removed.</returns> | |||
private EntityView Remove(EntityView entityView, TKey key, TValue value) | |||
{ | |||
int comparisonResult = KeyAndValueComparison(key, value, entityView.Key, entityView.Value); | |||
if (comparisonResult < 0) | |||
{ | |||
// * Continue search if left is present | |||
if (null != entityView.Left) | |||
{ | |||
if (!IsRed(entityView.Left) && !IsRed(entityView.Left.Left)) | |||
{ | |||
// Move a red entityView over | |||
entityView = MoveRedLeft(entityView); | |||
} | |||
// Remove from left | |||
entityView.Left = Remove(entityView.Left, key, value); | |||
} | |||
} | |||
else | |||
{ | |||
if (IsRed(entityView.Left)) | |||
{ | |||
// Flip a 3 entityView or unbalance a 4 entityView | |||
entityView = RotateRight(entityView); | |||
} | |||
if ((0 == KeyAndValueComparison(key, value, entityView.Key, entityView.Value)) && (null == entityView.Right)) | |||
{ | |||
// Remove leaf entityView | |||
Debug.Assert(null == entityView.Left, "About to remove an extra entityView."); | |||
Count--; | |||
if (0 < entityView.Siblings) | |||
{ | |||
// Record the removal of the "duplicate" entityView | |||
Debug.Assert(IsMultiDictionary, "Should not have siblings if tree is not a multi-dictionary."); | |||
entityView.Siblings--; | |||
return entityView; | |||
} | |||
else | |||
{ | |||
// Leaf entityView is gone | |||
return null; | |||
} | |||
} | |||
// * Continue search if right is present | |||
if (null != entityView.Right) | |||
{ | |||
if (!IsRed(entityView.Right) && !IsRed(entityView.Right.Left)) | |||
{ | |||
// Move a red entityView over | |||
entityView = MoveRedRight(entityView); | |||
} | |||
if (0 == KeyAndValueComparison(key, value, entityView.Key, entityView.Value)) | |||
{ | |||
// Remove leaf entityView | |||
Count--; | |||
if (0 < entityView.Siblings) | |||
{ | |||
// Record the removal of the "duplicate" entityView | |||
Debug.Assert(IsMultiDictionary, "Should not have siblings if tree is not a multi-dictionary."); | |||
entityView.Siblings--; | |||
} | |||
else | |||
{ | |||
// 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 | |||
entityView.Right = Remove(entityView.Right, key, value); | |||
} | |||
} | |||
} | |||
// Maintain invariants | |||
return FixUp(entityView); | |||
} | |||
/// <summary> | |||
/// Flip the colors of the specified entityView and its direct children. | |||
/// </summary> | |||
/// <param name="entityView">Specified entityView.</param> | |||
private static void FlipColor(EntityView entityView) | |||
{ | |||
entityView.IsBlack = !entityView.IsBlack; | |||
entityView.Left.IsBlack = !entityView.Left.IsBlack; | |||
entityView.Right.IsBlack = !entityView.Right.IsBlack; | |||
} | |||
/// <summary> | |||
/// Rotate the specified entityView "left". | |||
/// </summary> | |||
/// <param name="entityView">Specified entityView.</param> | |||
/// <returns>New root entityView.</returns> | |||
private static EntityView RotateLeft(EntityView entityView) | |||
{ | |||
EntityView x = entityView.Right; | |||
entityView.Right = x.Left; | |||
x.Left = entityView; | |||
x.IsBlack = entityView.IsBlack; | |||
entityView.IsBlack = false; | |||
return x; | |||
} | |||
/// <summary> | |||
/// Rotate the specified entityView "right". | |||
/// </summary> | |||
/// <param name="entityView">Specified entityView.</param> | |||
/// <returns>New root entityView.</returns> | |||
private static EntityView RotateRight(EntityView entityView) | |||
{ | |||
EntityView x = entityView.Left; | |||
entityView.Left = x.Right; | |||
x.Right = entityView; | |||
x.IsBlack = entityView.IsBlack; | |||
entityView.IsBlack = false; | |||
return x; | |||
} | |||
/// <summary> | |||
/// Moves a red entityView from the right child to the left child. | |||
/// </summary> | |||
/// <param name="entityView">Parent entityView.</param> | |||
/// <returns>New root entityView.</returns> | |||
private static EntityView MoveRedLeft(EntityView entityView) | |||
{ | |||
FlipColor(entityView); | |||
if (IsRed(entityView.Right.Left)) | |||
{ | |||
entityView.Right = RotateRight(entityView.Right); | |||
entityView = RotateLeft(entityView); | |||
FlipColor(entityView); | |||
// * Avoid creating right-leaning entityViews | |||
if (IsRed(entityView.Right.Right)) | |||
{ | |||
entityView.Right = RotateLeft(entityView.Right); | |||
} | |||
} | |||
return entityView; | |||
} | |||
/// <summary> | |||
/// Moves a red entityView from the left child to the right child. | |||
/// </summary> | |||
/// <param name="entityView">Parent entityView.</param> | |||
/// <returns>New root entityView.</returns> | |||
private static EntityView MoveRedRight(EntityView entityView) | |||
{ | |||
FlipColor(entityView); | |||
if (IsRed(entityView.Left.Left)) | |||
{ | |||
entityView = RotateRight(entityView); | |||
FlipColor(entityView); | |||
} | |||
return entityView; | |||
} | |||
/// <summary> | |||
/// Deletes the minimum entityView under the specified entityView. | |||
/// </summary> | |||
/// <param name="entityView">Specified entityView.</param> | |||
/// <returns>New root entityView.</returns> | |||
private EntityView DeleteMinimum(EntityView entityView) | |||
{ | |||
if (null == entityView.Left) | |||
{ | |||
// Nothing to do | |||
return null; | |||
} | |||
if (!IsRed(entityView.Left) && !IsRed(entityView.Left.Left)) | |||
{ | |||
// Move red entityView left | |||
entityView = MoveRedLeft(entityView); | |||
} | |||
// Recursively delete | |||
entityView.Left = DeleteMinimum(entityView.Left); | |||
// Maintain invariants | |||
return FixUp(entityView); | |||
} | |||
/// <summary> | |||
/// Maintains invariants by adjusting the specified entityViews children. | |||
/// </summary> | |||
/// <param name="entityView">Specified entityView.</param> | |||
/// <returns>New root entityView.</returns> | |||
private static EntityView FixUp(EntityView entityView) | |||
{ | |||
if (IsRed(entityView.Right)) | |||
{ | |||
// Avoid right-leaning entityView | |||
entityView = RotateLeft(entityView); | |||
} | |||
if (IsRed(entityView.Left) && IsRed(entityView.Left.Left)) | |||
{ | |||
// Balance 4-entityView | |||
entityView = RotateRight(entityView); | |||
} | |||
if (IsRed(entityView.Left) && IsRed(entityView.Right)) | |||
{ | |||
// Push red up | |||
FlipColor(entityView); | |||
} | |||
// * Avoid leaving behind right-leaning entityViews | |||
if ((null != entityView.Left) && IsRed(entityView.Left.Right) && !IsRed(entityView.Left.Left)) | |||
{ | |||
entityView.Left = RotateLeft(entityView.Left); | |||
if (IsRed(entityView.Left)) | |||
{ | |||
// Balance 4-entityView | |||
entityView = RotateRight(entityView); | |||
} | |||
} | |||
return entityView; | |||
} | |||
/// <summary> | |||
/// Gets the (first) entityView corresponding to the specified key. | |||
/// </summary> | |||
/// <param name="key">Key to search for.</param> | |||
/// <returns>Corresponding entityView or null if none found.</returns> | |||
private EntityView GetEntityViewForKey(TKey key) | |||
{ | |||
// Initialize | |||
EntityView entityView = _rootEntityView; | |||
while (null != entityView) | |||
{ | |||
// Compare keys and go left/right | |||
int comparisonResult = _keyComparison(key, entityView.Key); | |||
if (comparisonResult < 0) | |||
{ | |||
entityView = entityView.Left; | |||
} | |||
else if (0 < comparisonResult) | |||
{ | |||
entityView = entityView.Right; | |||
} | |||
else | |||
{ | |||
// Match; return entityView | |||
return entityView; | |||
} | |||
} | |||
// No match found | |||
return null; | |||
} | |||
/// <summary> | |||
/// Gets an extreme (ex: minimum/maximum) value. | |||
/// </summary> | |||
/// <typeparam name="T">Type of value.</typeparam> | |||
/// <param name="entityView">EntityView to start from.</param> | |||
/// <param name="successor">Successor function.</param> | |||
/// <param name="selector">Selector function.</param> | |||
/// <returns>Extreme value.</returns> | |||
private static T GetExtreme<T>(EntityView entityView, Func<EntityView, EntityView> successor, Func<EntityView, T> selector) | |||
{ | |||
// Initialize | |||
T extreme = default(T); | |||
EntityView current = entityView; | |||
while (null != current) | |||
{ | |||
// Go to extreme | |||
extreme = selector(current); | |||
current = successor(current); | |||
} | |||
return extreme; | |||
} | |||
/// <summary> | |||
/// Traverses a subset of the sequence of entityViews in order and selects the specified entityViews. | |||
/// </summary> | |||
/// <typeparam name="T">Type of elements.</typeparam> | |||
/// <param name="entityView">Starting entityView.</param> | |||
/// <param name="condition">Condition method.</param> | |||
/// <param name="selector">Selector method.</param> | |||
/// <returns>Sequence of selected entityViews.</returns> | |||
private IEnumerable<T> Traverse<T>(EntityView entityView, Func<EntityView, bool> condition, Func<EntityView, T> selector) | |||
{ | |||
// Create a stack to avoid recursion | |||
Stack<EntityView> stack = new Stack<EntityView>(); | |||
EntityView current = entityView; | |||
while (null != current) | |||
{ | |||
if (null != current.Left) | |||
{ | |||
// Save current state and go left | |||
stack.Push(current); | |||
current = current.Left; | |||
} | |||
else | |||
{ | |||
do | |||
{ | |||
for (int i = 0; i <= current.Siblings; i++) | |||
{ | |||
// Select current entityView if relevant | |||
if (condition(current)) | |||
{ | |||
yield return selector(current); | |||
} | |||
} | |||
// Go right - or up if nothing to the right | |||
current = current.Right; | |||
} | |||
while ((null == current) && | |||
(0 < stack.Count) && | |||
(null != (current = stack.Pop()))); | |||
} | |||
} | |||
} | |||
/// <summary> | |||
/// Compares the specified keys (primary) and values (secondary). | |||
/// </summary> | |||
/// <param name="leftKey">The left key.</param> | |||
/// <param name="leftValue">The left value.</param> | |||
/// <param name="rightKey">The right key.</param> | |||
/// <param name="rightValue">The right value.</param> | |||
/// <returns>CompareTo-style results: -1 if left is less, 0 if equal, and 1 if greater than right.</returns> | |||
private int KeyAndValueComparison(TKey leftKey, TValue leftValue, TKey rightKey, TValue rightValue) | |||
{ | |||
// Compare keys | |||
int comparisonResult = _keyComparison(leftKey, rightKey); | |||
if ((0 == comparisonResult) && (null != _valueComparison)) | |||
{ | |||
// Keys match; compare values | |||
comparisonResult = _valueComparison(leftValue, rightValue); | |||
} | |||
return comparisonResult; | |||
} | |||
#if DEBUGGING | |||
/// <summary> | |||
/// Asserts that tree invariants are not violated. | |||
/// </summary> | |||
private void AssertInvariants() | |||
{ | |||
// Root is black | |||
Debug.Assert((null == _rootEntityView) || _rootEntityView.IsBlack, "Root is not black"); | |||
// Every path contains the same number of black entityViews | |||
Dictionary<EntityView, EntityView> parents = new Dictionary<LeftLeaningRedBlackTree<TKey, TValue>.EntityView, LeftLeaningRedBlackTree<TKey, TValue>.EntityView>(); | |||
foreach (EntityView entityView in Traverse(_rootEntityView, n => true, n => n)) | |||
{ | |||
if (null != entityView.Left) | |||
{ | |||
parents[entityView.Left] = entityView; | |||
} | |||
if (null != entityView.Right) | |||
{ | |||
parents[entityView.Right] = entityView; | |||
} | |||
} | |||
if (null != _rootEntityView) | |||
{ | |||
parents[_rootEntityView] = null; | |||
} | |||
int treeCount = -1; | |||
foreach (EntityView entityView in Traverse(_rootEntityView, n => (null == n.Left) || (null == n.Right), n => n)) | |||
{ | |||
int pathCount = 0; | |||
EntityView current = entityView; | |||
while (null != current) | |||
{ | |||
if (current.IsBlack) | |||
{ | |||
pathCount++; | |||
} | |||
current = parents[current]; | |||
} | |||
Debug.Assert((-1 == treeCount) || (pathCount == treeCount), "Not all paths have the same number of black entityViews."); | |||
treeCount = pathCount; | |||
} | |||
// Verify entityView properties... | |||
foreach (EntityView entityView in Traverse(_rootEntityView, n => true, n => n)) | |||
{ | |||
// Left entityView is less | |||
if (null != entityView.Left) | |||
{ | |||
Debug.Assert(0 > KeyAndValueComparison(entityView.Left.Key, entityView.Left.Value, entityView.Key, entityView.Value), "Left entityView is greater than its parent."); | |||
} | |||
// Right entityView is greater | |||
if (null != entityView.Right) | |||
{ | |||
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 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(entityView.Right) || IsRed(entityView.Left), "EntityView is not left-leaning."); | |||
// No consecutive reds (subset of previous rule) | |||
//Debug.Assert(!(IsRed(entityView) && IsRed(entityView.Left))); | |||
} | |||
} | |||
/// <summary> | |||
/// Gets an HTML fragment representing the tree. | |||
/// </summary> | |||
public string HtmlDocument | |||
{ | |||
get | |||
{ | |||
return | |||
"<html>" + | |||
"<body>" + | |||
(null != _rootEntityView ? _rootEntityView.HtmlFragment : "[null]") + | |||
"</body>" + | |||
"</html>"; | |||
} | |||
} | |||
#endif | |||
} |
@@ -1,108 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Collections; | |||
// By James McCaffrey11/02/2012 | |||
sealed public class PriorityQueue<T>:IEnumerable<T> where T : IComparable<T> | |||
{ | |||
private List<T> data; | |||
public PriorityQueue () | |||
{ | |||
this.data = new List<T> (); | |||
} | |||
IEnumerator System.Collections.IEnumerable.GetEnumerator () | |||
{ | |||
// Lets call the generic version here | |||
return this.GetEnumerator (); | |||
} | |||
public IEnumerator<T> GetEnumerator () | |||
{ | |||
return data.GetEnumerator () as IEnumerator<T>; | |||
} | |||
public void Enqueue (T item) | |||
{ | |||
data.Add (item); | |||
int ci = data.Count - 1; // child index; start at end | |||
while (ci > 0) { | |||
int pi = (ci - 1) / 2; // parent index | |||
if (data [ci].CompareTo (data [pi]) >= 0) | |||
break; // child item is larger than (or equal) parent so we're done | |||
T tmp = data [ci]; | |||
data [ci] = data [pi]; | |||
data [pi] = tmp; | |||
ci = pi; | |||
} | |||
} | |||
public T Dequeue() | |||
{ | |||
// assumes pq is not empty; up to calling code | |||
int li = data.Count - 1; // last index (before removal) | |||
T frontItem = data [0]; // fetch the front | |||
data [0] = data [li]; | |||
data.RemoveAt (li); | |||
--li; // last index (after removal) | |||
int pi = 0; // parent index. start at front of pq | |||
while (true) | |||
{ | |||
int ci = pi * 2 + 1; // left child index of parent | |||
if (ci > li) | |||
break; // no children so done | |||
int rc = ci + 1; // right child | |||
if (rc <= li && data [rc].CompareTo (data [ci]) < 0) // if there is a rc (ci + 1), and it is smaller than left child, use the rc instead | |||
ci = rc; | |||
if (data [pi].CompareTo (data [ci]) <= 0) | |||
break; // parent is smaller than (or equal to) smallest child so done | |||
T tmp = data [pi]; | |||
data [pi] = data [ci]; | |||
data [ci] = tmp; // swap parent and child | |||
pi = ci; | |||
} | |||
return frontItem; | |||
} | |||
public T Peek () | |||
{ | |||
T frontItem = data [0]; | |||
return frontItem; | |||
} | |||
public int Count () | |||
{ | |||
return data.Count; | |||
} | |||
public override string ToString () | |||
{ | |||
string s = ""; | |||
for (int i = 0; i < data.Count; ++i) | |||
s += data [i].ToString () + " "; | |||
s += "count = " + data.Count; | |||
return s; | |||
} | |||
public bool IsConsistent () | |||
{ | |||
// is the heap property true for all data? | |||
if (data.Count == 0) | |||
return true; | |||
int li = data.Count - 1; // last index | |||
for (int pi = 0; pi < data.Count; ++pi) { // each parent index | |||
int lci = 2 * pi + 1; // left child index | |||
int rci = 2 * pi + 2; // right child index | |||
if (lci <= li && data [pi].CompareTo (data [lci]) > 0) | |||
return false; // if lc exists and it's greater than parent then bad. | |||
if (rci <= li && data [pi].CompareTo (data [rci]) > 0) | |||
return false; // check the right child too. | |||
} | |||
return true; // passed all checks | |||
} // IsConsistent | |||
} // PriorityQueue |
@@ -1,51 +0,0 @@ | |||
using Svelto.DataStructures; | |||
using System.Collections.Generic; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
/// <summary> | |||
/// This is just a place holder at the moment | |||
/// I always wanted to create my own Dictionary | |||
/// data structure as excercise, but never had the | |||
/// time to. At the moment I need the custom interface | |||
/// wrapped though. | |||
/// </summary> | |||
public interface ITypeSafeDictionary | |||
{ | |||
void FillWithIndexedEntityViews(ITypeSafeList entityViews); | |||
bool Remove(int entityId); | |||
IEntityView GetIndexedEntityView(int entityID); | |||
} | |||
class TypeSafeDictionary<TValue> : Dictionary<int, TValue>, ITypeSafeDictionary where TValue:IEntityView | |||
{ | |||
internal static readonly ReadOnlyDictionary<int, TValue> Default = | |||
new ReadOnlyDictionary<int, TValue>(new Dictionary<int, TValue>()); | |||
public void FillWithIndexedEntityViews(ITypeSafeList entityViews) | |||
{ | |||
int count; | |||
var buffer = FasterList<TValue>.NoVirt.ToArrayFast((FasterList<TValue>) entityViews, out count); | |||
for (int i = 0; i < count; i++) | |||
{ | |||
var entityView = buffer[i]; | |||
Add(entityView.ID, entityView); | |||
} | |||
} | |||
new public bool Remove(int entityId) | |||
{ | |||
base.Remove(entityId); | |||
return this.Count > 0; | |||
} | |||
public IEntityView GetIndexedEntityView(int entityID) | |||
{ | |||
return this[entityID]; | |||
} | |||
} | |||
} |
@@ -1,150 +0,0 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public interface ITypeSafeList: IEnumerable | |||
{ | |||
void AddRange(ITypeSafeList entityViewListValue); | |||
ITypeSafeList Create(); | |||
ITypeSafeList Create(int size); | |||
bool isQueryiableEntityView { get; } | |||
bool UnorderedRemove(int entityID); | |||
ITypeSafeDictionary CreateIndexedDictionary(); | |||
IEntityView[] ToArrayFast(out int count); | |||
void ReserveCapacity(int capacity); | |||
int GetIndexFromID(int entityID); | |||
} | |||
class TypeSafeFasterListForECS<T>: FasterList<T> where T:IEntityView | |||
{ | |||
protected TypeSafeFasterListForECS() | |||
{ | |||
_mappedIndices = new Dictionary<int, int>(); | |||
} | |||
protected TypeSafeFasterListForECS(int size):base(size) | |||
{ | |||
_mappedIndices = new Dictionary<int, int>(); | |||
} | |||
public bool UnorderedRemove(int entityID) | |||
{ | |||
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 entityViewListValue) | |||
{ | |||
var index = this.Count; | |||
base.AddRange(entityViewListValue as FasterList<T>); | |||
for (int i = index; i < Count; ++i) | |||
_mappedIndices[this[i].ID] = i; | |||
} | |||
new public void Add(T entityView) | |||
{ | |||
var index = this.Count; | |||
base.Add(entityView); | |||
_mappedIndices[entityView.ID] = index; | |||
} | |||
public void ReserveCapacity(int capacity) | |||
{ | |||
if (this.ToArrayFast().Length < capacity) | |||
Resize(capacity); | |||
} | |||
public int GetIndexFromID(int entityID) | |||
{ | |||
return _mappedIndices[entityID]; | |||
} | |||
readonly Dictionary<int, int> _mappedIndices; | |||
} | |||
class TypeSafeFasterListForECSForStructs<T> : TypeSafeFasterListForECS<T>, ITypeSafeList where T:struct, IEntityStruct | |||
{ | |||
public TypeSafeFasterListForECSForStructs(int size):base(size) | |||
{} | |||
public TypeSafeFasterListForECSForStructs() | |||
{} | |||
public ITypeSafeList Create() | |||
{ | |||
return new TypeSafeFasterListForECSForStructs<T>(); | |||
} | |||
public bool isQueryiableEntityView | |||
{ | |||
get { return false; } | |||
} | |||
public ITypeSafeDictionary CreateIndexedDictionary() | |||
{ | |||
throw new Exception("Not Allowed"); | |||
} | |||
public IEntityView[] ToArrayFast(out int count) | |||
{ | |||
throw new Exception("Not Allowed"); | |||
} | |||
public ITypeSafeList Create(int size) | |||
{ | |||
return new TypeSafeFasterListForECSForStructs<T>(size); | |||
} | |||
} | |||
class TypeSafeFasterListForECSForClasses<T> : TypeSafeFasterListForECS<T>, ITypeSafeList where T:EntityView, new() | |||
{ | |||
public TypeSafeFasterListForECSForClasses(int size):base(size) | |||
{} | |||
public TypeSafeFasterListForECSForClasses() | |||
{} | |||
public ITypeSafeList Create() | |||
{ | |||
return new TypeSafeFasterListForECSForClasses<T>(); | |||
} | |||
public bool isQueryiableEntityView | |||
{ | |||
get { return true; } | |||
} | |||
public ITypeSafeDictionary CreateIndexedDictionary() | |||
{ | |||
return new TypeSafeDictionary<T>(); | |||
} | |||
public IEntityView[] ToArrayFast(out int count) | |||
{ | |||
count = this.Count; | |||
return this.ToArrayFast(); | |||
} | |||
public ITypeSafeList Create(int size) | |||
{ | |||
return new TypeSafeFasterListForECSForClasses<T>(size); | |||
} | |||
} | |||
} |
@@ -1,168 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public class EngineEntityViewDB : IEngineEntityViewDB | |||
{ | |||
internal EngineEntityViewDB( Dictionary<Type, ITypeSafeList> entityViewsDB, | |||
Dictionary<Type, ITypeSafeDictionary> entityViewsDBdic, | |||
Dictionary<Type, ITypeSafeList> metaEntityViewsDB, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsDB) | |||
{ | |||
_entityViewsDB = entityViewsDB; | |||
_entityViewsDBdic = entityViewsDBdic; | |||
_metaEntityViewsDB = metaEntityViewsDB; | |||
_groupEntityViewsDB = groupEntityViewsDB; | |||
} | |||
public FasterReadOnlyList<T> QueryEntityViews<T>() where T:EntityView, new() | |||
{ | |||
var type = typeof(T); | |||
ITypeSafeList entityViews; | |||
if (_entityViewsDB.TryGetValue(type, out entityViews) == false) | |||
return RetrieveEmptyEntityViewList<T>(); | |||
return new FasterReadOnlyList<T>((FasterList<T>)entityViews); | |||
} | |||
public FasterReadOnlyList<T> QueryGroupedEntityViews<T>(int @group) where T:EntityView, new() | |||
{ | |||
Dictionary<Type, ITypeSafeList> entityViews; | |||
if (_groupEntityViewsDB.TryGetValue(group, out entityViews) == false) | |||
return RetrieveEmptyEntityViewList<T>(); | |||
return new FasterReadOnlyList<T>(entityViews as FasterList<T>); | |||
} | |||
public T[] QueryEntityViewsAsArray<T>(out int count) where T : IEntityView | |||
{ | |||
var type = typeof(T); | |||
count = 0; | |||
ITypeSafeList entityViews; | |||
if (_entityViewsDB.TryGetValue(type, out entityViews) == false) | |||
return RetrieveEmptyEntityViewArray<T>(); | |||
var castedEntityViews = (FasterList<T>)entityViews; | |||
count = castedEntityViews.Count; | |||
return castedEntityViews.ToArrayFast(); | |||
} | |||
public T[] QueryGroupedEntityViewsAsArray<T>(int @group, out int count) where T : IEntityView | |||
{ | |||
var type = typeof(T); | |||
count = 0; | |||
Dictionary<Type, ITypeSafeList> entityViews; | |||
if (_groupEntityViewsDB.TryGetValue(group, out entityViews) == false) | |||
return RetrieveEmptyEntityViewArray<T>(); | |||
var castedEntityViews = (FasterList<T>)entityViews[type]; | |||
count = castedEntityViews.Count; | |||
return castedEntityViews.ToArrayFast(); | |||
} | |||
public ReadOnlyDictionary<int, T> QueryIndexableEntityViews<T>() where T:IEntityView | |||
{ | |||
var type = typeof(T); | |||
ITypeSafeDictionary entityViews; | |||
if (_entityViewsDBdic.TryGetValue(type, out entityViews) == false) | |||
return TypeSafeDictionary<T>.Default; | |||
return new ReadOnlyDictionary<int, T>(entityViews as Dictionary<int, T>); | |||
} | |||
public bool TryQueryEntityView<T>(int ID, out T entityView) where T : IEntityView | |||
{ | |||
var type = typeof(T); | |||
T internalEntityView; | |||
ITypeSafeDictionary entityViews; | |||
TypeSafeDictionary<T> casted; | |||
_entityViewsDBdic.TryGetValue(type, out entityViews); | |||
casted = entityViews as TypeSafeDictionary<T>; | |||
if (casted != null && | |||
casted.TryGetValue(ID, out internalEntityView)) | |||
{ | |||
entityView = (T)internalEntityView; | |||
return true; | |||
} | |||
entityView = default(T); | |||
return false; | |||
} | |||
public T QueryEntityView<T>(int ID) where T : IEntityView | |||
{ | |||
var type = typeof(T); | |||
T internalEntityView; ITypeSafeDictionary entityViews; | |||
TypeSafeDictionary<T> casted; | |||
_entityViewsDBdic.TryGetValue(type, out entityViews); | |||
casted = entityViews as TypeSafeDictionary<T>; | |||
if (casted != null && | |||
casted.TryGetValue(ID, out internalEntityView)) | |||
return (T)internalEntityView; | |||
throw new Exception("EntityView Not Found"); | |||
} | |||
public T QueryMetaEntityView<T>(int metaEntityID) where T:EntityView, new() | |||
{ | |||
return QueryEntityView<T>(metaEntityID); | |||
} | |||
public bool TryQueryMetaEntityView<T>(int metaEntityID, out T entityView) where T:EntityView, new() | |||
{ | |||
return TryQueryEntityView(metaEntityID, out entityView); | |||
} | |||
public FasterReadOnlyList<T> QueryMetaEntityViews<T>() where T:EntityView, new() | |||
{ | |||
var type = typeof(T); | |||
ITypeSafeList entityViews; | |||
if (_metaEntityViewsDB.TryGetValue(type, out entityViews) == false) | |||
return RetrieveEmptyEntityViewList<T>(); | |||
return new FasterReadOnlyList<T>((FasterList<T>)entityViews); | |||
} | |||
static FasterReadOnlyList<T> RetrieveEmptyEntityViewList<T>() | |||
{ | |||
return FasterReadOnlyList<T>.DefaultList; | |||
} | |||
static T[] RetrieveEmptyEntityViewArray<T>() | |||
{ | |||
return FasterList<T>.DefaultList.ToArrayFast(); | |||
} | |||
readonly Dictionary<Type, ITypeSafeList> _entityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeDictionary> _entityViewsDBdic; | |||
readonly Dictionary<Type, ITypeSafeList> _metaEntityViewsDB; | |||
readonly Dictionary<int, Dictionary<Type, ITypeSafeList>> _groupEntityViewsDB; | |||
} | |||
} |
@@ -1,231 +0,0 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
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 | |||
{ | |||
public partial class EnginesRoot : IDisposable | |||
{ | |||
/// <summary> | |||
/// Engines root contextualize your engines and entities. You don't need to limit yourself to one EngineRoot | |||
/// as multiple engines root could promote separation of scopes. The EntitySubmissionScheduler checks | |||
/// periodically if new entity must be submited to the database and the engines. It's an external | |||
/// dependencies to be indipendent by the running platform as the user can define it. | |||
/// The EntitySubmissionScheduler cannot hold an EnginesRoot reference, that's why | |||
/// it must receive a weak reference of the EnginesRoot callback. | |||
/// </summary> | |||
public EnginesRoot(EntitySubmissionScheduler entityViewScheduler) | |||
{ | |||
_entityViewEngines = new Dictionary<Type, FasterList<IHandleEntityViewEngine>>(); | |||
_otherEngines = new FasterList<IEngine>(); | |||
_entityViewsDB = new Dictionary<Type, ITypeSafeList>(); | |||
_metaEntityViewsDB = new Dictionary<Type, ITypeSafeList>(); | |||
_groupEntityViewsDB = new Dictionary<int, Dictionary<Type, ITypeSafeList>>(); | |||
_entityViewsDBdic = new Dictionary<Type, ITypeSafeDictionary>(); | |||
_entityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>>(); | |||
_metaEntityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>>(); | |||
_groupedEntityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<int, Dictionary<Type, ITypeSafeList>>>(); | |||
_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<Type, Type[]>(); | |||
#endif | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); | |||
debugEngineObject.gameObject.AddComponent<EngineProfilerBehaviour>(); | |||
#endif | |||
} | |||
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 queryableEntityViewEngine = engine as IQueryingEntityViewEngine; | |||
if (queryableEntityViewEngine != null) | |||
{ | |||
queryableEntityViewEngine.entityViewsDB = _engineEntityViewDB; | |||
queryableEntityViewEngine.Ready(); | |||
} | |||
} | |||
#if EXPERIMENTAL | |||
void CollectImplementedInterfaces(Type[] implementedInterfaces) | |||
{ | |||
_implementedInterfaceTypes.Clear(); | |||
var type = typeof(IHandleEntityViewEngine); | |||
for (int index = 0; index < implementedInterfaces.Length; index++) | |||
{ | |||
var interfaceType = implementedInterfaces[index]; | |||
if (type.IsAssignableFrom(interfaceType) == false) | |||
continue; | |||
if (false == interfaceType.IsGenericTypeEx()) | |||
{ | |||
continue; | |||
} | |||
var genericTypeDefinition = interfaceType.GetGenericTypeDefinition(); | |||
_implementedInterfaceTypes.Add(genericTypeDefinition, interfaceType.GetGenericArguments()); | |||
} | |||
} | |||
bool CheckSpecialEngine(IEngine engine) | |||
{ | |||
if (_implementedInterfaceTypes.Count == 0) return false; | |||
bool engineAdded = false; | |||
if (_implementedInterfaceTypes.ContainsKey(_structEntityViewEngineType)) | |||
{ | |||
((IStructEntityViewEngine)engine).CreateStructEntityViews | |||
(_sharedStructEntityViewLists); | |||
} | |||
if (_implementedInterfaceTypes.ContainsKey(_groupedStructEntityViewsEngineType)) | |||
{ | |||
((IGroupedStructEntityViewsEngine)engine).CreateStructEntityViews | |||
(_sharedGroupedStructEntityViewLists); | |||
} | |||
return engineAdded; | |||
} | |||
#endif | |||
void CheckEntityViewsEngine(IEngine engine, Type engineType) | |||
{ | |||
var baseType = engineType.GetBaseType(); | |||
if (baseType.IsGenericTypeEx()) | |||
{ | |||
var genericArguments = baseType.GetGenericArgumentsEx(); | |||
AddEngine(engine as IHandleEntityViewEngine, genericArguments, _entityViewEngines); | |||
#if EXPERIMENTAL | |||
var activableEngine = engine as IHandleActivableEntityEngine; | |||
if (activableEngine != null) | |||
AddEngine(activableEngine, genericArguments, _activableViewEntitiesEngines); | |||
#endif | |||
return; | |||
} | |||
throw new Exception("Not Supported Engine"); | |||
} | |||
//The T parameter allows to pass datastructure sthat not necessarly are | |||
//defined with IEngine, but must be defined with IEngine implementations | |||
static void AddEngine<T>(T engine, Type[] types, | |||
Dictionary<Type, FasterList<T>> engines) where T:IEngine | |||
{ | |||
for (int i = 0; i < types.Length; i++) | |||
{ | |||
FasterList<T> list; | |||
var type = types[i]; | |||
if (engines.TryGetValue(type, out list) == false) | |||
{ | |||
list = new FasterList<T>(); | |||
engines.Add(type, list); | |||
} | |||
list.Add(engine); | |||
} | |||
} | |||
readonly Dictionary<Type, FasterList<IHandleEntityViewEngine>> _entityViewEngines; | |||
readonly FasterList<IEngine> _otherEngines; | |||
readonly Dictionary<Type, ITypeSafeList> _entityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeList> _metaEntityViewsDB; | |||
readonly Dictionary<int, Dictionary<Type, ITypeSafeList>> _groupEntityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeDictionary> _entityViewsDBdic; | |||
readonly DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>> _entityViewsToAdd; | |||
readonly DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>> _metaEntityViewsToAdd; | |||
readonly DoubleBufferedEntityViews<Dictionary<int, Dictionary<Type, ITypeSafeList>>> _groupedEntityViewsToAdd; | |||
readonly EntitySubmissionScheduler _scheduler; | |||
#if EXPERIMENTAL | |||
readonly Type _structEntityViewEngineType; | |||
readonly Type _groupedStructEntityViewsEngineType; | |||
readonly SharedStructEntityViewLists _sharedStructEntityViewLists; | |||
readonly SharedGroupedStructEntityViewsLists _sharedGroupedStructEntityViewLists; | |||
readonly Dictionary<Type, Type[]> _implementedInterfaceTypes; | |||
#endif | |||
readonly EngineEntityViewDB _engineEntityViewDB; | |||
class DoubleBufferedEntityViews<T> where T : class, IDictionary, new() | |||
{ | |||
readonly T _entityViewsToAddBufferA = new T(); | |||
readonly T _entityViewsToAddBufferB = new T(); | |||
internal DoubleBufferedEntityViews() | |||
{ | |||
this.other = _entityViewsToAddBufferA; | |||
this.current = _entityViewsToAddBufferB; | |||
} | |||
internal T other; | |||
internal T current; | |||
internal void Swap() | |||
{ | |||
var toSwap = other; | |||
other = current; | |||
current = toSwap; | |||
} | |||
} | |||
} | |||
} |
@@ -1,375 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
#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 | |||
{ | |||
public partial class EnginesRoot : IDisposable | |||
{ | |||
/// <summary> | |||
/// an EnginesRoot reference cannot be held by anything else than the Composition Root | |||
/// where it has been created. IEntityFactory and IEntityFunctions allow a weakreference | |||
/// of the EnginesRoot to be passed around. | |||
/// </summary> | |||
/// <returns></returns> | |||
public IEntityFactory GenerateEntityFactory() | |||
{ | |||
return new GenericEntityFactory(new DataStructures.WeakReference<EnginesRoot>(this)); | |||
} | |||
public IEntityFunctions GenerateEntityFunctions() | |||
{ | |||
return new GenericEntityFunctions(new DataStructures.WeakReference<EnginesRoot>(this)); | |||
} | |||
/// <summary> | |||
/// The EntityDescriptor doesn't need to be ever instantiated. It just describes the Entity | |||
/// itself in terms of EntityViews to build. The Implementors are passed to fill the | |||
/// references of the EntityViews components. Please read the articles on my blog | |||
/// to understand better the terminologies | |||
/// </summary> | |||
/// <typeparam name="T"></typeparam> | |||
/// <param name="entityID"></param> | |||
/// <param name="implementors"></param> | |||
void BuildEntity<T>(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() | |||
{ | |||
EntityFactory.BuildEntityViews | |||
(entityID, _entityViewsToAdd.current, EntityDescriptorTemplate<T>.Default, implementors); | |||
} | |||
/// <summary> | |||
/// When the type of the entity is not known (this is a special case!) an EntityDescriptorInfo | |||
/// can be built in place of the generic parameter T. | |||
/// </summary> | |||
/// <param name="entityID"></param> | |||
/// <param name="entityDescriptor"></param> | |||
/// <param name="implementors"></param> | |||
void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) | |||
{ | |||
EntityFactory.BuildEntityViews | |||
(entityID, _entityViewsToAdd.current, entityDescriptor, implementors); | |||
} | |||
/// <summary> | |||
/// 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 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 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 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 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. | |||
/// </summary> | |||
/// <param name="metaEntityID"></param> | |||
/// <param name="ed"></param> | |||
/// <param name="implementors"></param> | |||
void BuildMetaEntity<T>(int metaEntityID, object[] implementors) where T : IEntityDescriptor, new() | |||
{ | |||
EntityFactory.BuildEntityViews(metaEntityID, _entityViewsToAdd.current, | |||
EntityDescriptorTemplate<T>.Default, implementors); | |||
} | |||
/// <summary> | |||
/// Using this function is like building a normal entity, but the entityViews | |||
/// are grouped by groupID to be more efficently processed inside engines and | |||
/// improve cache locality. Either class entityViews and struct entityViews can be | |||
/// grouped. | |||
/// </summary> | |||
/// <param name="entityID"></param> | |||
/// <param name="groupID"></param> | |||
/// <param name="ed"></param> | |||
/// <param name="implementors"></param> | |||
void BuildEntityInGroup<T>(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() | |||
{ | |||
EntityFactory.BuildGroupedEntityViews(entityID, groupID, | |||
_groupedEntityViewsToAdd.current, | |||
EntityDescriptorTemplate<T>.Default, | |||
implementors); | |||
} | |||
void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) | |||
{ | |||
EntityFactory.BuildGroupedEntityViews(entityID, groupID, | |||
_groupedEntityViewsToAdd.current, | |||
entityDescriptor, implementors); | |||
} | |||
void Preallocate<T>(int size) where T : IEntityDescriptor, new() | |||
{ | |||
var entityViewsToBuild = EntityDescriptorTemplate<T>.Default.entityViewsToBuild; | |||
int count = entityViewsToBuild.Length; | |||
for (int index = 0; index < count; index++) | |||
{ | |||
var entityViewBuilder = entityViewsToBuild[index]; | |||
var entityViewType = entityViewBuilder.GetEntityViewType(); | |||
ITypeSafeList dbList; | |||
if (_entityViewsDB.TryGetValue(entityViewType, out dbList) == false) | |||
_entityViewsDB[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); | |||
else | |||
dbList.ReserveCapacity(size); | |||
if (_entityViewsToAdd.current.TryGetValue(entityViewType, out dbList) == false) | |||
_entityViewsToAdd.current[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); | |||
else | |||
dbList.ReserveCapacity(size); | |||
} | |||
} | |||
void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) | |||
{ | |||
var removeEntityImplementor = removeInfo as RemoveEntityImplementor; | |||
if (removeEntityImplementor.isInAGroup) | |||
InternalRemove(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, removeEntityImplementor.groupID, _entityViewsDB); | |||
else | |||
InternalRemove(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, _entityViewsDB); | |||
} | |||
void RemoveEntity<T>(int entityID) where T : IEntityDescriptor, new() | |||
{ | |||
InternalRemove(EntityDescriptorTemplate<T>.Default.entityViewsToBuild, entityID, _entityViewsDB); | |||
} | |||
void RemoveMetaEntity<T>(int metaEntityID) where T : IEntityDescriptor, new() | |||
{ | |||
InternalRemove(EntityDescriptorTemplate<T>.Default.entityViewsToBuild, metaEntityID, _metaEntityViewsDB); | |||
} | |||
void RemoveEntityFromGroup<T>(int entityID, int groupID) where T : IEntityDescriptor, new() | |||
{ | |||
InternalRemove(EntityDescriptorTemplate<T>.Default.entityViewsToBuild, entityID, _groupEntityViewsDB[groupID]); | |||
} | |||
void SwapEntityGroup<T>(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new() | |||
{ | |||
DesignByContract.Check.Require(fromGroupID != toGroupID, "can't move an entity to the same group where it already belongs to"); | |||
var entityViewBuilders = EntityDescriptorTemplate<T>.Default.entityViewsToBuild; | |||
int entityViewBuildersCount = entityViewBuilders.Length; | |||
Dictionary<Type, ITypeSafeList> dictionary = _groupEntityViewsDB[fromGroupID]; | |||
Dictionary<Type, ITypeSafeList> groupedEntityViewsTyped; | |||
if (_groupEntityViewsDB.TryGetValue(toGroupID, out groupedEntityViewsTyped) == false) | |||
{ | |||
groupedEntityViewsTyped = new Dictionary<Type, ITypeSafeList>(); | |||
_groupEntityViewsDB.Add(toGroupID, groupedEntityViewsTyped); | |||
} | |||
for (int i = 0; i < entityViewBuildersCount; i++) | |||
{ | |||
IEntityViewBuilder entityViewBuilder = entityViewBuilders[i]; | |||
Type entityViewType = entityViewBuilder.GetEntityViewType(); | |||
ITypeSafeList fromSafeList = dictionary[entityViewType]; | |||
ITypeSafeList toSafeList; | |||
if (groupedEntityViewsTyped.TryGetValue(entityViewType, out toSafeList) == false) | |||
{ | |||
toSafeList = fromSafeList.Create(); | |||
} | |||
entityViewBuilder.MoveEntityView(entityID, fromSafeList, toSafeList); | |||
if (fromSafeList.UnorderedRemove(entityID) == false) | |||
dictionary.Remove(entityViewType); | |||
} | |||
if (dictionary.Count == 0) _groupEntityViewsDB.Remove(fromGroupID); | |||
} | |||
void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
{ | |||
int entityViewBuildersCount = entityViewBuilders.Length; | |||
for (int i = 0; i < entityViewBuildersCount; i++) | |||
{ | |||
Type entityViewType = entityViewBuilders[i].GetEntityViewType(); | |||
ITypeSafeList entityViews = entityViewsDB[entityViewType]; | |||
if (entityViews.UnorderedRemove(entityID) == false) | |||
entityViewsDB.Remove(entityViewType); | |||
if (entityViews.isQueryiableEntityView) | |||
{ | |||
var typeSafeDictionary = _entityViewsDBdic[entityViewType]; | |||
var entityView = typeSafeDictionary.GetIndexedEntityView(entityID); | |||
if (typeSafeDictionary.Remove(entityID) == false) | |||
_entityViewsDBdic.Remove(entityViewType); | |||
RemoveEntityViewFromEngines(_entityViewEngines, entityView, entityViewType); | |||
} | |||
} | |||
} | |||
void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
{ | |||
InternalRemoveFromDB(entityViewBuilders, entityID, groupID); | |||
InternalRemove(entityViewBuilders, entityID, entityViewsDB); | |||
} | |||
void InternalRemoveFromDB(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID) | |||
{ | |||
int entityViewBuildersCount = entityViewBuilders.Length; | |||
Dictionary<Type, ITypeSafeList> dictionary = _groupEntityViewsDB[groupID]; | |||
for (int i = 0; i < entityViewBuildersCount; i++) | |||
{ | |||
Type entityViewType = entityViewBuilders[i].GetEntityViewType(); | |||
if (dictionary[entityViewType].UnorderedRemove(entityID) == false) | |||
dictionary.Remove(entityViewType); | |||
} | |||
if (dictionary.Count == 0) _groupEntityViewsDB.Remove(groupID); | |||
} | |||
static void RemoveEntityViewFromEngines(Dictionary<Type, FasterList<IHandleEntityViewEngine>> entityViewEngines, | |||
IEntityView entityView, Type entityViewType) | |||
{ | |||
FasterList<IHandleEntityViewEngine> enginesForEntityView; | |||
if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) | |||
{ | |||
int count; | |||
var fastList = FasterList<IHandleEntityViewEngine>.NoVirt.ToArrayFast(enginesForEntityView, out count); | |||
for (int j = 0; j < count; j++) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
EngineProfiler.MonitorRemoveDuration(fastList[j], entityView); | |||
#else | |||
fastList[j].Remove(entityView); | |||
#endif | |||
} | |||
} | |||
} | |||
class GenericEntityFactory : IEntityFactory | |||
{ | |||
DataStructures.WeakReference<EnginesRoot> _weakEngine; | |||
public GenericEntityFactory(DataStructures.WeakReference<EnginesRoot> weakReference) | |||
{ | |||
_weakEngine = weakReference; | |||
} | |||
public void BuildEntity<T>(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.BuildEntity<T>(entityID, implementors); | |||
} | |||
public void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) | |||
{ | |||
_weakEngine.Target.BuildEntity(entityID, entityDescriptor, implementors); | |||
} | |||
public void BuildMetaEntity<T>(int metaEntityID, object[] implementors = null) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.BuildMetaEntity<T>(metaEntityID, implementors); | |||
} | |||
public void BuildEntityInGroup<T>(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.BuildEntityInGroup<T>(entityID, groupID, implementors); | |||
} | |||
public void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) | |||
{ | |||
_weakEngine.Target.BuildEntityInGroup(entityID, groupID, entityDescriptor, implementors); | |||
} | |||
public void Preallocate<T>(int size) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.Preallocate<T>(size); | |||
} | |||
} | |||
class GenericEntityFunctions : IEntityFunctions | |||
{ | |||
public GenericEntityFunctions(DataStructures.WeakReference<EnginesRoot> weakReference) | |||
{ | |||
_weakReference = weakReference; | |||
} | |||
public void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) | |||
{ | |||
_weakReference.Target.RemoveEntity(entityID, removeInfo); | |||
} | |||
public void RemoveEntity<T>(int entityID) where T : IEntityDescriptor, new() | |||
{ | |||
_weakReference.Target.RemoveEntity<T>(entityID); | |||
} | |||
public void RemoveMetaEntity<T>(int metaEntityID) where T : IEntityDescriptor, new() | |||
{ | |||
_weakReference.Target.RemoveEntity<T>(metaEntityID); | |||
} | |||
public void RemoveEntityFromGroup<T>(int entityID, int groupID) where T : IEntityDescriptor, new() | |||
{ | |||
_weakReference.Target.RemoveEntity<T>(entityID); | |||
} | |||
public void SwapEntityGroup<T>(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new() | |||
{ | |||
_weakReference.Target.SwapEntityGroup<T>(entityID, fromGroupID, toGroupID); | |||
} | |||
readonly DataStructures.WeakReference<EnginesRoot> _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); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -1,160 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
#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 | |||
{ | |||
public partial class EnginesRoot : IDisposable | |||
{ | |||
void SubmitEntityViews() | |||
{ | |||
bool newEntityViewsHaveBeenAddedWhileIterating = | |||
_metaEntityViewsToAdd.current.Count > 0 | |||
|| _entityViewsToAdd.current.Count > 0 | |||
|| _groupedEntityViewsToAdd.current.Count > 0; | |||
int numberOfReenteringLoops = 0; | |||
while (newEntityViewsHaveBeenAddedWhileIterating) | |||
{ | |||
//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 (_metaEntityViewsToAdd.other.Count > 0) | |||
AddEntityViewsToTheDBAndSuitableEngines(_metaEntityViewsToAdd.other, _metaEntityViewsDB); | |||
if (_groupedEntityViewsToAdd.other.Count > 0) | |||
AddGroupEntityViewsToTheDBAndSuitableEngines(_groupedEntityViewsToAdd.other, _groupEntityViewsDB, _entityViewsDB); | |||
//other can be cleared now | |||
_entityViewsToAdd.other.Clear(); | |||
_metaEntityViewsToAdd.other.Clear(); | |||
_groupedEntityViewsToAdd.other.Clear(); | |||
//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 IEntityViewsEngine Add method, please consider building entities outside IEntityViewsEngine Add method"); | |||
numberOfReenteringLoops++; | |||
} | |||
} | |||
void AddEntityViewsToTheDBAndSuitableEngines(Dictionary<Type, ITypeSafeList> entityViewsToAdd, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
{ | |||
foreach (var entityViewList in entityViewsToAdd) | |||
{ | |||
AddEntityViewToDB(entityViewsDB, entityViewList); | |||
if (entityViewList.Value.isQueryiableEntityView) | |||
{ | |||
AddEntityViewToEntityViewsDictionary(_entityViewsDBdic, entityViewList.Value, entityViewList.Key); | |||
} | |||
} | |||
foreach (var entityViewList in entityViewsToAdd) | |||
{ | |||
if (entityViewList.Value.isQueryiableEntityView) | |||
{ | |||
AddEntityViewToTheSuitableEngines(_entityViewEngines, entityViewList.Value, | |||
entityViewList.Key); | |||
} | |||
} | |||
} | |||
void AddGroupEntityViewsToTheDBAndSuitableEngines(Dictionary<int, Dictionary<Type, ITypeSafeList>> groupedEntityViewsToAdd, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsDB, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
{ | |||
foreach (var group in groupedEntityViewsToAdd) | |||
{ | |||
AddEntityViewsToGroupDB(groupEntityViewsDB, @group); | |||
AddEntityViewsToTheDBAndSuitableEngines(group.Value, entityViewsDB); | |||
} | |||
} | |||
static void AddEntityViewsToGroupDB(Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsDB, | |||
KeyValuePair<int, Dictionary<Type, ITypeSafeList>> @group) | |||
{ | |||
Dictionary<Type, ITypeSafeList> groupedEntityViewsByType; | |||
if (groupEntityViewsDB.TryGetValue(@group.Key, out groupedEntityViewsByType) == false) | |||
groupedEntityViewsByType = groupEntityViewsDB[@group.Key] = new Dictionary<Type, ITypeSafeList>(); | |||
foreach (var entityView in @group.Value) | |||
{ | |||
groupedEntityViewsByType.Add(entityView.Key, entityView.Value); | |||
} | |||
} | |||
static void AddEntityViewToDB(Dictionary<Type, ITypeSafeList> entityViewsDB, KeyValuePair<Type, ITypeSafeList> entityViewList) | |||
{ | |||
ITypeSafeList dbList; | |||
if (entityViewsDB.TryGetValue(entityViewList.Key, out dbList) == false) | |||
dbList = entityViewsDB[entityViewList.Key] = entityViewList.Value.Create(); | |||
dbList.AddRange(entityViewList.Value); | |||
} | |||
static void AddEntityViewToEntityViewsDictionary(Dictionary<Type, ITypeSafeDictionary> entityViewsDBdic, | |||
ITypeSafeList entityViews, Type entityViewType) | |||
{ | |||
ITypeSafeDictionary entityViewsDic; | |||
if (entityViewsDBdic.TryGetValue(entityViewType, out entityViewsDic) == false) | |||
entityViewsDic = entityViewsDBdic[entityViewType] = entityViews.CreateIndexedDictionary(); | |||
entityViewsDic.FillWithIndexedEntityViews(entityViews); | |||
} | |||
static void AddEntityViewToTheSuitableEngines(Dictionary<Type, FasterList<IHandleEntityViewEngine>> entityViewEngines, ITypeSafeList entityViewsList, Type entityViewType) | |||
{ | |||
FasterList<IHandleEntityViewEngine> enginesForEntityView; | |||
if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) | |||
{ | |||
int viewsCount; | |||
var entityViews = entityViewsList.ToArrayFast(out viewsCount); | |||
for (int i = 0; i < viewsCount; i++) | |||
{ | |||
int count; | |||
var fastList = FasterList<IHandleEntityViewEngine>.NoVirt.ToArrayFast(enginesForEntityView, out count); | |||
IEntityView entityView = entityViews[i]; | |||
for (int j = 0; j < count; j++) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
EngineProfiler.MonitorAddDuration(fastList[j], entityView); | |||
#else | |||
fastList[j].Add(entityView); | |||
#endif | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -1,9 +0,0 @@ | |||
using Svelto.WeakEvents; | |||
namespace Svelto.ECS.Schedulers | |||
{ | |||
public abstract class EntitySubmissionScheduler | |||
{ | |||
abstract public void Schedule(WeakAction submitEntityViews); | |||
} | |||
} |
@@ -1,57 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Reflection; | |||
using Svelto.DataStructures; | |||
using Svelto.Utilities; | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEntityView | |||
{ | |||
int ID { get; } | |||
} | |||
public interface IEntityStruct:IEntityView | |||
{ | |||
new int ID { set; } | |||
} | |||
public class EntityView : IEntityView | |||
{ | |||
public int ID { get { return _ID; } } | |||
internal FasterList<KeyValuePair<Type, CastedAction<EntityView>>> entityViewBlazingFastReflection; | |||
internal int _ID; | |||
} | |||
internal static class EntityView<T> where T: EntityView, new() | |||
{ | |||
internal static T BuildEntityView(int ID) | |||
{ | |||
if (FieldCache<T>.list.Count == 0) | |||
{ | |||
var type = typeof(T); | |||
var fields = type.GetFields(BindingFlags.Public | | |||
BindingFlags.Instance); | |||
for (int i = fields.Length - 1; i >= 0; --i) | |||
{ | |||
var field = fields[i]; | |||
CastedAction<EntityView> setter = FastInvoke<T>.MakeSetter<EntityView>(field); | |||
FieldCache<T>.list.Add(new KeyValuePair<Type, CastedAction<EntityView>>(field.FieldType, setter)); | |||
} | |||
} | |||
return new T { _ID = ID, entityViewBlazingFastReflection = FieldCache<T>.list }; | |||
} | |||
static class FieldCache<W> where W:T | |||
{ | |||
internal static readonly FasterList<KeyValuePair<Type, CastedAction<EntityView>>> list = new FasterList<KeyValuePair<Type, CastedAction<EntityView>>>(); | |||
} | |||
} | |||
} | |||
@@ -1,99 +0,0 @@ | |||
using System; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEntityViewBuilder | |||
{ | |||
void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView); | |||
ITypeSafeList Preallocate(ref ITypeSafeList list, int size); | |||
Type GetEntityViewType(); | |||
void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList); | |||
} | |||
public class EntityViewBuilder<EntityViewType> : IEntityViewBuilder where EntityViewType : EntityView, new() | |||
{ | |||
public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) | |||
{ | |||
if (list == null) | |||
list = new TypeSafeFasterListForECSForClasses<EntityViewType>(); | |||
var castedList = list as TypeSafeFasterListForECSForClasses<EntityViewType>; | |||
var lentityView = EntityView<EntityViewType>.BuildEntityView(entityID); | |||
castedList.Add(lentityView); | |||
entityView = lentityView; | |||
} | |||
public ITypeSafeList Preallocate(ref ITypeSafeList list, int size) | |||
{ | |||
if (list == null) | |||
list = new TypeSafeFasterListForECSForClasses<EntityViewType>(size); | |||
else | |||
list.ReserveCapacity(size); | |||
return list; | |||
} | |||
public Type GetEntityViewType() | |||
{ | |||
return _entityViewType; | |||
} | |||
public void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList) | |||
{ | |||
var fromCastedList = fromSafeList as TypeSafeFasterListForECSForClasses<EntityViewType>; | |||
var toCastedList = toSafeList as TypeSafeFasterListForECSForClasses<EntityViewType>; | |||
toCastedList.Add(fromCastedList[fromCastedList.GetIndexFromID(entityID)]); | |||
} | |||
readonly Type _entityViewType = typeof(EntityViewType); | |||
} | |||
public class EntityStructBuilder<EntityViewType> : IEntityViewBuilder where EntityViewType : struct, IEntityStruct | |||
{ | |||
public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) | |||
{ | |||
var lentityView = default(EntityViewType); | |||
lentityView.ID = entityID; | |||
if (list == null) | |||
list = new TypeSafeFasterListForECSForStructs<EntityViewType>(); | |||
var castedList = list as TypeSafeFasterListForECSForStructs<EntityViewType>; | |||
castedList.Add(lentityView); | |||
entityView = null; | |||
} | |||
public ITypeSafeList Preallocate(ref ITypeSafeList list, int size) | |||
{ | |||
if (list == null) | |||
list = new TypeSafeFasterListForECSForStructs<EntityViewType>(size); | |||
else | |||
list.ReserveCapacity(size); | |||
return list; | |||
} | |||
public Type GetEntityViewType() | |||
{ | |||
return _entityViewType; | |||
} | |||
public void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList) | |||
{ | |||
var fromCastedList = fromSafeList as TypeSafeFasterListForECSForStructs<EntityViewType>; | |||
var toCastedList = toSafeList as TypeSafeFasterListForECSForStructs<EntityViewType>; | |||
toCastedList.Add(fromCastedList[fromCastedList.GetIndexFromID(entityID)]); | |||
} | |||
readonly Type _entityViewType = typeof(EntityViewType); | |||
} | |||
} |
@@ -1,178 +0,0 @@ | |||
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; } | |||
} | |||
/// <summary> | |||
/// 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 | |||
/// </summary> | |||
public interface IStructEntityViewEngine<T> : IStructEntityViewEngine where T:struct, IEntityStruct | |||
{ } | |||
/// <summary> | |||
/// same as above, but the entityViews are grouped by ID | |||
/// usually the ID is the owner of the entityViews of that | |||
/// group | |||
/// </summary> | |||
public interface IGroupedStructEntityViewsEngine<T> : IGroupedStructEntityViewsEngine where T : struct, IGroupedEntityView | |||
{ | |||
void Add(ref T entityView); | |||
void Remove(ref T entityView); | |||
} | |||
public sealed class StructEntityViews<T> where T:struct, IEntityStruct | |||
{ | |||
public T[] GetList(out int numberOfItems) | |||
{ | |||
numberOfItems = _internalList.Count; | |||
return _internalList.ToArrayFast(); | |||
} | |||
public StructEntityViews(SharedStructEntityViewLists container) | |||
{ | |||
_internalList = SharedStructEntityViewLists.NoVirt.GetList<T>(container); | |||
} | |||
public void Add(T entityView) | |||
{ | |||
T convert = (T)entityView; | |||
_internalList.Add(convert); | |||
} | |||
readonly FasterList<T> _internalList; | |||
} | |||
public struct StructGroupEntityViews<T> | |||
where T : struct, IEntityView | |||
{ | |||
public StructGroupEntityViews(SharedGroupedStructEntityViewsLists container) | |||
{ | |||
_container = container; | |||
indices = new Dictionary<int, int>(); | |||
} | |||
public void Add(int groupID, T entityView) | |||
{ | |||
T convert = (T)entityView; | |||
var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList<T>(_container, groupID) as FasterList<T>); | |||
indices[entityView.ID] = fasterList.Count; | |||
fasterList.Add(convert); | |||
} | |||
public void Remove(int groupID, T entityView) | |||
{ | |||
var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList<T>(_container, groupID) as FasterList<T>); | |||
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<T>(_container, groupID) as FasterList<T>); | |||
return FasterList<T>.NoVirt.ToArrayFast(fasterList, out numberOfItems); | |||
} | |||
readonly SharedGroupedStructEntityViewsLists _container; | |||
readonly Dictionary<int, int> indices; | |||
} | |||
public class SharedStructEntityViewLists | |||
{ | |||
internal SharedStructEntityViewLists() | |||
{ | |||
_collection = new Dictionary<Type, IFasterList>(); | |||
} | |||
internal static class NoVirt | |||
{ | |||
internal static FasterList<T> GetList<T>(SharedStructEntityViewLists obj) where T : struct | |||
{ | |||
IFasterList list; | |||
if (obj._collection.TryGetValue(typeof(T), out list)) | |||
{ | |||
return list as FasterList<T>; | |||
} | |||
list = new FasterList<T>(); | |||
obj._collection.Add(typeof(T), list); | |||
return (FasterList<T>)list; | |||
} | |||
} | |||
readonly Dictionary<Type, IFasterList> _collection; | |||
} | |||
public class SharedGroupedStructEntityViewsLists | |||
{ | |||
internal SharedGroupedStructEntityViewsLists() | |||
{ | |||
_collection = new Dictionary<Type, Dictionary<int, IFasterList>>(); | |||
} | |||
internal static class NoVirt | |||
{ | |||
internal static IFasterList GetList<T>(SharedGroupedStructEntityViewsLists list, int groupID) where T : struct | |||
{ | |||
Dictionary<int, IFasterList> dic = GetGroup<T>(list); | |||
IFasterList localList; | |||
if (dic.TryGetValue(groupID, out localList)) | |||
return localList; | |||
localList = new FasterList<T>(); | |||
dic.Add(groupID, localList); | |||
return localList; | |||
} | |||
internal static Dictionary<int, IFasterList> GetGroup<T>(SharedGroupedStructEntityViewsLists list) where T : struct | |||
{ | |||
Dictionary<int, IFasterList> dic; | |||
if (list._collection.TryGetValue(typeof(T), out dic)) | |||
{ | |||
return dic; | |||
} | |||
dic = new Dictionary<int, IFasterList>(); | |||
list._collection.Add(typeof(T), dic); | |||
return dic; | |||
} | |||
} | |||
readonly Dictionary<Type, Dictionary<int, IFasterList>> _collection; | |||
} | |||
} |
@@ -1,14 +0,0 @@ | |||
#if UNITY_5 || UNITY_5_3_OR_NEWER | |||
namespace Svelto.ECS | |||
{ | |||
public class GenericEntityDescriptorHolder<T>: | |||
UnityEngine.MonoBehaviour, IEntityDescriptorHolder | |||
where T: class, IEntityDescriptor, new() | |||
{ | |||
public EntityDescriptorInfo RetrieveDescriptor() | |||
{ | |||
return EntityDescriptorTemplate<T>.Default; | |||
} | |||
} | |||
} | |||
#endif |
@@ -1,22 +0,0 @@ | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEngineEntityViewDB | |||
{ | |||
FasterReadOnlyList<T> QueryEntityViews<T>() where T:EntityView, new(); | |||
FasterReadOnlyList<T> QueryMetaEntityViews<T>() where T: EntityView, new(); | |||
FasterReadOnlyList<T> QueryGroupedEntityViews<T>(int group) where T: EntityView, new(); | |||
T[] QueryEntityViewsAsArray<T>(out int count) where T: IEntityView; | |||
T[] QueryGroupedEntityViewsAsArray<T>(int @group, out int count) where T: IEntityView; | |||
ReadOnlyDictionary<int, T> QueryIndexableEntityViews<T>() where T: IEntityView; | |||
bool TryQueryEntityView<T>(int ID, out T entityView) where T : IEntityView; | |||
T QueryEntityView<T>(int ID) where T: IEntityView; | |||
bool TryQueryMetaEntityView<T>(int metaEntityID, out T entityView) where T: EntityView, new(); | |||
T QueryMetaEntityView<T>(int metaEntityID) where T: EntityView, new(); | |||
} | |||
} | |||
@@ -1,27 +0,0 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEntityFactory | |||
{ | |||
void Preallocate<T>(int size) where T : IEntityDescriptor, new(); | |||
void BuildEntity<T>(int entityID, object[] implementors = null) where T:IEntityDescriptor, new(); | |||
void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null); | |||
void BuildMetaEntity<T>(int metaEntityID, object[] implementors = null) where T:IEntityDescriptor, new(); | |||
void BuildEntityInGroup<T>(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 removeInfo); | |||
void RemoveEntity<T>(int entityID) where T:IEntityDescriptor, new(); | |||
void RemoveMetaEntity<T>(int metaEntityID) where T:IEntityDescriptor, new(); | |||
void RemoveEntityFromGroup<T>(int entityID, int groupID) where T:IEntityDescriptor, new(); | |||
void SwapEntityGroup<T>(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new(); | |||
} | |||
} |
@@ -1,107 +0,0 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public class MixedEntityDescriptor<T>: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<T, U> : 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<T, U, V> : 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<T, U, V, W> : 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<T, U, V, W, X> : 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<T, U, V, W, X, Y> : 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; | |||
} | |||
} |
@@ -1,87 +0,0 @@ | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public abstract class MultiEntityViewsEngine<T>:IHandleEntityViewEngine where T:EntityView, new() | |||
{ | |||
protected abstract void Add(T entityView); | |||
protected abstract void Remove(T entityView); | |||
public virtual void Add(IEntityView entityView) | |||
{ | |||
Add((T) entityView); | |||
} | |||
public virtual void Remove(IEntityView entityView) | |||
{ | |||
Remove((T) entityView); | |||
} | |||
} | |||
} | |||
namespace Svelto.ECS | |||
{ | |||
public abstract class MultiEntityViewsEngine<T, U> : MultiEntityViewsEngine<T> | |||
where T:EntityView, new() | |||
where U:EntityView, new() | |||
{ | |||
protected abstract void Add(U entityView); | |||
protected abstract void Remove(U entityView); | |||
public override void Add(IEntityView entityView) | |||
{ | |||
var castedEntityView = entityView as U; | |||
if (castedEntityView != null) | |||
{ | |||
Add(castedEntityView); | |||
} | |||
else | |||
{ | |||
base.Add(entityView); | |||
} | |||
} | |||
public override void Remove(IEntityView entityView) | |||
{ | |||
if (entityView is U) | |||
{ | |||
Remove((U) entityView); | |||
} | |||
else | |||
{ | |||
base.Remove(entityView); | |||
} | |||
} | |||
} | |||
public abstract class MultiEntityViewsEngine<T, U, V> : MultiEntityViewsEngine<T, U> | |||
where T : EntityView, new() | |||
where U : EntityView, new() | |||
where V : EntityView, new() | |||
{ | |||
protected abstract void Add(V entityView); | |||
protected abstract void Remove(V entityView); | |||
public override void Add(IEntityView entityView) | |||
{ | |||
var castedEntityView = entityView as V; | |||
if (castedEntityView != null) | |||
{ | |||
Add(castedEntityView); | |||
} | |||
else | |||
base.Add(entityView); | |||
} | |||
public override void Remove(IEntityView entityView) | |||
{ | |||
var castedEntityView = entityView as V; | |||
if (castedEntityView != null) | |||
{ | |||
Remove(castedEntityView); | |||
} | |||
else | |||
base.Remove(entityView); | |||
} | |||
} | |||
} |
@@ -1,36 +0,0 @@ | |||
namespace Svelto.ECS.Internal | |||
{ | |||
sealed class RemoveEntityImplementor : IRemoveEntityComponent | |||
{ | |||
public RemoveEntityImplementor(IEntityViewBuilder[] entityViews, int groupID):this(entityViews) | |||
{ | |||
this.groupID = groupID; | |||
isInAGroup = true; | |||
} | |||
internal RemoveEntityImplementor(IEntityViewBuilder[] entityViews) | |||
{ | |||
removeEntityInfo = new RemoveEntityInfo(entityViews); | |||
} | |||
readonly internal RemoveEntityInfo removeEntityInfo; | |||
readonly internal int groupID; | |||
readonly internal bool isInAGroup; | |||
} | |||
} | |||
namespace Svelto.ECS | |||
{ | |||
public interface IRemoveEntityComponent | |||
{} | |||
public struct RemoveEntityInfo | |||
{ | |||
readonly internal IEntityViewBuilder[] entityViewsToBuild; | |||
public RemoveEntityInfo(IEntityViewBuilder[] entityViews) : this() | |||
{ | |||
this.entityViewsToBuild = entityViews; | |||
} | |||
} | |||
} |
@@ -1,20 +0,0 @@ | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public abstract class SingleEntityViewEngine<T> : IHandleEntityViewEngine where T:EntityView, new() | |||
{ | |||
public void Add(IEntityView entityView) | |||
{ | |||
Add((T)entityView); //when byref returns will be vailable, this should be passed by reference, not copy! | |||
} | |||
public void Remove(IEntityView entityView) | |||
{ | |||
Remove((T)entityView); | |||
} | |||
protected abstract void Add(T entityView); | |||
protected abstract void Remove(T entityView); | |||
} | |||
} |
@@ -1,42 +0,0 @@ | |||
using System; | |||
namespace Svelto.Observer | |||
{ | |||
public delegate void ObserverAction<DispatchType>(ref DispatchType parameter); | |||
public interface IObservable | |||
{ | |||
event Action Notify; | |||
void Dispatch(); | |||
} | |||
public interface IObservable<DispatchType> | |||
{ | |||
event ObserverAction<DispatchType> Notify; | |||
void Dispatch(ref DispatchType parameter); | |||
} | |||
public class Observable<DispatchType>:IObservable<DispatchType> | |||
{ | |||
public event ObserverAction<DispatchType> Notify; | |||
public void Dispatch(ref DispatchType parameter) | |||
{ | |||
if (Notify != null) | |||
Notify(ref parameter); | |||
} | |||
} | |||
public class Observable:IObservable | |||
{ | |||
public event Action Notify; | |||
public void Dispatch() | |||
{ | |||
if (Notify != null) | |||
Notify(); | |||
} | |||
} | |||
} |
@@ -1,111 +0,0 @@ | |||
using System; | |||
namespace Svelto.Observer.InterNamespace | |||
{ | |||
public abstract class Observer<DispatchType, ActionType> : IObserver<ActionType> | |||
{ | |||
protected Observer(Observable<DispatchType> observable) | |||
{ | |||
observable.Notify += OnObservableDispatched; | |||
_unsubscribe = () => observable.Notify -= OnObservableDispatched; | |||
} | |||
public void AddAction(ObserverAction<ActionType> action) | |||
{ | |||
_actions += action; | |||
} | |||
public void RemoveAction(ObserverAction<ActionType> action) | |||
{ | |||
_actions -= action; | |||
} | |||
public void Unsubscribe() | |||
{ | |||
_unsubscribe(); | |||
} | |||
void OnObservableDispatched(ref DispatchType dispatchNotification) | |||
{ | |||
if (_actions != null) | |||
{ | |||
var actionType = TypeMap(ref dispatchNotification); | |||
_actions(ref actionType); | |||
} | |||
} | |||
protected abstract ActionType TypeMap(ref DispatchType dispatchNotification); | |||
ObserverAction<ActionType> _actions; | |||
Action _unsubscribe; | |||
} | |||
} | |||
namespace Svelto.Observer.IntraNamespace | |||
{ | |||
public class Observer<DispatchType> : InterNamespace.Observer<DispatchType, DispatchType> | |||
{ | |||
public Observer(Observable<DispatchType> observable) : base(observable) | |||
{ } | |||
protected override DispatchType TypeMap(ref DispatchType dispatchNotification) | |||
{ | |||
return dispatchNotification; | |||
} | |||
} | |||
} | |||
namespace Svelto.Observer | |||
{ | |||
public class Observer: IObserver | |||
{ | |||
public Observer(Observable observable) | |||
{ | |||
observable.Notify += OnObservableDispatched; | |||
_unsubscribe = () => observable.Notify -= OnObservableDispatched; | |||
} | |||
public void AddAction(Action action) | |||
{ | |||
_actions += action; | |||
} | |||
public void RemoveAction(Action action) | |||
{ | |||
_actions -= action; | |||
} | |||
public void Unsubscribe() | |||
{ | |||
_unsubscribe(); | |||
} | |||
void OnObservableDispatched() | |||
{ | |||
if (_actions != null) | |||
_actions(); | |||
} | |||
Action _actions; | |||
readonly Action _unsubscribe; | |||
} | |||
public interface IObserver<WatchingType> | |||
{ | |||
void AddAction(ObserverAction<WatchingType> action); | |||
void RemoveAction(ObserverAction<WatchingType> action); | |||
void Unsubscribe(); | |||
} | |||
public interface IObserver | |||
{ | |||
void AddAction(Action action); | |||
void RemoveAction(Action action); | |||
void Unsubscribe(); | |||
} | |||
} |
@@ -1,91 +0,0 @@ | |||
using System; | |||
using System.Reflection; | |||
using System.Reflection.Emit; | |||
using System.Linq.Expressions; | |||
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<T> where T : class | |||
{ | |||
#if ENABLE_IL2CPP | |||
public static CastedAction<CastedType> MakeSetter<CastedType>(FieldInfo field) where CastedType:class | |||
{ | |||
if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false) | |||
{ | |||
return new CastedAction<CastedType, T>(field.SetValue); | |||
} | |||
throw new ArgumentException("<color=orange>Svelto.ECS</color> unsupported field (must be an interface and a class)"); | |||
} | |||
#elif !NETFX_CORE | |||
public static CastedAction<CastedType> MakeSetter<CastedType>(FieldInfo field) where CastedType:class | |||
{ | |||
if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false) | |||
{ | |||
DynamicMethod m = new DynamicMethod("setter", typeof(void), new Type[] { typeof(T), typeof(object) }); | |||
ILGenerator cg = m.GetILGenerator(); | |||
// arg0.<field> = arg1 | |||
cg.Emit(OpCodes.Ldarg_0); | |||
cg.Emit(OpCodes.Ldarg_1); | |||
cg.Emit(OpCodes.Stfld, field); | |||
cg.Emit(OpCodes.Ret); | |||
var del = m.CreateDelegate(typeof(Action<T, object>)); | |||
return new CastedAction<CastedType, T>(del); | |||
} | |||
throw new ArgumentException("<color=orange>Svelto.ECS</color> unsupported field (must be an interface and a class)"); | |||
} | |||
#else | |||
public static CastedAction<CastedType> MakeSetter<CastedType>(FieldInfo field) where CastedType:class | |||
{ | |||
if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false) | |||
{ | |||
ParameterExpression targetExp = Expression.Parameter(typeof(T), "target"); | |||
ParameterExpression valueExp = Expression.Parameter(typeof(object), "value"); | |||
MemberExpression fieldExp = Expression.Field(targetExp, field); | |||
UnaryExpression convertedExp = Expression.TypeAs(valueExp, field.FieldType); | |||
BinaryExpression assignExp = Expression.Assign(fieldExp, convertedExp); | |||
Type type = typeof(Action<,>).MakeGenericType(new Type[] { typeof(T), typeof(object) }); | |||
var setter = Expression.Lambda(type, assignExp, targetExp, valueExp).Compile(); | |||
return new CastedAction<CastedType, T>(setter); | |||
} | |||
throw new ArgumentException("<color=orange>Svelto.ECS</color> unsupported field (must be an interface and a class)"); | |||
} | |||
#endif | |||
} | |||
public abstract class CastedAction<W> | |||
{ | |||
abstract public void Call(W target, object value); | |||
} | |||
public class CastedAction<W, T> : CastedAction<W> where W : class where T:class | |||
{ | |||
Action<T, object> setter; | |||
public CastedAction(Delegate setter) | |||
{ | |||
this.setter = (Action<T, object>)setter; | |||
} | |||
public CastedAction(Action<T, object> setter) | |||
{ | |||
this.setter = setter; | |||
} | |||
override public void Call(W target, object value) | |||
{ | |||
setter(target as T, value); | |||
} | |||
} | |||
} |
@@ -1,170 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Reflection; | |||
using System.Runtime.CompilerServices; | |||
using Svelto.DataStructures; | |||
public static class NetFXCoreWrappers | |||
{ | |||
public static Type GetDeclaringType(this MethodInfo methodInfo) | |||
{ | |||
#if NETFX_CORE | |||
return methodInfo.DeclaringType; | |||
#else | |||
return methodInfo.ReflectedType; | |||
#endif | |||
} | |||
public static MethodInfo GetMethodInfoEx(this Delegate delegateEx) | |||
{ | |||
#if NETFX_CORE | |||
var method = delegateEx.GetMethodInfo(); | |||
#else | |||
var method = delegateEx.Method; | |||
#endif | |||
return method; | |||
} | |||
public static Type[] GetInterfacesEx(this Type type) | |||
{ | |||
#if NETFX_CORE | |||
return type.GetInterfaces(); | |||
#else | |||
return type.GetInterfaces(); | |||
#endif | |||
} | |||
public static bool IsInterfaceEx(this Type type) | |||
{ | |||
#if NETFX_CORE | |||
return type.GetTypeInfo().IsInterface; | |||
#else | |||
return type.IsInterface; | |||
#endif | |||
} | |||
public static bool IsValueTypeEx(this Type type) | |||
{ | |||
#if NETFX_CORE | |||
return type.GetTypeInfo().IsValueType; | |||
#else | |||
return type.IsValueType; | |||
#endif | |||
} | |||
public static Type GetDeclaringType(this MemberInfo memberInfo) | |||
{ | |||
#if NETFX_CORE | |||
return memberInfo.DeclaringType; | |||
#else | |||
return memberInfo.ReflectedType; | |||
#endif | |||
} | |||
public static Type GetBaseType(this Type type) | |||
{ | |||
#if NETFX_CORE | |||
return type.GetTypeInfo().BaseType; | |||
#else | |||
return type.BaseType; | |||
#endif | |||
} | |||
public static IEnumerable<Attribute> GetCustomAttributes(this Type type, bool inherit) | |||
{ | |||
#if !NETFX_CORE | |||
return Attribute.GetCustomAttributes(type, inherit); | |||
#else | |||
return type.GetTypeInfo().GetCustomAttributes(inherit); | |||
#endif | |||
} | |||
public static bool ContainsCustomAttribute(this MemberInfo memberInfo, Type customAttribute, bool inherit) | |||
{ | |||
#if !NETFX_CORE | |||
return Attribute.IsDefined(memberInfo, customAttribute, inherit); | |||
#else | |||
return memberInfo.GetCustomAttribute(customAttribute, inherit) != null; | |||
#endif | |||
} | |||
public static bool IsGenericTypeEx(this Type type) | |||
{ | |||
#if !NETFX_CORE | |||
return type.IsGenericType; | |||
#else | |||
return type.IsConstructedGenericType; | |||
#endif | |||
} | |||
public static Type[] GetGenericArgumentsEx(this Type type) | |||
{ | |||
#if !NETFX_CORE | |||
return type.GetGenericArguments(); | |||
#else | |||
var typeinfo = type.GetTypeInfo(); | |||
return typeinfo.IsGenericTypeDefinition | |||
? typeinfo.GenericTypeParameters | |||
: typeinfo.GenericTypeArguments; | |||
#endif | |||
} | |||
public static MemberInfo[] FindWritablePropertiesWithCustomAttribute(this Type contract, | |||
Type customAttributeType) | |||
{ | |||
FasterList<MemberInfo> propertyList = new FasterList<MemberInfo>(8); | |||
do | |||
{ | |||
var propertyInfos = contract.GetProperties(System.Reflection.BindingFlags.Public | | |||
System.Reflection.BindingFlags.NonPublic | | |||
System.Reflection.BindingFlags.DeclaredOnly | | |||
System.Reflection.BindingFlags.Instance); | |||
for (int i = 0; i < propertyInfos.Length; i++) | |||
{ | |||
PropertyInfo propertyInfo = propertyInfos[i]; | |||
if (propertyInfo.CanWrite && | |||
propertyInfo.ContainsCustomAttribute(customAttributeType, false) == true) | |||
propertyList.Add(propertyInfo); | |||
} | |||
contract = contract.GetBaseType(); | |||
} while (contract != null); | |||
if (propertyList.Count > 0) | |||
return propertyList.ToArray(); | |||
return null; | |||
} | |||
public static bool IsCompilerGenerated(this Type t) | |||
{ | |||
#if NETFX_CORE | |||
var attr = t.GetTypeInfo().GetCustomAttribute(typeof(CompilerGeneratedAttribute)); | |||
return attr != null; | |||
#else | |||
var attr = Attribute.IsDefined(t, typeof(CompilerGeneratedAttribute)); | |||
return attr; | |||
#endif | |||
} | |||
public static bool IsCompilerGenerated(this MemberInfo memberInfo) | |||
{ | |||
#if NETFX_CORE | |||
var attr = memberInfo.DeclaringType.GetTypeInfo().GetCustomAttribute(_compilerType); | |||
return attr != null; | |||
#else | |||
var attr = Attribute.IsDefined(memberInfo, _compilerType); | |||
return attr; | |||
#endif | |||
} | |||
static readonly Type _compilerType = typeof(CompilerGeneratedAttribute); | |||
} | |||
@@ -1,16 +0,0 @@ | |||
using System.Threading; | |||
namespace Svelto.Utilities | |||
{ | |||
public static class ThreadUtility | |||
{ | |||
public static void MemoryBarrier() | |||
{ | |||
#if NETFX_CORE || NET_4_6 | |||
Interlocked.MemoryBarrier(); | |||
#else | |||
Thread.MemoryBarrier(); | |||
#endif | |||
} | |||
} | |||
} |