Browse Source

- optimize even more

- some renaming
tags/Rel2b
sebas77 6 years ago
parent
commit
c8f57253fc
17 changed files with 284 additions and 185 deletions
  1. +1
    -1
      DataStructures/FasterList.cs
  2. +33
    -32
      DataStructures/LockFreeQueue.cs
  3. +101
    -99
      DataStructures/PriorityQueue/HeapPriorityQueue.cs
  4. +5
    -5
      DataStructures/PriorityQueue/IPriorityQueue.cs
  5. +3
    -3
      DataStructures/PriorityQueue/PriorityQueueNode.cs
  6. +35
    -0
      ECS/DataStructures/TypeSafeFasterListForECS.cs
  7. +0
    -0
      ECS/EngineEntityViewDB.cs
  8. +42
    -14
      ECS/EnginesRoot.cs
  9. +26
    -15
      ECS/EntityDescriptorTemplate.cs
  10. +1
    -1
      ECS/EntitySubmissionScheduler.cs
  11. +0
    -0
      ECS/EntityView.cs
  12. +21
    -0
      ECS/EntityViewBuilder.cs
  13. +0
    -0
      ECS/IEngineEntityViewDB.cs
  14. +2
    -7
      ECS/IEnginesInterfaces.cs
  15. +0
    -0
      ECS/MultiEntityViewsEngine.cs
  16. +0
    -0
      ECS/SingleEntityViewEngine.cs
  17. +14
    -8
      Utilities/FastInvoke.cs

+ 1
- 1
DataStructures/FasterList.cs View File

@@ -788,7 +788,7 @@ namespace Svelto.DataStructures
_buffer = newList;
}

public void Trim()
public void Trim()
{
if (_count < _buffer.Length)
Resize(_count);


+ 33
- 32
DataStructures/LockFreeQueue.cs View File

@@ -1,13 +1,14 @@
using System.Collections.Generic;
using System.Threading;

//from unify wiki
namespace Svelto.DataStructures
{
public class SingleLinkEntityView<T>
public class SingleLinkNode<T>
{
// Note; the Next member cannot be a property since
// it participates in many CAS operations
public SingleLinkEntityView<T> Next;
public SingleLinkNode<T> Next;
public T Item;
}

@@ -23,33 +24,33 @@ namespace Svelto.DataStructures

public class LockFreeLinkPool<T>
{
private SingleLinkEntityView<T> head;
private SingleLinkNode<T> head;

public LockFreeLinkPool()
{
head = new SingleLinkEntityView<T>();
head = new SingleLinkNode<T>();
}

public void Push(SingleLinkEntityView<T> newEntityView)
public void Push(SingleLinkNode<T> newNode)
{
newEntityView.Item = default(T);
newNode.Item = default(T);
do
{
newEntityView.Next = head.Next;
} while (!SyncMethods.CAS<SingleLinkEntityView<T>>(ref head.Next, newEntityView.Next, newEntityView));
newNode.Next = head.Next;
} while (!SyncMethods.CAS<SingleLinkNode<T>>(ref head.Next, newNode.Next, newNode));
return;
}

public bool Pop(out SingleLinkEntityView<T> entityView)
public bool Pop(out SingleLinkNode<T> node)
{
do
{
entityView = head.Next;
if (entityView == null)
node = head.Next;
if (node == null)
{
return false;
}
} while (!SyncMethods.CAS<SingleLinkEntityView<T>>(ref head.Next, entityView, entityView.Next));
} while (!SyncMethods.CAS<SingleLinkNode<T>>(ref head.Next, node, node.Next));
return true;
}
}
@@ -57,35 +58,35 @@ namespace Svelto.DataStructures
public class LockFreeQueue<T>
{

SingleLinkEntityView<T> head;
SingleLinkEntityView<T> tail;
SingleLinkNode<T> head;
SingleLinkNode<T> tail;
LockFreeLinkPool<T> trash;

public LockFreeQueue()
{
head = new SingleLinkEntityView<T>();
head = new SingleLinkNode<T>();
tail = head;
trash = new LockFreeLinkPool<T>();
}

public void Enqueue(T item)
{
SingleLinkEntityView<T> oldTail = null;
SingleLinkEntityView<T> oldTailNext;
SingleLinkNode<T> oldTail = null;
SingleLinkNode<T> oldTailNext;

SingleLinkEntityView<T> newEntityView;
if (!trash.Pop(out newEntityView))
SingleLinkNode<T> newNode;
if (!trash.Pop(out newNode))
{
newEntityView = new SingleLinkEntityView<T>();
newNode = new SingleLinkNode<T>();
}
else
{
newEntityView.Next = null;
newNode.Next = null;
}
newEntityView.Item = item;
newNode.Item = item;

bool newEntityViewWasAdded = false;
while (!newEntityViewWasAdded)
bool newNodeWasAdded = false;
while (!newNodeWasAdded)
{
oldTail = tail;
oldTailNext = oldTail.Next;
@@ -93,26 +94,26 @@ namespace Svelto.DataStructures
if (tail == oldTail)
{
if (oldTailNext == null)
newEntityViewWasAdded = SyncMethods.CAS<SingleLinkEntityView<T>>(ref tail.Next, null, newEntityView);
newNodeWasAdded = SyncMethods.CAS<SingleLinkNode<T>>(ref tail.Next, null, newNode);
else
SyncMethods.CAS<SingleLinkEntityView<T>>(ref tail, oldTail, oldTailNext);
SyncMethods.CAS<SingleLinkNode<T>>(ref tail, oldTail, oldTailNext);
}
}
SyncMethods.CAS<SingleLinkEntityView<T>>(ref tail, oldTail, newEntityView);
SyncMethods.CAS<SingleLinkNode<T>>(ref tail, oldTail, newNode);
}

public bool Dequeue(out T item)
{
item = default(T);
SingleLinkEntityView<T> oldHead = null;
SingleLinkNode<T> oldHead = null;

bool haveAdvancedHead = false;
while (!haveAdvancedHead)
{

oldHead = head;
SingleLinkEntityView<T> oldTail = tail;
SingleLinkEntityView<T> oldHeadNext = oldHead.Next;
SingleLinkNode<T> oldTail = tail;
SingleLinkNode<T> oldHeadNext = oldHead.Next;

if (oldHead == head)
{
@@ -122,12 +123,12 @@ namespace Svelto.DataStructures
{
return false;
}
SyncMethods.CAS<SingleLinkEntityView<T>>(ref tail, oldTail, oldHeadNext);
SyncMethods.CAS<SingleLinkNode<T>>(ref tail, oldTail, oldHeadNext);
}
else
{
item = oldHeadNext.Item;
haveAdvancedHead = SyncMethods.CAS<SingleLinkEntityView<T>>(ref head, oldHead, oldHeadNext);
haveAdvancedHead = SyncMethods.CAS<SingleLinkNode<T>>(ref head, oldHead, oldHeadNext);
if (haveAdvancedHead)
{
trash.Push(oldHead);


+ 101
- 99
DataStructures/PriorityQueue/HeapPriorityQueue.cs View File

@@ -1,5 +1,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Svelto.DataStructures;

namespace Svelto.DataStructures
{
@@ -7,40 +9,40 @@ namespace Svelto.DataStructures
/// An implementation of a min-Priority Queue using a heap. Has O(1) .Contains()!
/// See https://bitbucket.org/BlueRaja/high-speed-priority-queue-for-c/wiki/Getting%20Started for more information
/// </summary>
/// <typeparam name="T">The values in the queue. Must implement the PriorityQueueEntityView interface</typeparam>
/// <typeparam name="T">The values in the queue. Must implement the PriorityQueueNode interface</typeparam>
public sealed class HeapPriorityQueue<T> : IPriorityQueue<T>
where T : PriorityQueueEntityView
where T : PriorityQueueNode
{
private int _numEntityViews;
private readonly FasterList<T> _entityViews;
private long _numEntityViewsEverEnqueued;
private int _numNodes;
private readonly FasterList<T> _nodes;
private long _numNodesEverEnqueued;

/// <summary>
/// Instantiate a new Priority Queue
/// </summary>
/// <param name="maxEntityViews">The max entityViews ever allowed to be enqueued (going over this will cause an exception)</param>
/// <param name="maxNodes">The max nodes ever allowed to be enqueued (going over this will cause an exception)</param>
public HeapPriorityQueue()
{
_numEntityViews = 0;
_entityViews = new FasterList<T>();
_numEntityViewsEverEnqueued = 0;
_numNodes = 0;
_nodes = new FasterList<T>();
_numNodesEverEnqueued = 0;
}

public HeapPriorityQueue(int initialSize)
{
_numEntityViews = 0;
_entityViews = new FasterList<T>(initialSize);
_numEntityViewsEverEnqueued = 0;
_numNodes = 0;
_nodes = new FasterList<T>(initialSize);
_numNodesEverEnqueued = 0;
}
/// <summary>
/// Returns the number of entityViews in the queue. O(1)
/// Returns the number of nodes in the queue. O(1)
/// </summary>
public int Count
{
get
{
return _numEntityViews;
return _numNodes;
}
}

@@ -52,119 +54,119 @@ namespace Svelto.DataStructures
{
get
{
return _entityViews.Count - 1;
return _nodes.Count - 1;
}
}

/// <summary>
/// Removes every entityView from the queue. O(n) (So, don't do this often!)
/// Removes every node from the queue. O(n) (So, don't do this often!)
/// </summary>
#if NET_VERSION_4_5
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public void Clear()
{
_entityViews.FastClear();
_nodes.FastClear();

_numEntityViews = 0;
_numNodes = 0;
}

/// <summary>
/// Returns (in O(1)!) whether the given entityView is in the queue. O(1)
/// Returns (in O(1)!) whether the given node is in the queue. O(1)
/// </summary>
#if NET_VERSION_4_5
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public bool Contains(T entityView)
public bool Contains(T node)
{
return (_entityViews[entityView.QueueIndex] == entityView);
return (_nodes[node.QueueIndex] == node);
}

/// <summary>
/// Enqueue a entityView - .Priority must be set beforehand! O(log n)
/// Enqueue a node - .Priority must be set beforehand! O(log n)
/// </summary>
#if NET_VERSION_4_5
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public void Enqueue(T entityView, double priority)
public void Enqueue(T node, double priority)
{
entityView.Priority = priority;
_numEntityViews++;
if (_entityViews.Count < _numEntityViews)
_entityViews.Resize(_numEntityViews + 1);
_entityViews[_numEntityViews] = entityView;
entityView.QueueIndex = _numEntityViews;
entityView.InsertionIndex = _numEntityViewsEverEnqueued++;
CascadeUp(_entityViews[_numEntityViews]);
node.Priority = priority;
_numNodes++;
if (_nodes.Count < _numNodes)
_nodes.Resize(_numNodes + 1);
_nodes[_numNodes] = node;
node.QueueIndex = _numNodes;
node.InsertionIndex = _numNodesEverEnqueued++;
CascadeUp(_nodes[_numNodes]);
}

#if NET_VERSION_4_5
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
private void Swap(T entityView1, T entityView2)
private void Swap(T node1, T node2)
{
//Swap the entityViews
_entityViews[entityView1.QueueIndex] = entityView2;
_entityViews[entityView2.QueueIndex] = entityView1;
//Swap the nodes
_nodes[node1.QueueIndex] = node2;
_nodes[node2.QueueIndex] = node1;

//Swap their indicies
int temp = entityView1.QueueIndex;
entityView1.QueueIndex = entityView2.QueueIndex;
entityView2.QueueIndex = temp;
int temp = node1.QueueIndex;
node1.QueueIndex = node2.QueueIndex;
node2.QueueIndex = temp;
}

//Performance appears to be slightly better when this is NOT inlined o_O
private void CascadeUp(T entityView)
private void CascadeUp(T node)
{
//aka Heapify-up
int parent = entityView.QueueIndex / 2;
int parent = node.QueueIndex / 2;
while(parent >= 1)
{
T parentEntityView = _entityViews[parent];
if(HasHigherPriority(parentEntityView, entityView))
T parentNode = _nodes[parent];
if(HasHigherPriority(parentNode, node))
break;

//EntityView has lower priority value, so move it up the heap
Swap(entityView, parentEntityView); //For some reason, this is faster with Swap() rather than (less..?) individual operations, like in CascadeDown()
//Node has lower priority value, so move it up the heap
Swap(node, parentNode); //For some reason, this is faster with Swap() rather than (less..?) individual operations, like in CascadeDown()

parent = entityView.QueueIndex / 2;
parent = node.QueueIndex / 2;
}
}

#if NET_VERSION_4_5
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
private void CascadeDown(T entityView)
private void CascadeDown(T node)
{
//aka Heapify-down
T newParent;
int finalQueueIndex = entityView.QueueIndex;
int finalQueueIndex = node.QueueIndex;
while(true)
{
newParent = entityView;
newParent = node;
int childLeftIndex = 2 * finalQueueIndex;

//Check if the left-child is higher-priority than the current entityView
if(childLeftIndex > _numEntityViews)
//Check if the left-child is higher-priority than the current node
if(childLeftIndex > _numNodes)
{
//This could be placed outside the loop, but then we'd have to check newParent != entityView twice
entityView.QueueIndex = finalQueueIndex;
_entityViews[finalQueueIndex] = entityView;
//This could be placed outside the loop, but then we'd have to check newParent != node twice
node.QueueIndex = finalQueueIndex;
_nodes[finalQueueIndex] = node;
break;
}

T childLeft = _entityViews[childLeftIndex];
T childLeft = _nodes[childLeftIndex];
if(HasHigherPriority(childLeft, newParent))
{
newParent = childLeft;
}

//Check if the right-child is higher-priority than either the current entityView or the left child
//Check if the right-child is higher-priority than either the current node or the left child
int childRightIndex = childLeftIndex + 1;
if(childRightIndex <= _numEntityViews)
if(childRightIndex <= _numNodes)
{
T childRight = _entityViews[childRightIndex];
T childRight = _nodes[childRightIndex];
if(HasHigherPriority(childRight, newParent))
{
newParent = childRight;
@@ -172,11 +174,11 @@ namespace Svelto.DataStructures
}

//If either of the children has higher (smaller) priority, swap and continue cascading
if(newParent != entityView)
if(newParent != node)
{
//Move new parent to its new index. entityView will be moved once, at the end
//Move new parent to its new index. node will be moved once, at the end
//Doing it this way is one less assignment operation than calling Swap()
_entityViews[finalQueueIndex] = newParent;
_nodes[finalQueueIndex] = newParent;

int temp = newParent.QueueIndex;
newParent.QueueIndex = finalQueueIndex;
@@ -185,8 +187,8 @@ namespace Svelto.DataStructures
else
{
//See note above
entityView.QueueIndex = finalQueueIndex;
_entityViews[finalQueueIndex] = entityView;
node.QueueIndex = finalQueueIndex;
_nodes[finalQueueIndex] = node;
break;
}
}
@@ -194,7 +196,7 @@ namespace Svelto.DataStructures

/// <summary>
/// Returns true if 'higher' has higher priority than 'lower', false otherwise.
/// Note that calling HasHigherPriority(entityView, entityView) (ie. both arguments the same entityView) will return false
/// Note that calling HasHigherPriority(node, node) (ie. both arguments the same node) will return false
/// </summary>
#if NET_VERSION_4_5
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -206,11 +208,11 @@ namespace Svelto.DataStructures
}

/// <summary>
/// Removes the head of the queue (entityView with highest priority; ties are broken by order of insertion), and returns it. O(log n)
/// Removes the head of the queue (node with highest priority; ties are broken by order of insertion), and returns it. O(log n)
/// </summary>
public T Dequeue()
{
T returnMe = _entityViews[1];
T returnMe = _nodes[1];
Remove(returnMe);
return returnMe;
}
@@ -222,77 +224,77 @@ namespace Svelto.DataStructures
{
get
{
return _entityViews[1];
return _nodes[1];
}
}

/// <summary>
/// This method must be called on a entityView every time its priority changes while it is in the queue.
/// This method must be called on a node every time its priority changes while it is in the queue.
/// <b>Forgetting to call this method will result in a corrupted queue!</b>
/// O(log n)
/// </summary>
#if NET_VERSION_4_5
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public void UpdatePriority(T entityView, double priority)
public void UpdatePriority(T node, double priority)
{
entityView.Priority = priority;
OnEntityViewUpdated(entityView);
node.Priority = priority;
OnNodeUpdated(node);
}

private void OnEntityViewUpdated(T entityView)
private void OnNodeUpdated(T node)
{
//Bubble the updated entityView up or down as appropriate
int parentIndex = entityView.QueueIndex / 2;
T parentEntityView = _entityViews[parentIndex];
//Bubble the updated node up or down as appropriate
int parentIndex = node.QueueIndex / 2;
T parentNode = _nodes[parentIndex];

if(parentIndex > 0 && HasHigherPriority(entityView, parentEntityView))
if(parentIndex > 0 && HasHigherPriority(node, parentNode))
{
CascadeUp(entityView);
CascadeUp(node);
}
else
{
//Note that CascadeDown will be called if parentEntityView == entityView (that is, entityView is the root)
CascadeDown(entityView);
//Note that CascadeDown will be called if parentNode == node (that is, node is the root)
CascadeDown(node);
}
}

/// <summary>
/// Removes a entityView from the queue. Note that the entityView does not need to be the head of the queue. O(log n)
/// Removes a node from the queue. Note that the node does not need to be the head of the queue. O(log n)
/// </summary>
public void Remove(T entityView)
public void Remove(T node)
{
if(_numEntityViews <= 1)
if(_numNodes <= 1)
{
_entityViews[1] = null;
_numEntityViews = 0;
_nodes[1] = null;
_numNodes = 0;
return;
}

//Make sure the entityView is the last entityView in the queue
//Make sure the node is the last node in the queue
bool wasSwapped = false;
T formerLastEntityView = _entityViews[_numEntityViews];
if(entityView.QueueIndex != _numEntityViews)
T formerLastNode = _nodes[_numNodes];
if(node.QueueIndex != _numNodes)
{
//Swap the entityView with the last entityView
Swap(entityView, formerLastEntityView);
//Swap the node with the last node
Swap(node, formerLastNode);
wasSwapped = true;
}

_numEntityViews--;
_entityViews[entityView.QueueIndex] = null;
_numNodes--;
_nodes[node.QueueIndex] = null;

if(wasSwapped)
{
//Now bubble formerLastEntityView (which is no longer the last entityView) up or down as appropriate
OnEntityViewUpdated(formerLastEntityView);
//Now bubble formerLastNode (which is no longer the last node) up or down as appropriate
OnNodeUpdated(formerLastNode);
}
}

public IEnumerator<T> GetEnumerator()
{
for(int i = 1; i <= _numEntityViews; i++)
yield return _entityViews[i];
for(int i = 1; i <= _numNodes; i++)
yield return _nodes[i];
}

IEnumerator IEnumerable.GetEnumerator()
@@ -306,16 +308,16 @@ namespace Svelto.DataStructures
/// </summary>
public bool IsValidQueue()
{
for(int i = 1; i < _entityViews.Count; i++)
for(int i = 1; i < _nodes.Count; i++)
{
if(_entityViews[i] != null)
if(_nodes[i] != null)
{
int childLeftIndex = 2 * i;
if(childLeftIndex < _entityViews.Count && _entityViews[childLeftIndex] != null && HasHigherPriority(_entityViews[childLeftIndex], _entityViews[i]))
if(childLeftIndex < _nodes.Count && _nodes[childLeftIndex] != null && HasHigherPriority(_nodes[childLeftIndex], _nodes[i]))
return false;

int childRightIndex = childLeftIndex + 1;
if(childRightIndex < _entityViews.Count && _entityViews[childRightIndex] != null && HasHigherPriority(_entityViews[childRightIndex], _entityViews[i]))
if(childRightIndex < _nodes.Count && _nodes[childRightIndex] != null && HasHigherPriority(_nodes[childRightIndex], _nodes[i]))
return false;
}
}


+ 5
- 5
DataStructures/PriorityQueue/IPriorityQueue.cs View File

@@ -8,16 +8,16 @@ namespace Svelto.DataStructures
/// (theoretically?) optimize method calls from concrete-types slightly better.
/// </summary>
public interface IPriorityQueue<T> : IEnumerable<T>
where T : PriorityQueueEntityView
where T : PriorityQueueNode
{
void Remove(T entityView);
void UpdatePriority(T entityView, double priority);
void Enqueue(T entityView, double priority);
void Remove(T node);
void UpdatePriority(T node, double priority);
void Enqueue(T node, double priority);
T Dequeue();
T First { get; }
int Count { get; }
int MaxSize { get; }
void Clear();
bool Contains(T entityView);
bool Contains(T node);
}
}

+ 3
- 3
DataStructures/PriorityQueue/PriorityQueueNode.cs View File

@@ -1,9 +1,9 @@
namespace Svelto.DataStructures
{
public class PriorityQueueEntityView
public class PriorityQueueNode
{
/// <summary>
/// The Priority to insert this entityView at. Must be set BEFORE adding a entityView to the queue
/// The Priority to insert this node at. Must be set BEFORE adding a node to the queue
/// </summary>
public double Priority { get;
set;
@@ -11,7 +11,7 @@

/// <summary>
/// <b>Used by the priority queue - do not edit this value.</b>
/// Represents the order the entityView was inserted in
/// Represents the order the node was inserted in
/// </summary>
public long InsertionIndex { get; set; }



+ 35
- 0
ECS/DataStructures/TypeSafeFasterListForECS.cs View File

@@ -10,10 +10,12 @@ namespace Svelto.ECS.Internal
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);
}

class TypeSafeFasterListForECS<T>: FasterList<T> where T:IEntityView
@@ -22,6 +24,11 @@ namespace Svelto.ECS.Internal
{
_mappedIndices = new Dictionary<int, int>();
}

protected TypeSafeFasterListForECS(int size):base(size)
{
_mappedIndices = new Dictionary<int, int>();
}
public bool UnorderedRemove(int entityID)
{
@@ -47,11 +54,23 @@ namespace Svelto.ECS.Internal
_mappedIndices[this[i].ID] = i;
}

public void ReserveCapacity(int capacity)
{
if (this.ToArrayFast().Length < capacity)
Resize(capacity);
}

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>();
@@ -71,10 +90,21 @@ namespace Svelto.ECS.Internal
{
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>();
@@ -96,5 +126,10 @@ namespace Svelto.ECS.Internal
return this.ToArrayFast();
}

public ITypeSafeList Create(int size)
{
return new TypeSafeFasterListForECSForClasses<T>(size);
}
}
}

ECS/EngineNodeDB.cs → ECS/EngineEntityViewDB.cs View File


+ 42
- 14
ECS/EnginesRoot.cs View File

@@ -18,9 +18,9 @@ using Svelto.ECS.Profiler;

namespace Svelto.ECS
{
public sealed class EnginesRoot : IEntityFunctions, IEntityFactory, IDisposable
public sealed class EnginesRoot : IDisposable
{
public EnginesRoot(EntityViewSubmissionScheduler entityViewScheduler)
public EnginesRoot(EntitySubmissionScheduler entityViewScheduler)
{
_entityViewEngines = new Dictionary<Type, FasterList<IHandleEntityViewEngine>>();
_otherEngines = new FasterList<IEngine>();
@@ -66,13 +66,13 @@ namespace Svelto.ECS
return new GenericEntityFunctions(new DataStructures.WeakReference<EnginesRoot>(this));
}
public void BuildEntity<T>(int entityID, object[] implementors = null) where T:IEntityDescriptor, new()
void BuildEntity<T>(int entityID, object[] implementors = null) where T:IEntityDescriptor, new()
{
EntityFactory.BuildEntityViews
(entityID, _entityViewsToAdd.current, EntityDescriptorTemplate<T>.Default, implementors);
}

public void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null)
void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null)
{
EntityFactory.BuildEntityViews
(entityID, _entityViewsToAdd.current, entityDescriptor, implementors);
@@ -103,7 +103,7 @@ namespace Svelto.ECS
/// <param name="metaEntityID"></param>
/// <param name="ed"></param>
/// <param name="implementors"></param>
public void BuildMetaEntity<T>(int metaEntityID, object[] implementors) where T:IEntityDescriptor, new()
void BuildMetaEntity<T>(int metaEntityID, object[] implementors) where T:IEntityDescriptor, new()
{
EntityFactory.BuildEntityViews(metaEntityID, _entityViewsToAdd.current,
EntityDescriptorTemplate<T>.Default, implementors);
@@ -119,7 +119,7 @@ namespace Svelto.ECS
/// <param name="groupID"></param>
/// <param name="ed"></param>
/// <param name="implementors"></param>
public void BuildEntityInGroup<T>(int entityID, int groupID, object[] implementors = null) where T:IEntityDescriptor, new()
void BuildEntityInGroup<T>(int entityID, int groupID, object[] implementors = null) where T:IEntityDescriptor, new()
{
EntityFactory.BuildGroupedEntityViews(entityID, groupID,
_groupedEntityViewsToAdd.current,
@@ -127,14 +127,14 @@ namespace Svelto.ECS
implementors);
}

public void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null)
void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null)
{
EntityFactory.BuildGroupedEntityViews(entityID, groupID,
_groupedEntityViewsToAdd.current,
entityDescriptor, implementors);
}

public void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo)
void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo)
{
var removeEntityImplementor = removeInfo as RemoveEntityImplementor;

@@ -144,21 +144,44 @@ namespace Svelto.ECS
InternalRemove(removeEntityImplementor.removeEntityInfo.descriptor.entityViewsToBuild, entityID, _entityViewsDB);
}

public void RemoveEntity<T>(int entityID) where T : IEntityDescriptor, new()
void RemoveEntity<T>(int entityID) where T : IEntityDescriptor, new()
{
InternalRemove(EntityDescriptorTemplate<T>.Default.descriptor.entityViewsToBuild, entityID, _entityViewsDB);
}

public void RemoveMetaEntity<T>(int metaEntityID) where T : IEntityDescriptor, new()
void RemoveMetaEntity<T>(int metaEntityID) where T : IEntityDescriptor, new()
{
InternalRemove(EntityDescriptorTemplate<T>.Default.descriptor.entityViewsToBuild, metaEntityID, _metaEntityViewsDB);
}

public void RemoveEntityFromGroup<T>(int entityID, int groupID) where T : IEntityDescriptor, new()
void RemoveEntityFromGroup<T>(int entityID, int groupID) where T : IEntityDescriptor, new()
{
InternalRemove(EntityDescriptorTemplate<T>.Default.descriptor.entityViewsToBuild, entityID, _groupEntityViewsDB[groupID]);
}

void Preallocate<T>(int size) where T : IEntityDescriptor, new()
{
var entityViewsToBuild = EntityDescriptorTemplate<T>.Default.descriptor.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);
}
}

public void AddEngine(IEngine engine)
{
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
@@ -323,7 +346,7 @@ namespace Svelto.ECS
groupedEntityViewsByType.Add(entityView.Key, entityView.Value);
}
}
static void AddEntityViewToDB(Dictionary<Type, ITypeSafeList> entityViewsDB, KeyValuePair<Type, ITypeSafeList> entityViewList)
{
ITypeSafeList dbList;
@@ -508,7 +531,7 @@ namespace Svelto.ECS
readonly DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>> _metaEntityViewsToAdd;
readonly DoubleBufferedEntityViews<Dictionary<int, Dictionary<Type, ITypeSafeList>>> _groupedEntityViewsToAdd;
readonly EntityViewSubmissionScheduler _scheduler;
readonly EntitySubmissionScheduler _scheduler;
#if EXPERIMENTAL
readonly Type _structEntityViewEngineType;
readonly Type _groupedStructEntityViewsEngineType;
@@ -580,6 +603,11 @@ namespace Svelto.ECS
{
_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


+ 26
- 15
ECS/EntityDescriptorTemplate.cs View File

@@ -101,17 +101,17 @@ namespace Svelto.ECS.Internal
}
}

static IEntityView BuildEntityView(int entityID, Dictionary<Type, ITypeSafeList> groupedEntityViewsTyped,
static IEntityView BuildEntityView(int entityID, Dictionary<Type, ITypeSafeList> entityViewsByType,
Type entityViewType, IEntityViewBuilder entityViewBuilderId)
{
ITypeSafeList entityViews;
ITypeSafeList entityViewsList;

var entityViewsPoolWillBeCreated =
groupedEntityViewsTyped.TryGetValue(entityViewType, out entityViews) == false;
var entityViewObjectToFill = entityViewBuilderId.BuildEntityViewAndAddToList(ref entityViews, entityID);
entityViewsByType.TryGetValue(entityViewType, out entityViewsList) == false;
var entityViewObjectToFill = entityViewBuilderId.BuildEntityViewAndAddToList(ref entityViewsList, entityID);

if (entityViewsPoolWillBeCreated)
groupedEntityViewsTyped.Add(entityViewType, entityViews);
entityViewsByType.Add(entityViewType, entityViewsList);

return entityViewObjectToFill as IEntityView;
}
@@ -163,13 +163,13 @@ namespace Svelto.ECS.Internal
var keyValuePair = setters[i];
Type fieldType = keyValuePair.Key;
if (fieldType == removeEntityComponentType)
{
keyValuePair.Value(entityView, removeEntity);
}
else
if (fieldType != removeEntityComponentType)
{
#if DEBUG && !PROFILER
Tuple<object, int> component;
#else
object component;
#endif

if (implementorsByType.TryGetValue(fieldType, out component) == false)
{
@@ -178,21 +178,28 @@ namespace Svelto.ECS.Internal

throw e;
}
#if DEBUG && !PROFILER
if (component.item2 > 1)
Utility.Console.LogError(DUPLICATE_IMPLEMENTOR_ERROR.FastConcat(
"Component Type: ", fieldType.Name, " implementor: ",
component.item1.ToString()) + " - EntityView: " +
entityView.GetType().Name + " - EntityDescriptor " + entityDescriptorName);

#endif
#if DEBUG && !PROFILER
keyValuePair.Value(entityView, component.item1);
#else
keyValuePair.Value(entityView, component);
#endif
}
else
{
keyValuePair.Value(entityView, removeEntity);
}

}

implementorsByType.Clear();
}

#if DEBUG && !PROFILER
struct Tuple<T1, T2>
{
public T1 item1;
@@ -204,9 +211,13 @@ namespace Svelto.ECS.Internal
item2 = v;
}
}
#endif
//this is used to avoid newing a dictionary every time, but it's used locally only
#if DEBUG && !PROFILER
static readonly Dictionary<Type, Tuple<object, int>> implementorsByType = new Dictionary<Type, Tuple<object, int>>();
#else
static readonly Dictionary<Type, object> implementorsByType = new Dictionary<Type, object>();
#endif
static Dictionary<Type, Type[]> _cachedTypes = new Dictionary<Type, Type[]>();

const string DUPLICATE_IMPLEMENTOR_ERROR =


ECS/NodeSubmissionScheduler.cs → ECS/EntitySubmissionScheduler.cs View File

@@ -2,7 +2,7 @@ using Svelto.WeakEvents;

namespace Svelto.ECS.Schedulers
{
public abstract class EntityViewSubmissionScheduler
public abstract class EntitySubmissionScheduler
{
abstract public void Schedule(WeakAction submitEntityViews);
}

ECS/INode.cs → ECS/EntityView.cs View File


ECS/NodeBuilder.cs → ECS/EntityViewBuilder.cs View File

@@ -6,6 +6,7 @@ namespace Svelto.ECS
public interface IEntityViewBuilder
{
IEntityView BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID);
ITypeSafeList Preallocate(ref ITypeSafeList list, int size);

Type GetEntityViewType();
}
@@ -26,6 +27,16 @@ namespace Svelto.ECS
return entityView;
}

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;
@@ -51,6 +62,16 @@ namespace Svelto.ECS
return 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;

ECS/IEngineNodeDB.cs → ECS/IEngineEntityViewDB.cs View File


+ 2
- 7
ECS/IEnginesInterfaces.cs View File

@@ -2,6 +2,8 @@ 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);

@@ -20,12 +22,5 @@ namespace Svelto.ECS
void RemoveMetaEntity<T>(int metaEntityID) where T:IEntityDescriptor, new();

void RemoveEntityFromGroup<T>(int entityID, int groupID) where T:IEntityDescriptor, new();
#if EXPERIMENTAL
void SetEntityActiveState<T>(int entityID, bool state) where T:IEntityDescriptor, new();
void SetMetaEntityActiveState<T>(int metaEntityID, bool state) where T:IEntityDescriptor, new();
void SetEntityInGroupActiveState<T>(int entityID, int group, bool state) where T:IEntityDescriptor, new();
#endif
}
}

ECS/MultiNodesEngine.cs → ECS/MultiEntityViewsEngine.cs View File


ECS/SingleNodeEngine.cs → ECS/SingleEntityViewEngine.cs View File


+ 14
- 8
Utilities/FastInvoke.cs View File

@@ -5,20 +5,26 @@ using System.Reflection.Emit;
namespace Svelto.Utilities
{
//https://stackoverflow.com/questions/321650/how-do-i-set-a-field-value-in-an-c-sharp-expression-tree/321686#321686

public static class FastInvoke<T> where T : class
{
public static Action<T, object> MakeSetter(FieldInfo field)
{
DynamicMethod m = new DynamicMethod("setter", typeof(void), new Type[] {typeof(T), typeof(object)});
ILGenerator cg = m.GetILGenerator();
if (field.FieldType.IsInterface == true && field.FieldType.IsValueType == 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);

// arg0.<field> = arg1
cg.Emit(OpCodes.Ldarg_0);
cg.Emit(OpCodes.Ldarg_1);
cg.Emit(OpCodes.Stfld, field);
cg.Emit(OpCodes.Ret);
return (Action<T, object>)m.CreateDelegate(typeof(Action<T, object>));
}

return (Action<T, object>) m.CreateDelegate(typeof(Action<T, object>));;
throw new ArgumentException("<color=orange>Svelto.ECS</color> unsupported EntityView field (must be an interface and a class)");
}
}
}

Loading…
Cancel
Save