diff --git a/.gitignore b/.gitignore index a41426d..f9c83e7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -/EntitySystem/note.txt -/EntitySystem/note.txt.meta -/*.meta *.meta /obj /bin/Release/netstandard2.0 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..532d6f0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Svelto.Common"] + path = Svelto.Common + url = https://github.com/sebas77/Svelto.Common.git diff --git a/DataStructures/CircularBufferIndexer.cs b/DataStructures/CircularBufferIndexer.cs deleted file mode 100644 index 6d86441..0000000 --- a/DataStructures/CircularBufferIndexer.cs +++ /dev/null @@ -1,183 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace Svelto.DataStructures -{ - // Serves as simple circular buffer dictionary, first in, first out - // Main drawback: it is the oldest in the list that is removed and the fact that we might re access a key - // isn't taken into account (we would have to do a shift in both arrays) - // Could be added as an option? - - public class CircularBufferIndexer : IDictionary - { - public ICollection Keys - { - get { return _keys; } - } - - public ICollection Values - { - get { return _values; } - } - - public int Count - { - get { throw new NotImplementedException(); } - } - - public bool IsReadOnly - { - get { throw new NotImplementedException(); } - } - - public CircularBufferIndexer(int size) - { - _keys = new TKey[size]; - _values = new TVal[size]; - _length = _startIndex = _nextIndex = 0; - } - - public TVal this[TKey key] - { - get - { - int index = _startIndex; - for (int i = 0; i < _length; ++i) - { - if (_keys[index].Equals(key)) - { - return _values[index]; - } - - index = NextPosition(index); - } - throw new KeyNotFoundException(); - } - set - { - int index = _startIndex; - for (int i = 0; i < _length; ++i) - { - if (_keys[index].Equals(key)) - { - _values[index] = value; - return; - } - - index = NextPosition(index); - } - throw new KeyNotFoundException(); - } - } - - public void Add(TKey key, TVal value) - { - if (ContainsKey(key)) - { - this[key] = value; - return; - } - - _keys[_nextIndex] = key; - _values[_nextIndex] = value; - _nextIndex = NextPosition(_nextIndex); - if (IsFull()) - { - _startIndex = NextPosition(_startIndex); - } - else - { - ++_length; - } - } - - public bool ContainsKey(TKey key) - { - int index = _startIndex; - for (int i = 0; i < _length; ++i) - { - if (_keys[index].Equals(key)) - { - return true; - } - - index = NextPosition(index); - } - return false; - } - - public bool Remove(TKey key) - { - throw new NotImplementedException(); - } - - public bool TryGetValue(TKey key, out TVal value) - { - value = default(TVal); - int index = _startIndex; - for (int i = 0; i < _length; ++i) - { - if (_keys[index].Equals(key)) - { - value = _values[index]; - return true; - } - - index = NextPosition(index); - } - return false; - } - - public IEnumerator GetEnumerator() - { - throw new NotImplementedException(); - } - - public void Add(KeyValuePair item) - { - Add(item.Key, item.Value); - } - - public void Clear() - { - throw new NotImplementedException(); - } - - public bool Contains(KeyValuePair item) - { - throw new NotImplementedException(); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - throw new NotImplementedException(); - } - - public bool Remove(KeyValuePair item) - { - throw new NotImplementedException(); - } - - IEnumerator> IEnumerable>.GetEnumerator() - { - throw new NotImplementedException(); - } - - int NextPosition(int position) - { - return (position + 1) % _keys.Length; - } - - bool IsFull() - { - return _length == _values.Length; - } - - TKey[] _keys; - TVal[] _values; - int _startIndex; - int _nextIndex; - int _length; - } -} diff --git a/DataStructures/FasterList.cs b/DataStructures/FasterList.cs deleted file mode 100644 index eed13af..0000000 --- a/DataStructures/FasterList.cs +++ /dev/null @@ -1,828 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Threading; - -namespace Svelto.DataStructures -{ - public struct FasterListEnumerator : IEnumerator - { - public T Current - { - get { return _current; } - } - - public FasterListEnumerator(T[] buffer, int size) - { - _size = size; - _counter = 0; - _buffer = buffer; - _current = default(T); - } - - object IEnumerator.Current - { - get { return _current; } - } - - T IEnumerator.Current - { - get { return _current; } - } - - public void Dispose() - { - _buffer = null; - } - - public bool MoveNext() - { - if (_counter < _size) - { - _current = _buffer[_counter++]; - - return true; - } - - _current = default(T); - - return false; - } - - public void Reset() - { - _counter = 0; - } - - bool IEnumerator.MoveNext() - { - return MoveNext(); - } - - void IEnumerator.Reset() - { - Reset(); - } - - T[] _buffer; - int _counter; - int _size; - T _current; - } - - public struct FasterListEnumeratorCast : IEnumerator where T:U - { - public T Current - { - get { return (T)_buffer.Current; } - } - - public FasterListEnumeratorCast(FasterListEnumerator buffer) - { - _buffer = buffer; - } - - object IEnumerator.Current - { - get { return (T)_buffer.Current; } - } - - T IEnumerator.Current - { - get { return (T)_buffer.Current; } - } - - public void Dispose() - {} - - public bool MoveNext() - { - return _buffer.MoveNext(); - } - - public void Reset() - { - _buffer.Reset(); - } - - bool IEnumerator.MoveNext() - { - return MoveNext(); - } - - void IEnumerator.Reset() - { - Reset(); - } - - FasterListEnumerator _buffer; - } - - public struct FasterReadOnlyList : IList - { - public static FasterReadOnlyList DefaultList = new FasterReadOnlyList(FasterList.DefaultList); - - public int Count { get { return _list.Count; } } - public bool IsReadOnly { get { return true; } } - - public FasterReadOnlyList(FasterList list) - { - _list = list; - - int count; - _buffer = FasterList.NoVirt.ToArrayFast(list, out count); - } - - public T this[int index] { get { return _buffer[index]; } set { throw new NotImplementedException(); } } - - public FasterListEnumerator GetEnumerator() - { - return _list.GetEnumerator(); - } - - public void Add(T item) - { - throw new NotImplementedException(); - } - - public void Clear() - { - throw new NotImplementedException(); - } - - public bool Contains(T item) - { - return _list.Contains(item); - } - - public void CopyTo(T[] array, int arrayIndex) - { - _list.CopyTo(array, arrayIndex); - } - - public bool Remove(T item) - { - throw new NotImplementedException(); - } - - public int IndexOf(T item) - { - return _list.IndexOf(item); - } - - public void Insert(int index, T item) - { - throw new NotImplementedException(); - } - - public void RemoveAt(int index) - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - readonly FasterList _list; - private readonly T[] _buffer; - } - - public struct FasterListThreadSafe : IList - { - public FasterListThreadSafe(FasterList list) - { - if (list == null) throw new ArgumentException("invalid list"); - _list = list; - _lockQ = new ReaderWriterLockSlim(); - } - - public int Count - { - get - { - _lockQ.EnterReadLock(); - try - { - return _list.Count; - } - finally - { - _lockQ.ExitReadLock(); - } - } - } - public bool IsReadOnly { get { return false; } } - - public T this[int index] - { - get - { - _lockQ.EnterReadLock(); - try - { - return _list[index]; - } - finally - { - _lockQ.ExitReadLock(); - } - } - set - { - _lockQ.EnterWriteLock(); - try - { - _list[index] = value; - } - finally - { - _lockQ.ExitWriteLock(); - } - } - } - - public FasterListEnumerator GetEnumerator() - { - throw new NotImplementedException(); - } - - public void Add(T item) - { - _lockQ.EnterWriteLock(); - try - { - _list.Add(item); - } - finally - { - _lockQ.ExitWriteLock(); - } - } - - public void Clear() - { - _lockQ.EnterWriteLock(); - try - { - _list.Clear(); - } - finally - { - _lockQ.ExitWriteLock(); - } - } - - public void FastClear() - { - _lockQ.EnterWriteLock(); - try - { - _list.FastClear(); - } - finally - { - _lockQ.ExitWriteLock(); - } - } - - public bool Contains(T item) - { - _lockQ.EnterReadLock(); - try - { - return _list.Contains(item); - } - finally - { - _lockQ.ExitReadLock(); - } - } - - public void CopyTo(T[] array, int arrayIndex) - { - _lockQ.EnterReadLock(); - try - { - _list.CopyTo(array, arrayIndex); - } - finally - { - _lockQ.ExitReadLock(); - } - } - - public bool Remove(T item) - { - _lockQ.EnterWriteLock(); - try - { - return _list.Remove(item); - } - finally - { - _lockQ.ExitWriteLock(); - } - } - - public int IndexOf(T item) - { - _lockQ.EnterReadLock(); - try - { - return _list.IndexOf(item); - } - finally - { - _lockQ.ExitReadLock(); - } - } - - public void Insert(int index, T item) - { - _lockQ.EnterWriteLock(); - try - { - _list.Insert(index, item); - } - finally - { - _lockQ.ExitWriteLock(); - } - } - - public void RemoveAt(int index) - { - _lockQ.EnterWriteLock(); - try - { - _list.RemoveAt(index); - } - finally - { - _lockQ.ExitWriteLock(); - } - } - - public void UnorderedRemoveAt(int index) - { - _lockQ.EnterWriteLock(); - try - { - _list.UnorderedRemoveAt(index); - } - finally - { - _lockQ.ExitWriteLock(); - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - - readonly FasterList _list; - - readonly ReaderWriterLockSlim _lockQ; - } - - public struct FasterReadOnlyListCast : IList where U:T - { - public static readonly FasterReadOnlyListCast DefaultList = new FasterReadOnlyListCast(new FasterList()); - - public int Count { get { return _list.Count; } } - public bool IsReadOnly { get { return true; } } - - public FasterReadOnlyListCast(FasterList list) - { - _list = list; - } - - public U this[int index] { get { return (U)_list[index]; } set { throw new NotImplementedException(); } } - - public FasterListEnumeratorCast GetEnumerator() - { - return new FasterListEnumeratorCast(_list.GetEnumerator()); - } - - public void Add(U item) - { - throw new NotImplementedException(); - } - - public void Clear() - { - throw new NotImplementedException(); - } - - public bool Contains(U item) - { - return _list.Contains(item); - } - - public void CopyTo(U[] array, int arrayIndex) - { - Array.Copy(_list.ToArrayFast(), 0, array, arrayIndex, _list.Count); - } - - public bool Remove(U item) - { - throw new NotImplementedException(); - } - - public int IndexOf(U item) - { - return _list.IndexOf(item); - } - - public void Insert(int index, U item) - { - throw new NotImplementedException(); - } - - public void RemoveAt(int index) - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - readonly FasterList _list; - } - - public interface IFasterList - {} - - public class FasterList : IList, IFasterList - { - public static readonly FasterList DefaultList = new FasterList(); - - const int MIN_SIZE = 4; - - public int Count - { - get { return _count; } - } - - public bool IsReadOnly - { - get { return false; } - } - - public FasterList() - { - _count = 0; - - _buffer = new T[MIN_SIZE]; - } - - public FasterList(int initialSize) - { - _count = 0; - - _buffer = new T[initialSize]; - } - - public FasterList(ICollection collection) - { - _buffer = new T[collection.Count]; - - collection.CopyTo(_buffer, 0); - - _count = _buffer.Length; - } - - public FasterList(FasterList listCopy) - { - _buffer = new T[listCopy.Count]; - - listCopy.CopyTo(_buffer, 0); - - _count = listCopy.Count; - } - - public T this[int i] - { - get { DesignByContract.Check.Require(i < _count, "out of bound index"); return _buffer[i]; } - set { DesignByContract.Check.Require(i < _count, "out of bound index"); _buffer[i] = value; } - } - - public void Add(T item) - { - if (_count == _buffer.Length) - AllocateMore(); - - _buffer[_count++] = item; - } - - - /// - /// this is a dirtish trick to be able to use the index operastor - /// before adding the elements through the Add functions - /// - /// - /// - /// - public static FasterList PreFill(int initialSize) where U:T, new() - { - var list = new FasterList(initialSize); - - for (int i = 0; i < initialSize; i++) - list.Add(new U()); - - list._count = 0; - - return list; - } - - public void AddRange(IEnumerable items, int count) - { - AddRange(items.GetEnumerator(), count); - } - - public void AddRange(IEnumerator items, int count) - { - if (_count + count >= _buffer.Length) - AllocateMore(_count + count); - - while (items.MoveNext()) - _buffer[_count++] = items.Current; - } - - public void AddRange(ICollection items) - { - AddRange(items.GetEnumerator(), items.Count); - } - - public void AddRange(FasterList items) - { - AddRange(items.ToArrayFast(), items.Count); - } - - public void AddRange(T[] items, int count) - { - if (count == 0) return; - - if (_count + count >= _buffer.Length) - AllocateMore(_count + count); - - Array.Copy(items, 0, _buffer, _count, count); - _count += count; - } - - public void AddRange(T[] items) - { - AddRange(items, items.Length); - } - - public FasterReadOnlyList AsReadOnly() - { - return new FasterReadOnlyList(this); - } - - /// - /// Careful, you could keep on holding references you don't want to hold to anymore - /// Use DeepClear in case. - /// - public void FastClear() - { - _count = 0; - } - - public void Clear() - { - Array.Clear(_buffer, 0, _buffer.Length); - - _count = 0; - } - - public bool Contains(T item) - { - var index = IndexOf(item); - - return index != -1; - } - - public void CopyTo(T[] array, int arrayIndex) - { - Array.Copy(_buffer, 0, array, arrayIndex, Count); - } - - public FasterListEnumerator GetEnumerator() - { - return new FasterListEnumerator(_buffer, Count); - } - - public int IndexOf(T item) - { - var comp = EqualityComparer.Default; - - for (var index = 0; index < _count; index++) - if (comp.Equals(_buffer[index], item)) - return index; - - return -1; - } - - public void Insert(int index, T item) - { - DesignByContract.Check.Require(index < _count, "out of bound index"); - - if (_count == _buffer.Length) AllocateMore(); - - Array.Copy(_buffer, index, _buffer, index + 1, _count - index); - - _buffer[index] = item; - ++_count; - } - - public void Release() - { - _count = 0; - _buffer = null; - } - - public bool Remove(T item) - { - var index = IndexOf(item); - - if (index == -1) - return false; - - RemoveAt(index); - - return true; - } - - public void RemoveAt(int index) - { - DesignByContract.Check.Require(index < _count, "out of bound index"); - - if (index == --_count) - return; - - Array.Copy(_buffer, index + 1, _buffer, index, _count - index); - - _buffer[_count] = default(T); - } - - public void Resize(int newSize) - { - if (newSize < MIN_SIZE) - newSize = MIN_SIZE; - - Array.Resize(ref _buffer, newSize); - - _count = newSize; - } - - public void SetAt(int index, T value) - { - if (index >= _buffer.Length) - AllocateMore(index + 1); - - if (_count <= index) - _count = index + 1; - - this[index] = value; - } - - public void Sort(IComparer comparer) - { - Array.Sort(_buffer, 0, _count, comparer); - } - - public T[] ToArray() - { - T[] destinationArray = new T[_count]; - - Array.Copy(_buffer, 0, destinationArray, 0, _count); - - return destinationArray; - } - - /// - /// This function exists to allow fast iterations. The size of the array returned cannot be - /// used. The list count must be used instead. - /// - /// - public T[] ToArrayFast() - { - return _buffer; - } - - public bool UnorderedRemove(T item) - { - var index = IndexOf(item); - - if (index == -1) - return false; - - UnorderedRemoveAt(index); - - return true; - } - - public bool UnorderedRemoveAt(int index) - { - DesignByContract.Check.Require(index < _count && _count > 0, "out of bound index"); - - if (index == --_count) - { - _buffer[_count] = default(T); - return false; - } - - _buffer[index] = _buffer[_count]; - _buffer[_count] = default(T); - - return true; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - void AllocateMore() - { - var newList = new T[Math.Max(_buffer.Length << 1, MIN_SIZE)]; - if (_count > 0) _buffer.CopyTo(newList, 0); - _buffer = newList; - } - - void AllocateMore(int newSize) - { - var oldLength = Math.Max(_buffer.Length, MIN_SIZE); - - while (oldLength < newSize) - oldLength <<= 1; - - var newList = new T[oldLength]; - if (_count > 0) Array.Copy(_buffer, newList, _count); - _buffer = newList; - } - - public void Trim() - { - if (_count < _buffer.Length) - Resize(_count); - } - - public bool Reuse(int index, out U result) - where U:class, T - { - result = default(U); - - if (index >= _buffer.Length) - return false; - - result = (U)_buffer[index]; - - return result != null; - } - - T[] _buffer; - int _count; - - public static class NoVirt - { - public static int Count(FasterList fasterList) - { - return fasterList._count; - } - - public static T[] ToArrayFast(FasterList fasterList, out int count) - { - count = fasterList._count; - - return fasterList._buffer; - } - } - } -} diff --git a/DataStructures/HashableWeakReference.cs b/DataStructures/HashableWeakReference.cs deleted file mode 100644 index 62edfa6..0000000 --- a/DataStructures/HashableWeakReference.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; - -namespace Svelto.DataStructures -{ - class HashableWeakRef : IEquatable> where T : class - { - public bool isAlive { get { return _weakRef.IsAlive; } } - public T Target { get { return (T)_weakRef.Target; } } - - public HashableWeakRef(T target) - { - _weakRef = new WeakReference(target); - _hash = target.GetHashCode(); - } - - public static bool operator !=(HashableWeakRef a, HashableWeakRef b) - { - return !(a == b); - } - - public static bool operator ==(HashableWeakRef a, HashableWeakRef b) - { - if (a._hash != b._hash) - return false; - - var tmpTargetA = (T) a._weakRef.Target; - var tmpTargetB = (T) b._weakRef.Target; - - if (tmpTargetA == null || tmpTargetB == null) - return false; - - return tmpTargetA == tmpTargetB; - } - - public override bool Equals(object other) - { - if (other is HashableWeakRef) - return this.Equals((HashableWeakRef)other); - - return false; - } - - public bool Equals(HashableWeakRef other) - { - return (this == other); - } - - public override int GetHashCode() - { - return _hash; - } - - int _hash; - WeakReference _weakRef; - } -} diff --git a/DataStructures/LockFreeQueue.cs b/DataStructures/LockFreeQueue.cs deleted file mode 100644 index 4c55f39..0000000 --- a/DataStructures/LockFreeQueue.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System.Collections.Generic; -using System.Threading; - -//from unify wiki -namespace Svelto.DataStructures -{ - public class SingleLinkNode - { - // Note; the Next member cannot be a property since - // it participates in many CAS operations - public SingleLinkNode Next; - public T Item; - } - - public static class SyncMethods - { - public static bool CAS(ref T location, T comparand, T newValue) where T : class - { - return - (object)comparand == - (object)Interlocked.CompareExchange(ref location, newValue, comparand); - } - } - - public class LockFreeLinkPool - { - private SingleLinkNode head; - - public LockFreeLinkPool() - { - head = new SingleLinkNode(); - } - - public void Push(SingleLinkNode newNode) - { - newNode.Item = default(T); - do - { - newNode.Next = head.Next; - } while (!SyncMethods.CAS>(ref head.Next, newNode.Next, newNode)); - return; - } - - public bool Pop(out SingleLinkNode node) - { - do - { - node = head.Next; - if (node == null) - { - return false; - } - } while (!SyncMethods.CAS>(ref head.Next, node, node.Next)); - return true; - } - } - - public class LockFreeQueue - { - - SingleLinkNode head; - SingleLinkNode tail; - LockFreeLinkPool trash; - - public LockFreeQueue() - { - head = new SingleLinkNode(); - tail = head; - trash = new LockFreeLinkPool(); - } - - public void Enqueue(T item) - { - SingleLinkNode oldTail = null; - SingleLinkNode oldTailNext; - - SingleLinkNode newNode; - if (!trash.Pop(out newNode)) - { - newNode = new SingleLinkNode(); - } - else - { - newNode.Next = null; - } - newNode.Item = item; - - bool newNodeWasAdded = false; - while (!newNodeWasAdded) - { - oldTail = tail; - oldTailNext = oldTail.Next; - - if (tail == oldTail) - { - if (oldTailNext == null) - newNodeWasAdded = SyncMethods.CAS>(ref tail.Next, null, newNode); - else - SyncMethods.CAS>(ref tail, oldTail, oldTailNext); - } - } - SyncMethods.CAS>(ref tail, oldTail, newNode); - } - - public bool Dequeue(out T item) - { - item = default(T); - SingleLinkNode oldHead = null; - - bool haveAdvancedHead = false; - while (!haveAdvancedHead) - { - - oldHead = head; - SingleLinkNode oldTail = tail; - SingleLinkNode oldHeadNext = oldHead.Next; - - if (oldHead == head) - { - if (oldHead == oldTail) - { - if (oldHeadNext == null) - { - return false; - } - SyncMethods.CAS>(ref tail, oldTail, oldHeadNext); - } - else - { - item = oldHeadNext.Item; - haveAdvancedHead = SyncMethods.CAS>(ref head, oldHead, oldHeadNext); - if (haveAdvancedHead) - { - trash.Push(oldHead); - } - } - } - } - return true; - } - } -} \ No newline at end of file diff --git a/DataStructures/PriorityQueue/HeapPriorityQueue.cs b/DataStructures/PriorityQueue/HeapPriorityQueue.cs deleted file mode 100644 index 606acd5..0000000 --- a/DataStructures/PriorityQueue/HeapPriorityQueue.cs +++ /dev/null @@ -1,327 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using Svelto.DataStructures; - -namespace Svelto.DataStructures -{ - /// - /// An implementation of a min-Priority Queue using a heap. Has O(1) .Contains()! - /// See https://bitbucket.org/BlueRaja/high-speed-priority-queue-for-c/wiki/Getting%20Started for more information - /// - /// The values in the queue. Must implement the PriorityQueueNode interface - public sealed class HeapPriorityQueue : IPriorityQueue - where T : PriorityQueueNode - { - private int _numNodes; - private readonly FasterList _nodes; - private long _numNodesEverEnqueued; - - /// - /// Instantiate a new Priority Queue - /// - /// The max nodes ever allowed to be enqueued (going over this will cause an exception) - public HeapPriorityQueue() - { - _numNodes = 0; - _nodes = new FasterList(); - _numNodesEverEnqueued = 0; - } - - public HeapPriorityQueue(int initialSize) - { - _numNodes = 0; - _nodes = new FasterList(initialSize); - _numNodesEverEnqueued = 0; - } - - /// - /// Returns the number of nodes in the queue. O(1) - /// - public int Count - { - get - { - return _numNodes; - } - } - - /// - /// Returns the maximum number of items that can be enqueued at once in this queue. Once you hit this number (ie. once Count == MaxSize), - /// attempting to enqueue another item will throw an exception. O(1) - /// - public int MaxSize - { - get - { - return _nodes.Count - 1; - } - } - - /// - /// Removes every node from the queue. O(n) (So, don't do this often!) - /// - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - public void Clear() - { - _nodes.FastClear(); - - _numNodes = 0; - } - - /// - /// Returns (in O(1)!) whether the given node is in the queue. O(1) - /// - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - public bool Contains(T node) - { - return (_nodes[node.QueueIndex] == node); - } - - /// - /// Enqueue a node - .Priority must be set beforehand! O(log n) - /// - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - public void Enqueue(T node, double priority) - { - node.Priority = priority; - _numNodes++; - if (_nodes.Count < _numNodes) - _nodes.Resize(_numNodes + 1); - - _nodes[_numNodes] = node; - node.QueueIndex = _numNodes; - node.InsertionIndex = _numNodesEverEnqueued++; - CascadeUp(_nodes[_numNodes]); - } - - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - private void Swap(T node1, T node2) - { - //Swap the nodes - _nodes[node1.QueueIndex] = node2; - _nodes[node2.QueueIndex] = node1; - - //Swap their indicies - 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 node) - { - //aka Heapify-up - int parent = node.QueueIndex / 2; - while(parent >= 1) - { - T parentNode = _nodes[parent]; - if(HasHigherPriority(parentNode, node)) - break; - - //Node has lower priority value, so move it up the heap - Swap(node, parentNode); //For some reason, this is faster with Swap() rather than (less..?) individual operations, like in CascadeDown() - - parent = node.QueueIndex / 2; - } - } - - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - private void CascadeDown(T node) - { - //aka Heapify-down - T newParent; - int finalQueueIndex = node.QueueIndex; - while(true) - { - newParent = node; - int childLeftIndex = 2 * finalQueueIndex; - - //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 != node twice - node.QueueIndex = finalQueueIndex; - _nodes[finalQueueIndex] = node; - break; - } - - T childLeft = _nodes[childLeftIndex]; - if(HasHigherPriority(childLeft, newParent)) - { - newParent = childLeft; - } - - //Check if the right-child is higher-priority than either the current node or the left child - int childRightIndex = childLeftIndex + 1; - if(childRightIndex <= _numNodes) - { - T childRight = _nodes[childRightIndex]; - if(HasHigherPriority(childRight, newParent)) - { - newParent = childRight; - } - } - - //If either of the children has higher (smaller) priority, swap and continue cascading - if(newParent != node) - { - //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() - _nodes[finalQueueIndex] = newParent; - - int temp = newParent.QueueIndex; - newParent.QueueIndex = finalQueueIndex; - finalQueueIndex = temp; - } - else - { - //See note above - node.QueueIndex = finalQueueIndex; - _nodes[finalQueueIndex] = node; - break; - } - } - } - - /// - /// Returns true if 'higher' has higher priority than 'lower', false otherwise. - /// Note that calling HasHigherPriority(node, node) (ie. both arguments the same node) will return false - /// - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - private bool HasHigherPriority(T higher, T lower) - { - return (higher.Priority < lower.Priority || - (higher.Priority == lower.Priority && higher.InsertionIndex < lower.InsertionIndex)); - } - - /// - /// Removes the head of the queue (node with highest priority; ties are broken by order of insertion), and returns it. O(log n) - /// - public T Dequeue() - { - T returnMe = _nodes[1]; - Remove(returnMe); - return returnMe; - } - - /// - /// Returns the head of the queue, without removing it (use Dequeue() for that). O(1) - /// - public T First - { - get - { - return _nodes[1]; - } - } - - /// - /// This method must be called on a node every time its priority changes while it is in the queue. - /// Forgetting to call this method will result in a corrupted queue! - /// O(log n) - /// - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - public void UpdatePriority(T node, double priority) - { - node.Priority = priority; - OnNodeUpdated(node); - } - - private void OnNodeUpdated(T node) - { - //Bubble the updated node up or down as appropriate - int parentIndex = node.QueueIndex / 2; - T parentNode = _nodes[parentIndex]; - - if(parentIndex > 0 && HasHigherPriority(node, parentNode)) - { - CascadeUp(node); - } - else - { - //Note that CascadeDown will be called if parentNode == node (that is, node is the root) - CascadeDown(node); - } - } - - /// - /// Removes a node from the queue. Note that the node does not need to be the head of the queue. O(log n) - /// - public void Remove(T node) - { - if(_numNodes <= 1) - { - _nodes[1] = null; - _numNodes = 0; - return; - } - - //Make sure the node is the last node in the queue - bool wasSwapped = false; - T formerLastNode = _nodes[_numNodes]; - if(node.QueueIndex != _numNodes) - { - //Swap the node with the last node - Swap(node, formerLastNode); - wasSwapped = true; - } - - _numNodes--; - _nodes[node.QueueIndex] = null; - - if(wasSwapped) - { - //Now bubble formerLastNode (which is no longer the last node) up or down as appropriate - OnNodeUpdated(formerLastNode); - } - } - - public IEnumerator GetEnumerator() - { - for(int i = 1; i <= _numNodes; i++) - yield return _nodes[i]; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// Should not be called in production code. - /// Checks to make sure the queue is still in a valid state. Used for testing/debugging the queue. - /// - public bool IsValidQueue() - { - for(int i = 1; i < _nodes.Count; i++) - { - if(_nodes[i] != null) - { - int childLeftIndex = 2 * i; - if(childLeftIndex < _nodes.Count && _nodes[childLeftIndex] != null && HasHigherPriority(_nodes[childLeftIndex], _nodes[i])) - return false; - - int childRightIndex = childLeftIndex + 1; - if(childRightIndex < _nodes.Count && _nodes[childRightIndex] != null && HasHigherPriority(_nodes[childRightIndex], _nodes[i])) - return false; - } - } - return true; - } - } -} \ No newline at end of file diff --git a/DataStructures/PriorityQueue/IPriorityQueue.cs b/DataStructures/PriorityQueue/IPriorityQueue.cs deleted file mode 100644 index 632820e..0000000 --- a/DataStructures/PriorityQueue/IPriorityQueue.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections.Generic; - -namespace Svelto.DataStructures -{ - /// - /// The IPriorityQueue interface. This is mainly here for purists, and in case I decide to add more implementations later. - /// For speed purposes, it is actually recommended that you *don't* access the priority queue through this interface, since the JIT can - /// (theoretically?) optimize method calls from concrete-types slightly better. - /// - public interface IPriorityQueue : IEnumerable - where T : PriorityQueueNode - { - 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 node); - } -} diff --git a/DataStructures/PriorityQueue/PriorityQueueNode.cs b/DataStructures/PriorityQueue/PriorityQueueNode.cs deleted file mode 100644 index b09f3a4..0000000 --- a/DataStructures/PriorityQueue/PriorityQueueNode.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace Svelto.DataStructures -{ - public class PriorityQueueNode - { - /// - /// The Priority to insert this node at. Must be set BEFORE adding a node to the queue - /// - public double Priority { get; - set; - } - - /// - /// Used by the priority queue - do not edit this value. - /// Represents the order the node was inserted in - /// - public long InsertionIndex { get; set; } - - /// - /// Used by the priority queue - do not edit this value. - /// Represents the current position in the queue - /// - public int QueueIndex { get; set; } - } -} diff --git a/DataStructures/ReadOnlyDictionary.cs b/DataStructures/ReadOnlyDictionary.cs deleted file mode 100644 index 8b09f3a..0000000 --- a/DataStructures/ReadOnlyDictionary.cs +++ /dev/null @@ -1,544 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace Svelto.DataStructures -{ - public struct ReadOnlyDictionary : IDictionary - { - public bool isInitialized { get { return _dictionary != null; } } - - /// - /// Gets the element that has the specified key. - /// - /// The key of the element to get. - /// The element that has the specified key. - /// If is . - /// If property is retrieved and is not found. - public TValue this[TKey key] - { - get - { - return _dictionary[key]; - } - } - - /// - /// Gets the number of items in the dictionary. - /// - /// - /// The number of items in the dictionary. - /// - public int Count - { - get - { - return _dictionary.Count; - } - } - - /// - /// Gets a key collection that contains the keys of the dictionary. - /// - /// - /// A key collection that contains the keys of the dictionary. - /// - public KeyCollection Keys - { - get - { - return new KeyCollection(_dictionary.Keys); - } - } - - /// - /// Gets a collection that contains the values in the dictionary. - /// - /// - /// A collection that contains the values in the object that implements . - /// - public ValueCollection Values - { - get - { - return new ValueCollection(_dictionary.Values); - } - } - - /// - /// Initializes a new instance of the class - /// that is a wrapper around the specified dictionary. - /// - /// The dictionary to wrap. - public ReadOnlyDictionary(Dictionary dictionary) - { - if (dictionary == null) - throw new ArgumentNullException("dictionary"); - - _dictionary = dictionary; - } - - /// - /// - /// Gets the element that has the specified key. - /// - /// If the property is set. - TValue IDictionary.this[TKey key] - { - get - { - return this[key]; - } - - set - { - throw new NotSupportedException(); - } - } - - /// - ICollection IDictionary.Keys - { - get - { - return Keys; - } - } - - /// - ICollection IDictionary.Values - { - get - { - return Values; - } - } - - /// - bool ICollection>.IsReadOnly - { - get - { - return true; - } - } - - /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - void IDictionary.Add(TKey key, TValue value) - { - throw new NotSupportedException(); - } - - /// - bool IDictionary.Remove(TKey key) - { - throw new NotSupportedException(); - } - - /// - void ICollection>.Add(KeyValuePair item) - { - throw new NotSupportedException(); - } - - /// - void ICollection>.Clear() - { - throw new NotSupportedException(); - } - - /// - bool ICollection>.Contains(KeyValuePair item) - { - throw new NotImplementedException(); - } - - /// - void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) - { - throw new NotImplementedException(); - } - - /// - bool ICollection>.Remove(KeyValuePair item) - { - throw new NotSupportedException(); - } - - bool IDictionary.ContainsKey(TKey key) - { - return _dictionary.ContainsKey(key); - } - - bool IDictionary.TryGetValue(TKey key, out TValue value) - { - return _dictionary.TryGetValue(key, out value); - } - - int ICollection>.Count - { - get { return _dictionary.Count; } - } - - IEnumerator> IEnumerable>.GetEnumerator() - { - return _dictionary.GetEnumerator(); - } - - /// - /// Determines whether the dictionary contains an element that has the specified key. - /// - /// The key to locate in the dictionary. - /// if the dictionary contains an element that has the specified key; otherwise, . - public bool ContainsKey(TKey key) - { - return _dictionary.ContainsKey(key); - } - - public DictionaryEnumerator GetEnumerator() - { - return new DictionaryEnumerator(_dictionary); - } - - /// - /// Retrieves the value that is associated with the specified key. - /// - /// The key whose value will be retrieved. - /// When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized. - /// if the object that implements contains an element with the specified key; otherwise, . - public bool TryGetValue(TKey key, out TValue value) - { - return _dictionary.TryGetValue(key, out value); - } - - readonly Dictionary _dictionary; - - /// - /// Represents a read-only collection of the keys of a object. - /// - public struct KeyCollection : ICollection, ICollection - { - /// - /// Initializes a new instance of the class - /// as a wrapper around the specified collection of keys. - /// - /// The collection of keys to wrap. - /// If is . - internal KeyCollection(ICollection keys) - { - if (keys == null) - throw new ArgumentNullException("keys"); - - _keys = keys; - } - - /// - bool ICollection.IsSynchronized - { - get - { - return false; - } - } - - /// - object ICollection.SyncRoot - { - get - { - throw new NotImplementedException(); - } - } - - /// - void ICollection.CopyTo(Array array, int index) - { - throw new NotImplementedException(); - } - - /// - /// Gets the number of elements in the collection. - /// - /// - /// The number of elements in the collection. - /// - public int Count - { - get - { - return _keys.Count; - } - } - - /// - bool ICollection.IsReadOnly - { - get - { - return true; - } - } - - /// - /// Copies the elements of the collection to an array, starting at a specific array index. - /// - /// The one-dimensional array that is the destination of the elements copied from the collection. The array must have zero-based indexing. - /// The zero-based index in at which copying begins. - /// If is . - /// If is less than 0. - /// - /// If is multidimensional. - /// -or- - /// If the number of elements in the source collection is greater than the available space from to the end of the destination . - /// -or- - /// If the type cannot be cast automatically to the type of the destination . - /// - public void CopyTo(TKey[] array, int arrayIndex) - { - _keys.CopyTo(array, arrayIndex); - } - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - public IEnumerator GetEnumerator() - { - return _keys.GetEnumerator(); - } - - /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - bool ICollection.Contains(TKey item) - { - return _keys.Contains(item); - } - - /// - void ICollection.Add(TKey item) - { - throw new NotSupportedException(); - } - - /// - bool ICollection.Remove(TKey item) - { - throw new NotSupportedException(); - } - - /// - void ICollection.Clear() - { - throw new NotSupportedException(); - } - - /// - /// The wrapped collection of keys. - /// - readonly ICollection _keys; - } - - /// - /// Represents a read-only collection of the values of a object. - /// - public struct ValueCollection : ICollection, ICollection - { - /// - /// Initializes a new instance of the class - /// as a wrapper around the specified collection of values. - /// - /// The collection of values to wrap. - /// If is . - internal ValueCollection(ICollection values) - { - if (values == null) - throw new ArgumentNullException("values"); - - _values = values; - } - - /// - bool ICollection.IsSynchronized - { - get - { - return false; - } - } - - /// - object ICollection.SyncRoot - { - get - { - throw new NotImplementedException(); - } - } - - /// - void ICollection.CopyTo(Array array, int index) - { - throw new NotImplementedException(); - } - - /// - /// Gets the number of elements in the collection. - /// - /// - /// The number of elements in the collection. - /// - public int Count - { - get - { - return _values.Count; - } - } - - /// - bool ICollection.IsReadOnly - { - get - { - return true; - } - } - - /// - /// Copies the elements of the collection to an array, starting at a specific array index. - /// - /// The one-dimensional array that is the destination of the elements copied from the collection. The array must have zero-based indexing. - /// The zero-based index in at which copying begins. - /// If is . - /// If is less than 0. - /// - /// If is multidimensional. - /// -or- - /// If the number of elements in the source collection is greater than the available space from to the end of the destination . - /// -or- - /// If the type cannot be cast automatically to the type of the destination . - /// - public void CopyTo(TValue[] array, int arrayIndex) - { - _values.CopyTo(array, arrayIndex); - } - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - public IEnumerator GetEnumerator() - { - return _values.GetEnumerator(); - } - - /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - bool ICollection.Contains(TValue item) - { - return _values.Contains(item); - } - - /// - void ICollection.Add(TValue item) - { - throw new NotSupportedException(); - } - - /// - bool ICollection.Remove(TValue item) - { - throw new NotSupportedException(); - } - - /// - void ICollection.Clear() - { - throw new NotSupportedException(); - } - - /// - /// The wrapped collection of values. - /// - readonly ICollection _values; - } - - public struct DictionaryEnumerator:IEnumerator> - { - /// - public TKey Key - { - get - { - return _enumerator.Current.Key; - } - } - - /// - public TValue Value - { - get - { - return _enumerator.Current.Value; - } - } - - public DictionaryEnumerator(IDictionary dictionary) - { - if (dictionary == null) - throw new ArgumentNullException("dictionary"); - - _enumerator = dictionary.GetEnumerator(); - } - - /// - public KeyValuePair Current - { - get - { - return _enumerator.Current; - } - } - - /// - public bool MoveNext() - { - return _enumerator.MoveNext(); - } - - /// - public void Reset() - { - _enumerator.Reset(); - } - - object IEnumerator.Current - { - get { return _enumerator.Current; } - } - - public void Dispose() - { - _enumerator.Dispose(); - } - - readonly IEnumerator> _enumerator; - } - } -} diff --git a/DataStructures/ThreadSafeDictionary.cs b/DataStructures/ThreadSafeDictionary.cs deleted file mode 100644 index 4a4a71f..0000000 --- a/DataStructures/ThreadSafeDictionary.cs +++ /dev/null @@ -1,290 +0,0 @@ - -using System.Collections.Generic; -using System.Threading; - -namespace Svelto.DataStructures -{ - /// - /// original code: http://devplanet.com/blogs/brianr/archive/2008/09/29/thread-safe-dictionary-update.aspx - /// simplified (not an IDictionary) and apdated (uses FasterList) - /// - /// - /// - - public class ThreadSafeDictionary - { - public ThreadSafeDictionary(int v) - { - dict = new Dictionary(v); - } - - public ThreadSafeDictionary() - { - dict = new Dictionary(); - } - - // setup the lock; - public virtual int Count - { - get - { - LockQ.EnterReadLock(); - try - { - return dict.Count; - } - finally - { - LockQ.ExitReadLock(); - } - } - } - - public virtual bool IsReadOnly - { - get - { - LockQ.EnterReadLock(); - try - { - return dict.IsReadOnly; - } - finally - { - LockQ.ExitReadLock(); - } - } - } - - public virtual FasterList Keys - { - get - { - LockQ.EnterReadLock(); - try - { - return new FasterList(dict.Keys); - } - finally - { - LockQ.ExitReadLock(); - } - } - } - - public virtual FasterList Values - { - get - { - LockQ.EnterReadLock(); - try - { - return new FasterList(dict.Values); - } - finally - { - LockQ.ExitReadLock(); - } - } - } - - public virtual TValue this[TKey key] - { - get - { - LockQ.EnterReadLock(); - try - { - return dict[key]; - } - finally - { - LockQ.ExitReadLock(); - } - } - - set - { - LockQ.EnterWriteLock(); - try - { - dict[key] = value; - } - finally - { - LockQ.ExitWriteLock(); - } - } - } - - public virtual void Add(KeyValuePair item) - { - LockQ.EnterWriteLock(); - try - { - dict.Add(item); - } - finally - { - LockQ.ExitWriteLock(); - } - } - - public virtual void Clear() - { - LockQ.EnterWriteLock(); - try - { - dict.Clear(); - } - finally - { - LockQ.ExitWriteLock(); - } - } - - public virtual bool Contains(KeyValuePair item) - { - LockQ.EnterReadLock(); - try - { - return dict.Contains(item); - } - finally - { - LockQ.ExitReadLock(); - } - } - - public virtual void CopyTo(KeyValuePair[] array, int arrayIndex) - { - LockQ.EnterReadLock(); - try - { - dict.CopyTo(array, arrayIndex); - } - finally - { - LockQ.ExitReadLock(); - } - } - - public virtual bool Remove(KeyValuePair item) - { - LockQ.EnterWriteLock(); - try - { - return dict.Remove(item); - } - finally - { - LockQ.ExitWriteLock(); - } - } - - public virtual void Add(TKey key, TValue value) - { - LockQ.EnterWriteLock(); - try - { - dict.Add(key, value); - } - finally - { - LockQ.ExitWriteLock(); - } - } - - public virtual bool ContainsKey(TKey key) - { - LockQ.EnterReadLock(); - try - { - return dict.ContainsKey(key); - } - finally - { - LockQ.ExitReadLock(); - } - } - - public virtual bool Remove(TKey key) - { - LockQ.EnterWriteLock(); - try - { - return dict.Remove(key); - } - finally - { - LockQ.ExitWriteLock(); - } - } - - public virtual bool TryGetValue(TKey key, out TValue value) - { - LockQ.EnterReadLock(); - try - { - return dict.TryGetValue(key, out value); - } - finally - { - LockQ.ExitReadLock(); - } - } - - /// - /// Merge does a blind remove, and then add. Basically a blind Upsert. - /// - /// Key to lookup - /// New Value - public void MergeSafe(TKey key, TValue newValue) - { - LockQ.EnterWriteLock(); - try - { - // take a writelock immediately since we will always be writing - if (dict.ContainsKey(key)) - dict.Remove(key); - - dict.Add(key, newValue); - } - finally - { - LockQ.ExitWriteLock(); - } - } - - /// - /// This is a blind remove. Prevents the need to check for existence first. - /// - /// Key to remove - public void RemoveSafe(TKey key) - { - LockQ.EnterReadLock(); - try - { - if (dict.ContainsKey(key)) - LockQ.EnterWriteLock(); - try - { - dict.Remove(key); - } - finally - { - LockQ.ExitWriteLock(); - } - } - finally - { - LockQ.ExitReadLock(); - } - } - - // This is the internal dictionary that we are wrapping - readonly IDictionary dict; - - readonly ReaderWriterLockSlim LockQ = new ReaderWriterLockSlim(); - } -} diff --git a/DataStructures/ThreadSafeQueue.cs b/DataStructures/ThreadSafeQueue.cs deleted file mode 100644 index d9197f0..0000000 --- a/DataStructures/ThreadSafeQueue.cs +++ /dev/null @@ -1,233 +0,0 @@ -using System.Collections.Generic; -using System.Threading; - -namespace Svelto.DataStructures -{ - public class ThreadSafeQueue - { - readonly Queue m_Queue; - - readonly ReaderWriterLockSlim LockQ = new ReaderWriterLockSlim(); - - public ThreadSafeQueue() - { - m_Queue = new Queue(); - } - - public ThreadSafeQueue(int capacity) - { - m_Queue = new Queue(capacity); - } - - public ThreadSafeQueue(IEnumerable collection) - { - m_Queue = new Queue(collection); - } - - public IEnumerator GetEnumerator() - { - Queue localQ; - - LockQ.EnterReadLock(); - try - { - localQ = new Queue(m_Queue); - } - - finally - { - LockQ.ExitReadLock(); - } - - foreach (T item in localQ) - yield return item; - } - - public void Enqueue(T item) - { - LockQ.EnterWriteLock(); - try - { - m_Queue.Enqueue(item); - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public T Dequeue() - { - LockQ.EnterWriteLock(); - try - { - return m_Queue.Dequeue(); - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public void EnqueueAll(IEnumerable ItemsToQueue) - { - LockQ.EnterWriteLock(); - try - { - foreach (T item in ItemsToQueue) - m_Queue.Enqueue(item); - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public FasterList DequeueAll() - { - LockQ.EnterWriteLock(); - try - { - FasterList returnList = new FasterList(); - - while (m_Queue.Count > 0) - returnList.Add(m_Queue.Dequeue()); - - return returnList; - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public void DequeueAllInto(FasterList list) - { - LockQ.EnterWriteLock(); - try - { - while (m_Queue.Count > 0) - list.Add(m_Queue.Dequeue()); - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public void DequeueInto(FasterList list, int count) - { - LockQ.EnterWriteLock(); - try - { - int originalSize = m_Queue.Count; - while (m_Queue.Count > 0 && originalSize - m_Queue.Count < count) - list.Add(m_Queue.Dequeue()); - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public FasterList DequeueAllAs() where U:class - { - LockQ.EnterWriteLock(); - try - { - FasterList returnList = new FasterList(); - - while (m_Queue.Count > 0) - returnList.Add(m_Queue.Dequeue() as U); - - return returnList; - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public T Peek() - { - LockQ.EnterWriteLock(); - try - { - T item = default(T); - - if (m_Queue.Count > 0) - item = m_Queue.Peek(); - - return item; - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public void Clear() - { - LockQ.EnterWriteLock(); - try - { - m_Queue.Clear(); - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public bool TryDequeue(out T item) - { - LockQ.EnterWriteLock(); - try - { - if (m_Queue.Count > 0) - { - item = m_Queue.Dequeue(); - - return true; - } - else - { - item = default(T); - - return false; - } - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public int Count - { - get - { - LockQ.EnterWriteLock(); - try - { - return m_Queue.Count; - } - - finally - { - LockQ.ExitWriteLock(); - } - } - } - } -} diff --git a/DataStructures/WeakReference.cs b/DataStructures/WeakReference.cs deleted file mode 100644 index 0f14cca..0000000 --- a/DataStructures/WeakReference.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -/// -/// Represents a weak reference, which references an object while still allowing -/// that object to be reclaimed by garbage collection. -/// -/// The type of the object that is referenced. - -namespace Svelto.DataStructures -{ -#if !NETFX_CORE - public class WeakReference - : WeakReference where T : class - { - public bool IsValid { get { return Target != null && IsAlive == true; } } - - /// - /// Gets or sets the object (the target) referenced by the - /// current WeakReference{T} object. - /// - public new T Target - { - get - { - return (T)base.Target; - } - set - { - base.Target = value; - } - } - /// - /// Initializes a new instance of the WeakReference{T} class, referencing - /// the specified object. - /// - /// The object to reference. - public WeakReference(T target) - : base(target) - { } - - /// - /// Initializes a new instance of the WeakReference{T} class, referencing - /// the specified object and using the specified resurrection tracking. - /// - /// An object to track. - /// Indicates when to stop tracking the object. - /// If true, the object is tracked - /// after finalization; if false, the object is only tracked - /// until finalization. - public WeakReference(T target, bool trackResurrection) - : base(target, trackResurrection) - { } - } -#else - public class WeakReference : System.WeakReference where T : class - { - public bool IsValid { get { return Target != null && IsAlive == true; } } - - public new T Target - { - get - { - return (T)base.Target; - } - set - { - base.Target = value; - } - } - - public WeakReference(T target) - : base(target) - { } - - public WeakReference(T target, bool trackResurrection) - : base(target, trackResurrection) - { } - } -#endif -} diff --git a/ECS/note.txt b/ECS/note.txt deleted file mode 100644 index 33ca04c..0000000 --- a/ECS/note.txt +++ /dev/null @@ -1,111 +0,0 @@ -systems do not hold component data, but only system states -systems cannot be injected -systems are SRP and OCP -systems communicates between component, mediators, producer/consumer, observers. producer/consumer and observers must be defined in the layer of the engine. -systems can have injected dependencies - -components don't have logic -components can have only getter and setter -components cannot define patterns that requires logic. -components cannot issues commands - -High Cohesion[edit] -Main article: Cohesion (computer science) -High Cohesion is an evaluative pattern that attempts to keep objects appropriately focused, manageable and understandable. High cohesion is generally used in support of Low Coupling. High cohesion means that the responsibilities of a given element are strongly related and highly focused. Breaking programs into classes and subsystems is an example of activities that increase the cohesive properties of a system. Alternatively, low cohesion is a situation in which a given element has too many unrelated responsibilities. Elements with low cohesion often suffer from being hard to comprehend, hard to reuse, hard to maintain and averse to change.[3] - -Low Coupling[edit] -Main article: Loose coupling -Low Coupling is an evaluative pattern, which dictates how to assign responsibilities to support: - -lower dependency between the classes, -change in one class having lower impact on other classes, -higher reuse potential. - -events, observers and mediators have the inconvience to hold the reference to the engine, which forces to use cleanup if the engine must be removed. -Observers are easy to clean up from the engine. Mediators needs to be integrated to the framework to be simple to clean up. Component events need the clean up function. -producer/consumer has the inconvienent to force check the number of jobs available everyframe - -Engine can't be removed, they can only be disabled, but the logic of disabling must be handled by the engine itself - -Should components have just one element? Should engines use just entityViews? Components are ditacted by the entities and EntityViews by the engines - -http://thelinuxlich.github.io/artemis_CSharp/ - -differences: components no events, everthing must be update -give more responsabiltiy to the user, semplicity - -https://github.com/sschmid/Entitas-CSharp/wiki/Overview - -no groups, no queries - -http://entity-systems.wikidot.com/es-articles - -http://www.ashframework.org/ - -it's very important to give a namespace to the engines. In this way it's impossible to create semantically wrong entityViews (PlayerEntityView Vs TargetEntityView) - -ToDo: - -it's not safe to remove an engine without having called being denitialised internal states. A special ClearOnRemove function must be added for each engine - -namespace GameFramework.RayCast -{ - public class RayCastEngineEngine - { - public RayCastEngine(RayCastEmployer jobList) - { - jobList.onJobassigned += OnRaycastRequested; - } - - public void Add(IComponent obj) - {} - - public void Remove(IComponent obj) - {} - - void OnRaycastRequested(RayCastJob job) - { - RaycastHit shootHit; - - Physics.Raycast(job.rayVector, out shootHit, job.range, _enemyMask); - - job.Done(shootHit); - } - - RayCastEmployer _employer; - - int _enemyMask; - } - - public struct RayCastJob - { - readonly public Ray rayVector; - readonly public float range; - readonly public Action Done; - - public RayCastJob(Ray direction, float distance, Action OnDone) - { - rayVector = direction; - range = distance; - Done = OnDone; - } - } - - public class RayCastEmployer - { - public event Action onJobassigned; - - public void AssignJob(RayCastJob data, Action onJobdone) - { - onJobassigned(data); - } - } -} - -if your code can be read as - -A tells B to do something is direct -A register B event is indirect -althoggh if B tells A something through event is direct again. B must say something like I don't know who you are, but this just happened. you say B.SomethingHappenedToMe() not B.YouMustDoThis(); - -un engine non deve mai avere concetti di un altro engine. dire all'engine sonoro suona morte � sbagliato. � l'engine death che triggera l'evento e l'engine sound ad ascoltarlo. diff --git a/Svelto.Common b/Svelto.Common new file mode 160000 index 0000000..1d516b3 --- /dev/null +++ b/Svelto.Common @@ -0,0 +1 @@ +Subproject commit 1d516b3c1eae36e366f48dad4af5950828793835 diff --git a/Svelto.ECS/.gitignore b/Svelto.ECS/.gitignore new file mode 100644 index 0000000..ac529bb --- /dev/null +++ b/Svelto.ECS/.gitignore @@ -0,0 +1,4 @@ +/EntitySystem/note.txt +/EntitySystem/note.txt.meta +/*.meta +*.meta diff --git a/Context/ContextNotifier.cs b/Svelto.ECS/Context/ContextNotifier.cs similarity index 100% rename from Context/ContextNotifier.cs rename to Svelto.ECS/Context/ContextNotifier.cs diff --git a/Context/Factories/GameObjectFactory.cs b/Svelto.ECS/Context/Factories/GameObjectFactory.cs similarity index 100% rename from Context/Factories/GameObjectFactory.cs rename to Svelto.ECS/Context/Factories/GameObjectFactory.cs diff --git a/Context/Factories/MonoBehaviourFactory.cs b/Svelto.ECS/Context/Factories/MonoBehaviourFactory.cs similarity index 100% rename from Context/Factories/MonoBehaviourFactory.cs rename to Svelto.ECS/Context/Factories/MonoBehaviourFactory.cs diff --git a/Context/ICompositionRoot.cs b/Svelto.ECS/Context/ICompositionRoot.cs similarity index 100% rename from Context/ICompositionRoot.cs rename to Svelto.ECS/Context/ICompositionRoot.cs diff --git a/Context/IContextNotifer.cs b/Svelto.ECS/Context/IContextNotifer.cs similarity index 100% rename from Context/IContextNotifer.cs rename to Svelto.ECS/Context/IContextNotifer.cs diff --git a/Svelto.ECS/Context/IUnityCompositionRoot.cs b/Svelto.ECS/Context/IUnityCompositionRoot.cs new file mode 100644 index 0000000..c4db99a --- /dev/null +++ b/Svelto.ECS/Context/IUnityCompositionRoot.cs @@ -0,0 +1,11 @@ +#if UNITY_5 || UNITY_5_3_OR_NEWER +namespace Svelto.Context +{ + public interface IUnityCompositionRoot + { + void OnContextCreated(UnityContext contextHolder); + void OnContextInitialized(); + void OnContextDestroyed(); + } +} +#endif \ No newline at end of file diff --git a/Context/IWaitForFrameworkDestruction.cs b/Svelto.ECS/Context/IWaitForFrameworkDestruction.cs similarity index 100% rename from Context/IWaitForFrameworkDestruction.cs rename to Svelto.ECS/Context/IWaitForFrameworkDestruction.cs diff --git a/Context/IWaitForFrameworkInitialization.cs b/Svelto.ECS/Context/IWaitForFrameworkInitialization.cs similarity index 100% rename from Context/IWaitForFrameworkInitialization.cs rename to Svelto.ECS/Context/IWaitForFrameworkInitialization.cs diff --git a/Context/UnityContext.cs b/Svelto.ECS/Context/UnityContext.cs similarity index 100% rename from Context/UnityContext.cs rename to Svelto.ECS/Context/UnityContext.cs diff --git a/Svelto.ECS/ECS/DataStructures/TypeSafeDictionary.cs b/Svelto.ECS/ECS/DataStructures/TypeSafeDictionary.cs new file mode 100644 index 0000000..c7cdc14 --- /dev/null +++ b/Svelto.ECS/ECS/DataStructures/TypeSafeDictionary.cs @@ -0,0 +1,51 @@ +using Svelto.DataStructures; +using System.Collections.Generic; + +namespace Svelto.ECS.Internal +{ + /// + /// 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. + /// + + public interface ITypeSafeDictionary + { + void FillWithIndexedEntityViews(ITypeSafeList entityViews); + bool Remove(int entityId); + IEntityView GetIndexedEntityView(int entityID); + } + + class TypeSafeDictionary : Dictionary, ITypeSafeDictionary where TValue:IEntityView + { + internal static readonly ReadOnlyDictionary Default = + new ReadOnlyDictionary(new Dictionary()); + + public void FillWithIndexedEntityViews(ITypeSafeList entityViews) + { + int count; + var buffer = FasterList.NoVirt.ToArrayFast((FasterList) 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]; + } + } +} diff --git a/Svelto.ECS/ECS/DataStructures/TypeSafeFasterListForECS.cs b/Svelto.ECS/ECS/DataStructures/TypeSafeFasterListForECS.cs new file mode 100644 index 0000000..17235f2 --- /dev/null +++ b/Svelto.ECS/ECS/DataStructures/TypeSafeFasterListForECS.cs @@ -0,0 +1,148 @@ +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(); + bool isQueryiableEntityView { get; } + bool UnorderedRemove(int entityID); + ITypeSafeDictionary CreateIndexedDictionary(); + IEntityView[] ToArrayFast(out int count); + void ReserveCapacity(int capacity); + } + + class TypeSafeFasterListForECS: FasterList where T:IEntityView + { + protected TypeSafeFasterListForECS() + { + _mappedIndices = new Dictionary(); + } + + protected TypeSafeFasterListForECS(int size):base(size) + { + _mappedIndices = new Dictionary(); + } + + 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); + + 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 _mappedIndices; + } + + class TypeSafeFasterListForECSForStructs : TypeSafeFasterListForECS, ITypeSafeList where T:struct, IEntityStruct + { + public TypeSafeFasterListForECSForStructs(int size):base(size) + {} + + public TypeSafeFasterListForECSForStructs() + {} + + public ITypeSafeList Create() + { + return new TypeSafeFasterListForECSForStructs(); + } + + 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(size); + } + } + + class TypeSafeFasterListForECSForClasses : TypeSafeFasterListForECS, ITypeSafeList where T:EntityView, new() + { + public TypeSafeFasterListForECSForClasses(int size):base(size) + {} + + public TypeSafeFasterListForECSForClasses() + {} + + public ITypeSafeList Create() + { + return new TypeSafeFasterListForECSForClasses(); + } + + public bool isQueryiableEntityView + { + get { return true; } + } + + public ITypeSafeDictionary CreateIndexedDictionary() + { + return new TypeSafeDictionary(); + } + + public IEntityView[] ToArrayFast(out int count) + { + count = this.Count; + + return this.ToArrayFast(); + } + + public ITypeSafeList Create(int size) + { + return new TypeSafeFasterListForECSForClasses(size); + } + } +} diff --git a/ECS/Dispatcher/DispatchOnChange.cs b/Svelto.ECS/ECS/Dispatcher/DispatchOnChange.cs similarity index 100% rename from ECS/Dispatcher/DispatchOnChange.cs rename to Svelto.ECS/ECS/Dispatcher/DispatchOnChange.cs diff --git a/ECS/Dispatcher/DispatcherOnSet.cs b/Svelto.ECS/ECS/Dispatcher/DispatcherOnSet.cs similarity index 100% rename from ECS/Dispatcher/DispatcherOnSet.cs rename to Svelto.ECS/ECS/Dispatcher/DispatcherOnSet.cs diff --git a/Svelto.ECS/ECS/EnginesRootEngines.cs b/Svelto.ECS/ECS/EnginesRootEngines.cs new file mode 100644 index 0000000..e2ebfaa --- /dev/null +++ b/Svelto.ECS/ECS/EnginesRootEngines.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Svelto.DataStructures; +using Svelto.ECS.Internal; +using Svelto.ECS.Schedulers; +using Svelto.WeakEvents; + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR +using Svelto.ECS.Profiler; +#endif + +namespace Svelto.ECS +{ + public partial class EnginesRoot : IDisposable + { + /// + /// 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. + /// + public EnginesRoot(EntitySubmissionScheduler entityViewScheduler) + { + _entityViewEngines = new Dictionary>(); + _otherEngines = new FasterList(); + + _entityViewsDB = new Dictionary(); + _metaEntityViewsDB = new Dictionary(); + _groupEntityViewsDB = new Dictionary>(); + _entityViewsDBDic = new Dictionary(); + + _entityViewsToAdd = new DoubleBufferedEntityViews>(); + _metaEntityViewsToAdd = new DoubleBufferedEntityViews>(); + _groupedEntityViewsToAdd = new DoubleBufferedEntityViews>>(); + + _DB = new EntityViewsDB(_entityViewsDB, _entityViewsDBDic, _metaEntityViewsDB, _groupEntityViewsDB); + + _scheduler = entityViewScheduler; + _scheduler.Schedule(new WeakAction(SubmitEntityViews)); +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); + debugEngineObject.gameObject.AddComponent(); +#endif + } + + public void AddEngine(IEngine engine) + { +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + Profiler.EngineProfiler.AddEngine(engine); +#endif + var viewEngine = engine as IHandleEntityViewEngine; + + if (viewEngine != null) + CheckEntityViewsEngine(viewEngine); + else + _otherEngines.Add(engine); + + var queryableEntityViewEngine = engine as IQueryingEntityViewEngine; + if (queryableEntityViewEngine != null) + { + queryableEntityViewEngine.entityViewsDB = _DB; + queryableEntityViewEngine.Ready(); + } + } + + void CheckEntityViewsEngine(IEngine engine) + { + var baseType = engine.GetType().GetBaseType(); + + while (baseType != _object) + { + if (baseType.IsGenericTypeEx()) + { + var genericArguments = baseType.GetGenericArgumentsEx(); + AddEngine(engine as IHandleEntityViewEngine, genericArguments, _entityViewEngines); + + return; + } + + baseType = baseType.GetBaseType(); + } + + throw new ArgumentException("Not Supported Engine " + engine.ToString()); + } + + //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 engine, Type[] entityViewTypes, + Dictionary> engines) where T:IEngine + { + for (int i = 0; i < entityViewTypes.Length; i++) + { + var type = entityViewTypes[i]; + + AddEngine(engine, engines, type); + } + } + + static void AddEngine(T engine, Dictionary> engines, Type type) where T : IEngine + { + FasterList list; + if (engines.TryGetValue(type, out list) == false) + { + list = new FasterList(); + + engines.Add(type, list); + } + + list.Add(engine); + } + + readonly Dictionary> _entityViewEngines; + readonly FasterList _otherEngines; + + static readonly Type _entityViewType= typeof(EntityView); + static readonly Type _object = typeof(object); + + class DoubleBufferedEntityViews 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; + } + } + } +} \ No newline at end of file diff --git a/Svelto.ECS/ECS/EnginesRootEntities.cs b/Svelto.ECS/ECS/EnginesRootEntities.cs new file mode 100644 index 0000000..fea2823 --- /dev/null +++ b/Svelto.ECS/ECS/EnginesRootEntities.cs @@ -0,0 +1,411 @@ +using System; +using System.Collections.Generic; +using Svelto.DataStructures; +using Svelto.ECS.Internal; + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR +using Svelto.ECS.Profiler; +#endif + +namespace Svelto.ECS +{ + public partial class EnginesRoot : IDisposable + { + /// + /// 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. + /// + /// + public IEntityFactory GenerateEntityFactory() + { + return new GenericEntityFactory(new DataStructures.WeakReference(this)); + } + + public IEntityFunctions GenerateEntityFunctions() + { + return new GenericEntityFunctions(new DataStructures.WeakReference(this)); + } + + /// + /// 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 + /// + /// + /// + /// + void BuildEntity(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() + { + EntityFactory.BuildEntityViews + (entityID, _entityViewsToAdd.current, EntityDescriptorTemplate.Default, implementors); + } + + /// + /// 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. + /// + /// + /// + /// + void BuildEntity(int entityID, IEntityDescriptorInfo entityDescriptor, object[] implementors) + { + EntityFactory.BuildEntityViews + (entityID, _entityViewsToAdd.current, entityDescriptor, implementors); + } + + /// + /// A meta entity is a way to manage a set of entitites that are not easily + /// queriable otherwise. For example you may want to group existing entities + /// by size and type and then use the meta entity 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. + /// + /// + /// + /// + void BuildMetaEntity(int metaEntityID, object[] implementors) where T : IEntityDescriptor, new() + { + EntityFactory.BuildEntityViews(metaEntityID, _metaEntityViewsToAdd.current, + EntityDescriptorTemplate.Default, implementors); + } + + /// + /// 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. + /// + /// + /// + /// + /// + void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() + { + EntityFactory.BuildGroupedEntityViews(entityID, groupID, + _groupedEntityViewsToAdd.current, + EntityDescriptorTemplate.Default, + implementors); + } + + void BuildEntityInGroup(int entityID, int groupID, IEntityDescriptorInfo entityDescriptor, object[] implementors = null) + { + EntityFactory.BuildGroupedEntityViews(entityID, groupID, + _groupedEntityViewsToAdd.current, + entityDescriptor, implementors); + } + + void Preallocate(int size) where T : IEntityDescriptor, new() + { + var entityViewsToBuild = ((EntityDescriptorInfo) EntityDescriptorTemplate.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 + InternalRemoveFromDBAndEngines(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, _entityViewsDB); + } + + void RemoveEntity(int entityID) where T : IEntityDescriptor, new() + { + InternalRemoveFromDBAndEngines( ((EntityDescriptorInfo) EntityDescriptorTemplate.Default).entityViewsToBuild, entityID, _entityViewsDB); + } + + void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() + { + InternalRemoveFromDBAndEngines(((EntityDescriptorInfo) EntityDescriptorTemplate.Default).entityViewsToBuild, metaEntityID, _metaEntityViewsDB); + } + + void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() + { + InternalRemoveFromDBAndEngines(((EntityDescriptorInfo) EntityDescriptorTemplate.Default).entityViewsToBuild, entityID, _groupEntityViewsDB[groupID]); + } + + void RemoveEntitiesGroup(int groupID) + { + foreach (var group in _groupEntityViewsDB[groupID]) + { + var entityViewType = group.Key; + + int count; + var entities = group.Value.ToArrayFast(out count); + + for (int i = 0; i < count; i++) + { + var entityID = entities[i].ID; + + InternalRemoveEntityViewFromDBAndEngines(_entityViewsDB, entityViewType, entityID); + } + } + + _groupEntityViewsDB.Remove(groupID); + } + + void InternalRemoveEntityViewFromDBAndEngines(Dictionary entityViewsDB, + Type entityViewType, int entityID) + { + var 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); + + for (var current = entityViewType; current != _entityViewType; current = current.BaseType) + RemoveEntityViewFromEngines(_entityViewEngines, entityView, current); + } + } + + void SwapEntityGroup(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 = ((EntityDescriptorInfo) EntityDescriptorTemplate.Default).entityViewsToBuild; + int entityViewBuildersCount = entityViewBuilders.Length; + + var dictionary = _groupEntityViewsDB[fromGroupID]; + + Dictionary groupedEntityViewsTyped; + if (_groupEntityViewsDB.TryGetValue(toGroupID, out groupedEntityViewsTyped) == false) + { + groupedEntityViewsTyped = new Dictionary(); + + _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 InternalRemoveFromDBAndEngines(IEntityViewBuilder[] entityViewBuilders, int entityID, + Dictionary entityViewsDB) + { + int entityViewBuildersCount = entityViewBuilders.Length; + + for (int i = 0; i < entityViewBuildersCount; i++) + { + Type entityViewType = entityViewBuilders[i].GetEntityViewType(); + + InternalRemoveEntityViewFromDBAndEngines(entityViewsDB, entityViewType, entityID); + } + } + + void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID, + Dictionary entityViewsDB) + { + InternalRemoveFromGroupDB(entityViewBuilders, entityID, groupID); + + InternalRemoveFromDBAndEngines(entityViewBuilders, entityID, entityViewsDB); + } + + void InternalRemoveFromGroupDB(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID) + { + int entityViewBuildersCount = entityViewBuilders.Length; + + Dictionary 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> entityViewEngines, + IEntityView entityView, Type entityViewType) + { + FasterList enginesForEntityView; + + if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) + { + int count; + var fastList = FasterList.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 _weakEngine; + + public GenericEntityFactory(DataStructures.WeakReference weakReference) + { + _weakEngine = weakReference; + } + + public void BuildEntity(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() + { + _weakEngine.Target.BuildEntity(entityID, implementors); + } + + public void BuildEntity(int entityID, IEntityDescriptorInfo entityDescriptor, object[] implementors = null) + { + _weakEngine.Target.BuildEntity(entityID, entityDescriptor, implementors); + } + + public void BuildMetaEntity(int metaEntityID, object[] implementors = null) where T : IEntityDescriptor, new() + { + _weakEngine.Target.BuildMetaEntity(metaEntityID, implementors); + } + + public void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() + { + _weakEngine.Target.BuildEntityInGroup(entityID, groupID, implementors); + } + + public void BuildEntityInGroup(int entityID, int groupID, IEntityDescriptorInfo entityDescriptor, object[] implementors = null) + { + _weakEngine.Target.BuildEntityInGroup(entityID, groupID, entityDescriptor, implementors); + } + + public void Preallocate(int size) where T : IEntityDescriptor, new() + { + _weakEngine.Target.Preallocate(size); + } + } + + class GenericEntityFunctions : IEntityFunctions + { + public GenericEntityFunctions(DataStructures.WeakReference weakReference) + { + _weakReference = weakReference; + } + + public void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) + { + _weakReference.Target.RemoveEntity(entityID, removeInfo); + } + + public void RemoveEntity(int entityID) where T : IEntityDescriptor, new() + { + _weakReference.Target.RemoveEntity(entityID); + } + + public void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() + { + _weakReference.Target.RemoveEntity(metaEntityID); + } + + public void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() + { + _weakReference.Target.RemoveEntity(entityID); + } + + public void RemoveGroupedEntities(int groupID) + { + _weakReference.Target.RemoveEntitiesGroup(groupID); + } + + public void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new() + { + _weakReference.Target.SwapEntityGroup(entityID, fromGroupID, toGroupID); + } + + readonly DataStructures.WeakReference _weakReference; + } + + public void Dispose() + { + foreach (var entity in _entityViewsDB) + { + if (entity.Value.isQueryiableEntityView == true) + { + foreach (var entityView in entity.Value) + { + RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); + } + } + } + + foreach (var entity in _metaEntityViewsDB) + { + foreach (var entityView in entity.Value) + { + RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); + } + } + } + + readonly EntityViewsDB _DB; + + readonly Dictionary _entityViewsDB; + readonly Dictionary _metaEntityViewsDB; + readonly Dictionary> _groupEntityViewsDB; + + readonly Dictionary _entityViewsDBDic; + + } +} \ No newline at end of file diff --git a/Svelto.ECS/ECS/EnginesRootSubmission.cs b/Svelto.ECS/ECS/EnginesRootSubmission.cs new file mode 100644 index 0000000..c2343b9 --- /dev/null +++ b/Svelto.ECS/ECS/EnginesRootSubmission.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using Svelto.DataStructures; +using Svelto.ECS.Internal; +using Svelto.ECS.Schedulers; + +#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 entityViewsToAdd, + Dictionary 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) + { + var type = entityViewList.Key; + for (var current = type; current != _entityViewType; current = current.BaseType) + AddEntityViewToTheSuitableEngines(_entityViewEngines, entityViewList.Value, + current); + } + } + } + + void AddGroupEntityViewsToTheDBAndSuitableEngines(Dictionary> groupedEntityViewsToAdd, + Dictionary> groupEntityViewsDB, + Dictionary entityViewsDB) + { + foreach (var group in groupedEntityViewsToAdd) + { + AddEntityViewsToGroupDB(groupEntityViewsDB, @group); + + AddEntityViewsToTheDBAndSuitableEngines(group.Value, entityViewsDB); + } + } + + static void AddEntityViewsToGroupDB(Dictionary> groupEntityViewsDB, + KeyValuePair> @group) + { + Dictionary groupedEntityViewsByType; + + if (groupEntityViewsDB.TryGetValue(@group.Key, out groupedEntityViewsByType) == false) + groupedEntityViewsByType = groupEntityViewsDB[@group.Key] = new Dictionary(); + + foreach (var entityView in @group.Value) + { + groupedEntityViewsByType.Add(entityView.Key, entityView.Value); + } + } + + static void AddEntityViewToDB(Dictionary entityViewsDB, KeyValuePair 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 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> entityViewEngines, ITypeSafeList entityViewsList, Type entityViewType) + { + FasterList 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.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 + } + } + } + } + + readonly DoubleBufferedEntityViews> _entityViewsToAdd; + readonly DoubleBufferedEntityViews> _metaEntityViewsToAdd; + readonly DoubleBufferedEntityViews>> _groupedEntityViewsToAdd; + + readonly EntitySubmissionScheduler _scheduler; + + } +} \ No newline at end of file diff --git a/ECS/EntityDescriptor.cs b/Svelto.ECS/ECS/EntityDescriptor.cs similarity index 76% rename from ECS/EntityDescriptor.cs rename to Svelto.ECS/ECS/EntityDescriptor.cs index 9b2de27..d6c5aa3 100644 --- a/ECS/EntityDescriptor.cs +++ b/Svelto.ECS/ECS/EntityDescriptor.cs @@ -11,35 +11,72 @@ namespace Svelto.ECS IEntityViewBuilder[] entityViewsToBuild { get; } } - internal static class EntityDescriptorTemplate where TType : IEntityDescriptor, new() + public class EntityDescriptor:IEntityDescriptor { - public static readonly EntityDescriptorInfo Default = new EntityDescriptorInfo(new TType()); + protected EntityDescriptor(IEntityViewBuilder[] entityViewsToBuild) + { + this.entityViewsToBuild = entityViewsToBuild; + } + + public IEntityViewBuilder[] entityViewsToBuild { get; private set; } } - public class EntityDescriptorInfo + public interface IEntityDescriptorInfo + {} + + public static class EntityDescriptorTemplate where TType : IEntityDescriptor, new() { - readonly internal IEntityViewBuilder[] entityViewsToBuild; - readonly internal RemoveEntityImplementor removeEntityImplementor; - internal readonly string name; + public static readonly IEntityDescriptorInfo Default = new EntityDescriptorInfo(new TType()); + } - internal EntityDescriptorInfo(IEntityDescriptor descriptor) + public class DynamicEntityDescriptorInfo : EntityDescriptorInfo where TType : IEntityDescriptor, new() + { + public DynamicEntityDescriptorInfo(FasterList extraEntityViews) { - name = descriptor.ToString(); - entityViewsToBuild = descriptor.entityViewsToBuild; + DesignByContract.Check.Require(extraEntityViews.Count > 0, "don't use a DynamicEntityDescriptorInfo if you don't need to use extra EntityViews"); + + var descriptor = new TType(); + int length = descriptor.entityViewsToBuild.Length; + + entityViewsToBuild = new IEntityViewBuilder[length + extraEntityViews.Count]; + + Array.Copy(descriptor.entityViewsToBuild, 0, entityViewsToBuild, 0, length); + Array.Copy(extraEntityViews.ToArrayFast(), 0, entityViewsToBuild, length, extraEntityViews.Count); + removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuild); + name = descriptor.ToString(); } } } namespace Svelto.ECS.Internal { + public class EntityDescriptorInfo:IEntityDescriptorInfo + { + internal IEntityViewBuilder[] entityViewsToBuild; + internal RemoveEntityImplementor removeEntityImplementor; + internal string name; + + internal EntityDescriptorInfo(IEntityDescriptor descriptor) + { + name = descriptor.ToString(); + entityViewsToBuild = descriptor.entityViewsToBuild; + + removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuild); + } + + protected EntityDescriptorInfo() + {} + } + static class EntityFactory { internal static void BuildGroupedEntityViews(int entityID, int groupID, Dictionary> groupEntityViewsByType, - EntityDescriptorInfo entityViewsToBuildDescriptor, + IEntityDescriptorInfo eentityViewsToBuildDescriptor, object[] implementors) { + var entityViewsToBuildDescriptor = eentityViewsToBuildDescriptor as EntityDescriptorInfo; Dictionary groupedEntityViewsTyped; if (groupEntityViewsByType.TryGetValue(groupID, out groupedEntityViewsTyped) == false) @@ -48,6 +85,7 @@ namespace Svelto.ECS.Internal groupEntityViewsByType.Add(groupID, groupedEntityViewsTyped); } + //I would like to find a better solution for this var removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.entityViewsToBuild, groupID); InternalBuildEntityViews(entityID, groupedEntityViewsTyped, entityViewsToBuildDescriptor, implementors, removeEntityImplementor); @@ -55,19 +93,21 @@ namespace Svelto.ECS.Internal internal static void BuildEntityViews(int entityID, Dictionary entityViewsByType, - EntityDescriptorInfo entityViewsToBuildDescriptor, + IEntityDescriptorInfo eentityViewsToBuildDescriptor, object[] implementors) { + var entityViewsToBuildDescriptor = eentityViewsToBuildDescriptor as EntityDescriptorInfo; var removeEntityImplementor = entityViewsToBuildDescriptor.removeEntityImplementor; InternalBuildEntityViews(entityID, entityViewsByType, entityViewsToBuildDescriptor, implementors, removeEntityImplementor); } - private static void InternalBuildEntityViews(int entityID, + static void InternalBuildEntityViews(int entityID, Dictionary entityViewsByType, - EntityDescriptorInfo entityViewsToBuildDescriptor, + IEntityDescriptorInfo eentityViewsToBuildDescriptor, object[] implementors, RemoveEntityImplementor removeEntityImplementor) { + var entityViewsToBuildDescriptor = eentityViewsToBuildDescriptor as EntityDescriptorInfo; var entityViewsToBuild = entityViewsToBuildDescriptor.entityViewsToBuild; int count = entityViewsToBuild.Length; @@ -92,7 +132,7 @@ namespace Svelto.ECS.Internal } } - internal static IEntityView BuildEntityView(int entityID, Dictionary entityViewsByType, + static IEntityView BuildEntityView(int entityID, Dictionary entityViewsByType, Type entityViewType, IEntityViewBuilder entityViewBuilder) { ITypeSafeList entityViewsList; @@ -148,8 +188,6 @@ namespace Svelto.ECS.Internal #else implementorsByType[componentType] = implementor; #endif - - } } #if DEBUG && !PROFILER @@ -223,12 +261,12 @@ namespace Svelto.ECS.Internal static Dictionary _cachedTypes = new Dictionary(); const string DUPLICATE_IMPLEMENTOR_ERROR = - "Svelto.ECS the same component is implemented with more than one implementor. This is considered an error and MUST be fixed."; + "Svelto.ECS the same component is implemented with more than one implementor. This is considered an error and MUST be fixed. "; const string NULL_IMPLEMENTOR_ERROR = - "Svelto.ECS Null implementor, please be careful about the implementors passed to avoid performance loss"; + "Svelto.ECS Null implementor, please be careful about the implementors passed to avoid performance loss "; - const string NOT_FOUND_EXCEPTION = "Svelto.ECS Implementor not found for an EntityView."; + const string NOT_FOUND_EXCEPTION = "Svelto.ECS Implementor not found for an EntityView. "; } } diff --git a/Svelto.ECS/ECS/EntitySubmissionScheduler.cs b/Svelto.ECS/ECS/EntitySubmissionScheduler.cs new file mode 100644 index 0000000..cfa8168 --- /dev/null +++ b/Svelto.ECS/ECS/EntitySubmissionScheduler.cs @@ -0,0 +1,9 @@ +using Svelto.WeakEvents; + +namespace Svelto.ECS.Schedulers +{ + public abstract class EntitySubmissionScheduler + { + abstract public void Schedule(WeakAction submitEntityViews); + } +} \ No newline at end of file diff --git a/Svelto.ECS/ECS/EntityView.cs b/Svelto.ECS/ECS/EntityView.cs new file mode 100644 index 0000000..b8e56fa --- /dev/null +++ b/Svelto.ECS/ECS/EntityView.cs @@ -0,0 +1,59 @@ +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>> entityViewBlazingFastReflection; + internal int _ID; + } + + static class EntityView where T: EntityView, new() + { + internal static T BuildEntityView(int ID) + { + if (FieldCache.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 setter = FastInvoke.MakeSetter(field); + + FieldCache.list.Add(new KeyValuePair>(field.FieldType, setter)); + } + } + + return new T { _ID = ID, entityViewBlazingFastReflection = FieldCache.list }; + } + + //check if I can remove W + static class FieldCache where W:T + { + internal static readonly FasterList>> list + = new FasterList>>(); + } + } +} + diff --git a/Svelto.ECS/ECS/EntityViewBuilder.cs b/Svelto.ECS/ECS/EntityViewBuilder.cs new file mode 100644 index 0000000..73606af --- /dev/null +++ b/Svelto.ECS/ECS/EntityViewBuilder.cs @@ -0,0 +1,99 @@ +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 : IEntityViewBuilder where EntityViewType : EntityView, new() + { + public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) + { + if (list == null) + list = new TypeSafeFasterListForECSForClasses(); + + var castedList = list as TypeSafeFasterListForECSForClasses; + + var lentityView = EntityView.BuildEntityView(entityID); + + castedList.Add(lentityView); + + entityView = lentityView; + } + + public ITypeSafeList Preallocate(ref ITypeSafeList list, int size) + { + if (list == null) + list = new TypeSafeFasterListForECSForClasses(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; + var toCastedList = toSafeList as TypeSafeFasterListForECSForClasses; + + toCastedList.Add(fromCastedList[fromCastedList.GetIndexFromID(entityID)]); + } + + readonly Type _entityViewType = typeof(EntityViewType); + } + + public class EntityStructBuilder : 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(); + + var castedList = list as TypeSafeFasterListForECSForStructs; + + castedList.Add(lentityView); + + entityView = null; + } + + public ITypeSafeList Preallocate(ref ITypeSafeList list, int size) + { + if (list == null) + list = new TypeSafeFasterListForECSForStructs(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; + var toCastedList = toSafeList as TypeSafeFasterListForECSForStructs; + + toCastedList.Add(fromCastedList[fromCastedList.GetIndexFromID(entityID)]); + } + + readonly Type _entityViewType = typeof(EntityViewType); + } +} \ No newline at end of file diff --git a/Svelto.ECS/ECS/EntityViewsDB.cs b/Svelto.ECS/ECS/EntityViewsDB.cs new file mode 100644 index 0000000..b92c5ed --- /dev/null +++ b/Svelto.ECS/ECS/EntityViewsDB.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using Svelto.DataStructures; + +namespace Svelto.ECS.Internal +{ + class EntityViewsDB : IEntityViewsDB + { + internal EntityViewsDB( Dictionary entityViewsDB, + Dictionary entityViewsDBdic, + Dictionary metaEntityViewsDB, + Dictionary> groupEntityViewsDB) + { + _entityViewsDB = entityViewsDB; + _entityViewsDBdic = entityViewsDBdic; + _metaEntityViewsDB = metaEntityViewsDB; + _groupEntityViewsDB = groupEntityViewsDB; + } + + public FasterReadOnlyList QueryEntityViews() where T:EntityView, new() + { + var type = typeof(T); + + ITypeSafeList entityViews; + + if (_entityViewsDB.TryGetValue(type, out entityViews) == false) + return RetrieveEmptyEntityViewList(); + + return new FasterReadOnlyList((FasterList)entityViews); + } + + public FasterReadOnlyList QueryGroupedEntityViews(int @group) where T:EntityView, new() + { + Dictionary entityViews; + + if (_groupEntityViewsDB.TryGetValue(group, out entityViews) == false) + return RetrieveEmptyEntityViewList(); + + return new FasterReadOnlyList(entityViews as FasterList); + } + + public T[] QueryEntityViewsAsArray(out int count) where T : IEntityView + { + var type = typeof(T); + count = 0; + + ITypeSafeList entityViews; + + if (_entityViewsDB.TryGetValue(type, out entityViews) == false) + return RetrieveEmptyEntityViewArray(); + + var castedEntityViews = (FasterList)entityViews; + + return FasterList < T > .NoVirt.ToArrayFast(castedEntityViews, out count); + } + + public T[] QueryGroupedEntityViewsAsArray(int @group, out int count) where T : IEntityView + { + var type = typeof(T); + count = 0; + + Dictionary entityViews; + + if (_groupEntityViewsDB.TryGetValue(group, out entityViews) == false) + return RetrieveEmptyEntityViewArray(); + + var castedEntityViews = (FasterList)entityViews[type]; + + count = castedEntityViews.Count; + + return FasterList.NoVirt.ToArrayFast(castedEntityViews, out count); + } + + public ReadOnlyDictionary QueryIndexableEntityViews() where T:IEntityView + { + var type = typeof(T); + + ITypeSafeDictionary entityViews; + + if (_entityViewsDBdic.TryGetValue(type, out entityViews) == false) + return TypeSafeDictionary.Default; + + return new ReadOnlyDictionary(entityViews as Dictionary); + } + + public bool TryQueryEntityView(int ID, out T entityView) where T : IEntityView + { + var type = typeof(T); + + T internalEntityView; + + ITypeSafeDictionary entityViews; + TypeSafeDictionary casted; + + _entityViewsDBdic.TryGetValue(type, out entityViews); + casted = entityViews as TypeSafeDictionary; + + if (casted != null && + casted.TryGetValue(ID, out internalEntityView)) + { + entityView = internalEntityView; + + return true; + } + + entityView = default(T); + + return false; + } + + public T QueryEntityView(int ID) where T : IEntityView + { + var type = typeof(T); + + T internalEntityView; ITypeSafeDictionary entityViews; + TypeSafeDictionary casted; + + _entityViewsDBdic.TryGetValue(type, out entityViews); + casted = entityViews as TypeSafeDictionary; + + if (casted != null && + casted.TryGetValue(ID, out internalEntityView)) + return (T)internalEntityView; + + throw new Exception("EntityView Not Found"); + } + + public T QueryMetaEntityView(int metaEntityID) where T:EntityView, new() + { + return QueryEntityView(metaEntityID); + } + + public bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T:EntityView, new() + { + return TryQueryEntityView(metaEntityID, out entityView); + } + + public FasterReadOnlyList QueryMetaEntityViews() where T:EntityView, new() + { + var type = typeof(T); + + ITypeSafeList entityViews; + + if (_metaEntityViewsDB.TryGetValue(type, out entityViews) == false) + return RetrieveEmptyEntityViewList(); + + return new FasterReadOnlyList((FasterList)entityViews); + } + + static FasterReadOnlyList RetrieveEmptyEntityViewList() + { + return FasterReadOnlyList.DefaultList; + } + + static T[] RetrieveEmptyEntityViewArray() + { + return FasterList.DefaultList.ToArrayFast(); + } + + readonly Dictionary _entityViewsDB; + readonly Dictionary _entityViewsDBdic; + readonly Dictionary _metaEntityViewsDB; + readonly Dictionary> _groupEntityViewsDB; + } +} diff --git a/Svelto.ECS/ECS/Experimental/StructNodeCollections.cs b/Svelto.ECS/ECS/Experimental/StructNodeCollections.cs new file mode 100644 index 0000000..1b81938 --- /dev/null +++ b/Svelto.ECS/ECS/Experimental/StructNodeCollections.cs @@ -0,0 +1,180 @@ +#if EXPERIMENTAL +using System; +using System.Collections.Generic; +using Svelto.DataStructures; +using Svelto.ECS.Experimental.Internal; + +namespace Svelto.ECS.Experimental.Internal +{ + public interface IStructEntityViewEngine : IEngine + { + void CreateStructEntityViews(SharedStructEntityViewLists sharedStructEntityViewLists); + } + + public interface IGroupedStructEntityViewsEngine : IEngine + { + void CreateStructEntityViews(SharedGroupedStructEntityViewsLists sharedStructEntityViewLists); + } +} + +namespace Svelto.ECS.Experimental +{ + public interface IGroupedEntityView + { + int groupID { get; set; } + } + + /// + /// The engines can receive and store IEntityViews structs + /// Unboxing will happen during the Add, but the + /// data will then be stored and processed as stucts + /// + public interface IStructEntityViewEngine : IStructEntityViewEngine where T:struct, IEntityStruct + { } + + /// + /// same as above, but the entityViews are grouped by ID + /// usually the ID is the owner of the entityViews of that + /// group + /// + public interface IGroupedStructEntityViewsEngine : IGroupedStructEntityViewsEngine where T : struct, IGroupedEntityView + { + void Add(ref T entityView); + void Remove(ref T entityView); + } + + public sealed class StructEntityViews where T:struct, IEntityStruct + { + public T[] GetList(out int numberOfItems) + { + numberOfItems = _internalList.Count; + return _internalList.ToArrayFast(); + } + + public StructEntityViews(SharedStructEntityViewLists container) + { + _internalList = SharedStructEntityViewLists.NoVirt.GetList(container); + } + + public void Add(T entityView) + { + T convert = (T)entityView; + + _internalList.Add(convert); + } + + readonly FasterList _internalList; + } + + public struct StructGroupEntityViews + where T : struct, IEntityView + { + public StructGroupEntityViews(SharedGroupedStructEntityViewsLists container) + { + _container = container; + indices = new Dictionary(); + } + + public void Add(int groupID, T entityView) + { + T convert = (T)entityView; + + var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList(_container, groupID) as FasterList); + indices[entityView.ID] = fasterList.Count; + + fasterList.Add(convert); + } + + public void Remove(int groupID, T entityView) + { + var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList(_container, groupID) as FasterList); + var index = indices[entityView.ID]; + indices.Remove(entityView.ID); + + if (fasterList.UnorderedRemoveAt(index)) + indices[fasterList[index].ID] = index; + } + + public T[] GetList(int groupID, out int numberOfItems) + { + var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList(_container, groupID) as FasterList); + + return FasterList.NoVirt.ToArrayFast(fasterList, out numberOfItems); + } + + readonly SharedGroupedStructEntityViewsLists _container; + readonly Dictionary indices; + } + + public class SharedStructEntityViewLists + { + internal SharedStructEntityViewLists() + { + _collection = new Dictionary(); + } + + internal static class NoVirt + { + internal static FasterList GetList(SharedStructEntityViewLists obj) where T : struct + { + IFasterList list; + if (obj._collection.TryGetValue(typeof(T), out list)) + { + return list as FasterList; + } + + list = new FasterList(); + + obj._collection.Add(typeof(T), list); + + return (FasterList)list; + } + } + + readonly Dictionary _collection; + } + + public class SharedGroupedStructEntityViewsLists + { + internal SharedGroupedStructEntityViewsLists() + { + _collection = new Dictionary>(); + } + + internal static class NoVirt + { + internal static IFasterList GetList(SharedGroupedStructEntityViewsLists list, int groupID) where T : struct + { + Dictionary dic = GetGroup(list); + IFasterList localList; + + if (dic.TryGetValue(groupID, out localList)) + return localList; + + localList = new FasterList(); + dic.Add(groupID, localList); + + return localList; + } + + internal static Dictionary GetGroup(SharedGroupedStructEntityViewsLists list) where T : struct + { + Dictionary dic; + + if (list._collection.TryGetValue(typeof(T), out dic)) + { + return dic; + } + + dic = new Dictionary(); + + list._collection.Add(typeof(T), dic); + + return dic; + } + } + + readonly Dictionary> _collection; + } +} +#endif \ No newline at end of file diff --git a/Svelto.ECS/ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs b/Svelto.ECS/ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs new file mode 100644 index 0000000..fb672cb --- /dev/null +++ b/Svelto.ECS/ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs @@ -0,0 +1,14 @@ +#if UNITY_5 || UNITY_5_3_OR_NEWER +namespace Svelto.ECS +{ + public class GenericEntityDescriptorHolder: + UnityEngine.MonoBehaviour , IEntityDescriptorHolder + where T: class, IEntityDescriptor, new() + { + public IEntityDescriptorInfo RetrieveDescriptor() + { + return EntityDescriptorTemplate.Default; + } + } +} +#endif \ No newline at end of file diff --git a/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs b/Svelto.ECS/ECS/Extensions/Unity/UnitySumbmissionEntityViewScheduler .cs similarity index 97% rename from ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs rename to Svelto.ECS/ECS/Extensions/Unity/UnitySumbmissionEntityViewScheduler .cs index a2dcf89..4eab8cd 100644 --- a/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs +++ b/Svelto.ECS/ECS/Extensions/Unity/UnitySumbmissionEntityViewScheduler .cs @@ -3,7 +3,7 @@ using System.Collections; using Svelto.WeakEvents; using UnityEngine; -namespace Svelto.ECS.Schedulers +namespace Svelto.ECS.Schedulers.Unity { //The EntityViewSubmissionScheduler has been introduced to make //the entityView submission logic platform indipendent. diff --git a/ECS/GenericEntityDescriptor.cs b/Svelto.ECS/ECS/GenericEntityDescriptor.cs similarity index 100% rename from ECS/GenericEntityDescriptor.cs rename to Svelto.ECS/ECS/GenericEntityDescriptor.cs diff --git a/ECS/IEngine.cs b/Svelto.ECS/ECS/IEngine.cs similarity index 59% rename from ECS/IEngine.cs rename to Svelto.ECS/ECS/IEngine.cs index 9fb5bec..98597d5 100644 --- a/ECS/IEngine.cs +++ b/Svelto.ECS/ECS/IEngine.cs @@ -11,16 +11,10 @@ namespace Svelto.ECS { public interface IEngine {} -#if EXPERIMENTAL - public interface IHandleActivableEntityEngine : IEngine - { - void Enable(EntityView entityView); - void Disable(EntityView entityView); - } -#endif + public interface IQueryingEntityViewEngine : IEngine { - IEngineEntityViewDB entityViewsDB { set; } + IEntityViewsDB entityViewsDB { set; } void Ready(); } diff --git a/Svelto.ECS/ECS/IEnginesInterfaces.cs b/Svelto.ECS/ECS/IEnginesInterfaces.cs new file mode 100644 index 0000000..36f9aab --- /dev/null +++ b/Svelto.ECS/ECS/IEnginesInterfaces.cs @@ -0,0 +1,29 @@ +namespace Svelto.ECS +{ + public interface IEntityFactory + { + void Preallocate(int size) where T : IEntityDescriptor, new(); + + void BuildEntity(int entityID, object[] implementors = null) where T:IEntityDescriptor, new(); + void BuildEntity(int entityID, IEntityDescriptorInfo entityDescriptorInfo, object[] implementors); + + void BuildMetaEntity(int metaEntityID, object[] implementors = null) where T:IEntityDescriptor, new(); + + void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T:IEntityDescriptor, new(); + void BuildEntityInGroup(int entityID, int groupID, IEntityDescriptorInfo entityDescriptor, object[] implementors); + } + + public interface IEntityFunctions + { + void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo); + void RemoveEntity(int entityID) where T:IEntityDescriptor, new(); + + void RemoveMetaEntity(int metaEntityID) where T:IEntityDescriptor, new(); + + void RemoveEntityFromGroup(int entityID, int groupID) where T:IEntityDescriptor, new(); + + void RemoveGroupedEntities(int groupID); + + void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new(); + } +} diff --git a/ECS/IEntityDescriptorHolder.cs b/Svelto.ECS/ECS/IEntityDescriptorHolder.cs similarity index 61% rename from ECS/IEntityDescriptorHolder.cs rename to Svelto.ECS/ECS/IEntityDescriptorHolder.cs index c2a7515..c144811 100644 --- a/ECS/IEntityDescriptorHolder.cs +++ b/Svelto.ECS/ECS/IEntityDescriptorHolder.cs @@ -2,6 +2,6 @@ namespace Svelto.ECS { public interface IEntityDescriptorHolder { - EntityDescriptorInfo RetrieveDescriptor(); + IEntityDescriptorInfo RetrieveDescriptor(); } } diff --git a/Svelto.ECS/ECS/IEntityViewsDB.cs b/Svelto.ECS/ECS/IEntityViewsDB.cs new file mode 100644 index 0000000..a6eb0c6 --- /dev/null +++ b/Svelto.ECS/ECS/IEntityViewsDB.cs @@ -0,0 +1,22 @@ +using Svelto.DataStructures; + +namespace Svelto.ECS +{ + public interface IEntityViewsDB + { + FasterReadOnlyList QueryEntityViews() where T:EntityView, new(); + FasterReadOnlyList QueryMetaEntityViews() where T: EntityView, new(); + FasterReadOnlyList QueryGroupedEntityViews(int group) where T: EntityView, new(); + + T[] QueryEntityViewsAsArray(out int count) where T: IEntityView; + T[] QueryGroupedEntityViewsAsArray(int @group, out int count) where T: IEntityView; + + ReadOnlyDictionary QueryIndexableEntityViews() where T: IEntityView; + bool TryQueryEntityView(int ID, out T entityView) where T : IEntityView; + T QueryEntityView(int ID) where T: IEntityView; + + bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T: EntityView, new(); + T QueryMetaEntityView(int metaEntityID) where T: EntityView, new(); + } +} + diff --git a/Svelto.ECS/ECS/MixedEntityDescriptor.cs b/Svelto.ECS/ECS/MixedEntityDescriptor.cs new file mode 100644 index 0000000..f91ad54 --- /dev/null +++ b/Svelto.ECS/ECS/MixedEntityDescriptor.cs @@ -0,0 +1,107 @@ +namespace Svelto.ECS +{ + public class MixedEntityDescriptor:IEntityDescriptor where T : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + where V : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + where V : class, IEntityViewBuilder, new() + where W : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V(), new W()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + where V : class, IEntityViewBuilder, new() + where W : class, IEntityViewBuilder, new() + where X : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V(), new W(), new X()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + where V : class, IEntityViewBuilder, new() + where W : class, IEntityViewBuilder, new() + where X : class, IEntityViewBuilder, new() + where Y : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V(), new W(), new X(), new Y()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } +} diff --git a/Svelto.ECS/ECS/MultiEntityViewsEngine.cs b/Svelto.ECS/ECS/MultiEntityViewsEngine.cs new file mode 100644 index 0000000..324bc36 --- /dev/null +++ b/Svelto.ECS/ECS/MultiEntityViewsEngine.cs @@ -0,0 +1,118 @@ +using Svelto.ECS.Internal; + +namespace Svelto.ECS.Internal +{ + public abstract class MultiEntityViewsEngine: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 : MultiEntityViewsEngine + where U:EntityView, new() where T : 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 : MultiEntityViewsEngine + where V : EntityView, new() where U : EntityView, new() where T : 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); + } + } + + /// + /// Please do not add more MultiEntityViewsEngine + /// if you use more than 4 nodes, your engine has + /// already too many responsabilities. + /// + public abstract class MultiEntityViewsEngine : MultiEntityViewsEngine + where W : EntityView, new() where V : EntityView, new() where U : EntityView, new() where T : EntityView, new() + { + protected abstract void Add(W entityView); + protected abstract void Remove(W entityView); + + public override void Add(IEntityView entityView) + { + var castedEntityView = entityView as W; + if (castedEntityView != null) + { + Add(castedEntityView); + } + else + base.Add(entityView); + } + + public override void Remove(IEntityView entityView) + { + var castedEntityView = entityView as W; + if (castedEntityView != null) + { + Remove(castedEntityView); + } + else + base.Remove(entityView); + } + } +} \ No newline at end of file diff --git a/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs b/Svelto.ECS/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs similarity index 100% rename from ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs rename to Svelto.ECS/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs diff --git a/ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs b/Svelto.ECS/ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs similarity index 100% rename from ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs rename to Svelto.ECS/ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs diff --git a/ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs b/Svelto.ECS/ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs similarity index 100% rename from ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs rename to Svelto.ECS/ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs diff --git a/ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs b/Svelto.ECS/ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs similarity index 100% rename from ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs rename to Svelto.ECS/ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs diff --git a/ECS/Profiler/EngineInfo.cs b/Svelto.ECS/ECS/Profiler/EngineInfo.cs similarity index 100% rename from ECS/Profiler/EngineInfo.cs rename to Svelto.ECS/ECS/Profiler/EngineInfo.cs diff --git a/ECS/Profiler/EngineProfiler.cs b/Svelto.ECS/ECS/Profiler/EngineProfiler.cs similarity index 100% rename from ECS/Profiler/EngineProfiler.cs rename to Svelto.ECS/ECS/Profiler/EngineProfiler.cs diff --git a/ECS/Profiler/EngineProfilerBehaviour.cs b/Svelto.ECS/ECS/Profiler/EngineProfilerBehaviour.cs similarity index 100% rename from ECS/Profiler/EngineProfilerBehaviour.cs rename to Svelto.ECS/ECS/Profiler/EngineProfilerBehaviour.cs diff --git a/Svelto.ECS/ECS/RemoveEntityImplementor.cs b/Svelto.ECS/ECS/RemoveEntityImplementor.cs new file mode 100644 index 0000000..0ad6a93 --- /dev/null +++ b/Svelto.ECS/ECS/RemoveEntityImplementor.cs @@ -0,0 +1,36 @@ +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); + } + + internal readonly RemoveEntityInfo removeEntityInfo; + internal readonly int groupID; + internal readonly bool isInAGroup; + } +} + +namespace Svelto.ECS +{ + public interface IRemoveEntityComponent + {} + + public struct RemoveEntityInfo + { + internal readonly IEntityViewBuilder[] entityViewsToBuild; + + public RemoveEntityInfo(IEntityViewBuilder[] entityViews) : this() + { + this.entityViewsToBuild = entityViews; + } + } +} diff --git a/ECS/Sequencer.cs b/Svelto.ECS/ECS/Sequencer.cs similarity index 100% rename from ECS/Sequencer.cs rename to Svelto.ECS/ECS/Sequencer.cs diff --git a/Svelto.ECS/ECS/SingleEntityViewEngine.cs b/Svelto.ECS/ECS/SingleEntityViewEngine.cs new file mode 100644 index 0000000..605f775 --- /dev/null +++ b/Svelto.ECS/ECS/SingleEntityViewEngine.cs @@ -0,0 +1,20 @@ +using Svelto.ECS.Internal; + +namespace Svelto.ECS +{ + public abstract class SingleEntityViewEngine : 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); + } +} diff --git a/Factories/IGameObjectFactory.cs b/Svelto.ECS/Factories/IGameObjectFactory.cs similarity index 100% rename from Factories/IGameObjectFactory.cs rename to Svelto.ECS/Factories/IGameObjectFactory.cs diff --git a/Factories/IMonoBehaviourFactory.cs b/Svelto.ECS/Factories/IMonoBehaviourFactory.cs similarity index 100% rename from Factories/IMonoBehaviourFactory.cs rename to Svelto.ECS/Factories/IMonoBehaviourFactory.cs diff --git a/LICENSE b/Svelto.ECS/LICENSE similarity index 100% rename from LICENSE rename to Svelto.ECS/LICENSE diff --git a/README.md b/Svelto.ECS/README.md similarity index 89% rename from README.md rename to Svelto.ECS/README.md index dac0880..2d521cb 100644 --- a/README.md +++ b/Svelto.ECS/README.md @@ -33,6 +33,12 @@ http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-iv-dependency http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-v-drifting-away-from-ioc-containers/ +new article on optimizations: + +http://www.sebaslab.com/svelto-ecs-svelto-tasks-to-write-data-oriented-cache-friendly-multi-threaded-code-in-unity/ + +Note: if you ever build something with Svelto.ECS that you can share with the community, please do and let me know. Other coders need more examples. + Copyright (c) Sebastiano Mandalà Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/Utilities/Console.cs b/Utilities/Console.cs deleted file mode 100644 index c5ca1a5..0000000 --- a/Utilities/Console.cs +++ /dev/null @@ -1,155 +0,0 @@ -using System; -#if NETFX_CORE -using Windows.System.Diagnostics; -#else -using System.Diagnostics; -#endif -using System.Text; - -namespace Utility -{ - public static class Console - { - static StringBuilder _stringBuilder = new StringBuilder(256); - - public static ILogger logger; - - public static volatile bool BatchLog = false; - - //Hack, have to find the right solution - public static Action onException; - - static Console() - { -#if UNITY_5_3_OR_NEWER || UNITY_5 - logger = new SlowLoggerUnity(); - onException = (e, message, stack) => - { - UnityEngine.Debug.LogException(e, null); - }; -#else - logger = new SimpleLogger(); -#endif - } - - public static void Log(string txt) - { - logger.Log(txt); - } - - public static void LogError(string txt) - { - string toPrint; - - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - _stringBuilder.Append("-!!!!!!-> "); - _stringBuilder.Append(txt); - - toPrint = _stringBuilder.ToString(); - } - - logger.Log(toPrint, null, LogType.Error); - } - - public static void LogError(string txt, string stack) - { - string toPrint; - - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - _stringBuilder.Append("-!!!!!!-> "); - _stringBuilder.Append(txt); - - toPrint = _stringBuilder.ToString(); - } - - logger.Log(toPrint, stack, LogType.Error); - } - - public static void LogException(Exception e) - { - string toPrint; - string stackTrace; - - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - _stringBuilder.Append("-!!!!!!-> ").Append(e.Message); - - stackTrace = e.StackTrace; - - if (e.InnerException != null) - { - e = e.InnerException; - - _stringBuilder.Append(" Inner Message: ").Append(e.Message).Append(" Inner Stacktrace:") - .Append(e.StackTrace); - - stackTrace = e.StackTrace; - } - - toPrint = _stringBuilder.ToString(); - } - - if (onException != null) - onException(e, toPrint, stackTrace); - } - - public static void LogWarning(string txt) - { - string toPrint; - - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - _stringBuilder.Append("------> "); - _stringBuilder.Append(txt); - - toPrint = _stringBuilder.ToString(); - } - - logger.Log(toPrint, null, LogType.Warning); - } - - /// - /// Use this function if you don't want the message to be batched - /// - /// - public static void SystemLog(string txt) - { - string toPrint; - - lock (_stringBuilder) - { -#if NETFX_CORE - string currentTimeString = DateTime.UtcNow.ToString("dd/mm/yy hh:ii:ss"); - string processTimeString = (DateTime.UtcNow - ProcessDiagnosticInfo.GetForCurrentProcess().ProcessStartTime.DateTime).ToString(); -#else - string currentTimeString = DateTime.UtcNow.ToLongTimeString(); //ensure includes seconds - string processTimeString = (DateTime.Now - Process.GetCurrentProcess().StartTime).ToString(); -#endif - - _stringBuilder.Length = 0; - _stringBuilder.Append("[").Append(currentTimeString); - _stringBuilder.Append("][").Append(processTimeString); - _stringBuilder.Length = _stringBuilder.Length - 3; //remove some precision that we don't need - _stringBuilder.Append("] ").AppendLine(txt); - - toPrint = _stringBuilder.ToString(); - } - -#if !UNITY_EDITOR -#if !NETFX_CORE - System.Console.WriteLine(toPrint); -#else - //find a way to adopt a logger externally, if this is still needed -#endif -#else - UnityEngine.Debug.Log(toPrint); -#endif - } - } -} \ No newline at end of file diff --git a/Utilities/DesignByContract.cs b/Utilities/DesignByContract.cs deleted file mode 100644 index b6a22d7..0000000 --- a/Utilities/DesignByContract.cs +++ /dev/null @@ -1,459 +0,0 @@ -// from: http://www.codeproject.com/Articles/1863/Design-by-Contract-Framework -// Provides support for Design By Contract -// as described by Bertrand Meyer in his seminal book, -// Object-Oriented Software Construction (2nd Ed) Prentice Hall 1997 -// (See chapters 11 and 12). -// -// See also Building Bug-free O-O Software: An Introduction to Design by Contract -// http://www.eiffel.com/doc/manuals/technology/contract/ -// -// The following conditional compilation symbols are supported: -// -// These suggestions are based on Bertrand Meyer's Object-Oriented Software Construction (2nd Ed) p393 -// -// DBC_CHECK_ALL - Check assertions - implies checking preconditions, postconditions and invariants -// DBC_CHECK_INVARIANT - Check invariants - implies checking preconditions and postconditions -// DBC_CHECK_POSTCONDITION - Check postconditions - implies checking preconditions -// DBC_CHECK_PRECONDITION - Check preconditions only, e.g., in Release build -// -// A suggested default usage scenario is the following: -// -// #if DEBUG -// #define DBC_CHECK_ALL -// #else -// #define DBC_CHECK_PRECONDITION -// #endif -// -// Alternatively, you can define these in the project properties dialog. - -#if DEBUG && !PROFILER -#define DBC_CHECK_ALL -#endif - -using System; -using System.Diagnostics; - -namespace DesignByContract -{ - /// - /// Design By Contract Checks. - /// - /// Each method generates an exception or - /// a trace assertion statement if the contract is broken. - /// - /// - /// This example shows how to call the Require method. - /// Assume DBC_CHECK_PRECONDITION is defined. - /// - /// public void Test(int x) - /// { - /// try - /// { - /// Check.Require(x > 1, "x must be > 1"); - /// } - /// catch (System.Exception ex) - /// { - /// Console.WriteLine(ex.ToString()); - /// } - /// } - /// - /// If you wish to use trace assertion statements, intended for Debug scenarios, - /// rather than exception handling then set - /// - /// Check.UseAssertions = true - /// - /// You can specify this in your application entry point and maybe make it - /// dependent on conditional compilation flags or configuration file settings, e.g., - /// - /// #if DBC_USE_ASSERTIONS - /// Check.UseAssertions = true; - /// #endif - /// - /// You can direct output to a Trace listener. For example, you could insert - /// - /// Trace.Listeners.Clear(); - /// Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); - /// - /// - /// or direct output to a file or the Event Log. - /// - /// (Note: For ASP.NET clients use the Listeners collection - /// of the Debug, not the Trace, object and, for a Release build, only exception-handling - /// is possible.) - /// - /// - public sealed class Check - { - #region Interface - - /// - /// Precondition check. - /// - [Conditional("DBC_CHECK_ALL"), - Conditional("DBC_CHECK_INVARIANT"), - Conditional("DBC_CHECK_POSTCONDITION"), - Conditional("DBC_CHECK_PRECONDITION")] - public static void Require(bool assertion, string message) - { - if (UseExceptions) - { - if (!assertion) - throw new PreconditionException(message); - } - else - { - Trace.Assert(assertion, "Precondition: " + message); - } - } - - /// - /// Precondition check. - /// - [Conditional("DBC_CHECK_ALL"), - Conditional("DBC_CHECK_INVARIANT"), - Conditional("DBC_CHECK_POSTCONDITION"), - Conditional("DBC_CHECK_PRECONDITION")] - public static void Require(bool assertion, string message, Exception inner) - { - if (UseExceptions) - { - if (!assertion) - throw new PreconditionException(message, inner); - } - else - { - Trace.Assert(assertion, "Precondition: " + message); - } - } - - /// - /// Precondition check. - /// - [Conditional("DBC_CHECK_ALL"), - Conditional("DBC_CHECK_INVARIANT"), - Conditional("DBC_CHECK_POSTCONDITION"), - Conditional("DBC_CHECK_PRECONDITION")] - public static void Require(bool assertion) - { - if (UseExceptions) - { - if (!assertion) - throw new PreconditionException("Precondition failed."); - } - else - { - Trace.Assert(assertion, "Precondition failed."); - } - } - - /// - /// Postcondition check. - /// - [Conditional("DBC_CHECK_ALL"), - Conditional("DBC_CHECK_INVARIANT"), - Conditional("DBC_CHECK_POSTCONDITION")] - public static void Ensure(bool assertion, string message) - { - if (UseExceptions) - { - if (!assertion) - throw new PostconditionException(message); - } - else - { - Trace.Assert(assertion, "Postcondition: " + message); - } - } - - /// - /// Postcondition check. - /// - [Conditional("DBC_CHECK_ALL"), - Conditional("DBC_CHECK_INVARIANT"), - Conditional("DBC_CHECK_POSTCONDITION")] - public static void Ensure(bool assertion, string message, Exception inner) - { - if (UseExceptions) - { - if (!assertion) - throw new PostconditionException(message, inner); - } - else - { - Trace.Assert(assertion, "Postcondition: " + message); - } - } - - /// - /// Postcondition check. - /// - [Conditional("DBC_CHECK_ALL"), - Conditional("DBC_CHECK_INVARIANT"), - Conditional("DBC_CHECK_POSTCONDITION")] - public static void Ensure(bool assertion) - { - if (UseExceptions) - { - if (!assertion) - throw new PostconditionException("Postcondition failed."); - } - else - { - Trace.Assert(assertion, "Postcondition failed."); - } - } - - /// - /// Invariant check. - /// - [Conditional("DBC_CHECK_ALL"), - Conditional("DBC_CHECK_INVARIANT")] - public static void Invariant(bool assertion, string message) - { - if (UseExceptions) - { - if (!assertion) - throw new InvariantException(message); - } - else - { - Trace.Assert(assertion, "Invariant: " + message); - } - } - - /// - /// Invariant check. - /// - [Conditional("DBC_CHECK_ALL"), - Conditional("DBC_CHECK_INVARIANT")] - public static void Invariant(bool assertion, string message, Exception inner) - { - if (UseExceptions) - { - if (!assertion) - throw new InvariantException(message, inner); - } - else - { - Trace.Assert(assertion, "Invariant: " + message); - } - } - - /// - /// Invariant check. - /// - [Conditional("DBC_CHECK_ALL"), - Conditional("DBC_CHECK_INVARIANT")] - public static void Invariant(bool assertion) - { - if (UseExceptions) - { - if (!assertion) - throw new InvariantException("Invariant failed."); - } - else - { - Trace.Assert(assertion, "Invariant failed."); - } - } - - /// - /// Assertion check. - /// - [Conditional("DBC_CHECK_ALL")] - public static void Assert(bool assertion, string message) - { - if (UseExceptions) - { - if (!assertion) - throw new AssertionException(message); - } - else - { - Trace.Assert(assertion, "Assertion: " + message); - } - } - - /// - /// Assertion check. - /// - [Conditional("DBC_CHECK_ALL")] - public static void Assert(bool assertion, string message, Exception inner) - { - if (UseExceptions) - { - if (!assertion) - throw new AssertionException(message, inner); - } - else - { - Trace.Assert(assertion, "Assertion: " + message); - } - } - - /// - /// Assertion check. - /// - [Conditional("DBC_CHECK_ALL")] - public static void Assert(bool assertion) - { - if (UseExceptions) - { - if (!assertion) - throw new AssertionException("Assertion failed."); - } - else - { - Trace.Assert(assertion, "Assertion failed."); - } - } - - /// - /// Set this if you wish to use Trace Assert statements - /// instead of exception handling. - /// (The Check class uses exception handling by default.) - /// - public static bool UseAssertions - { - get - { - return useAssertions; - } - set - { - useAssertions = value; - } - } - - #endregion // Interface - - #region Implementation - - // No creation - private Check() {} - - /// - /// Is exception handling being used? - /// - private static bool UseExceptions - { - get - { - return !useAssertions; - } - } - - // Are trace assertion statements being used? - // Default is to use exception handling. - private static bool useAssertions = false; - - #endregion // Implementation - - } // End Check - - internal class Trace - { - internal static void Assert(bool assertion, string v) - { -#if NETFX_CORE - System.Diagnostics.Contracts.Contract.Assert(assertion, v); -#else - System.Diagnostics.Trace.Assert(assertion, v); -#endif - } - } - - #region Exceptions - - /// - /// Exception raised when a contract is broken. - /// Catch this exception type if you wish to differentiate between - /// any DesignByContract exception and other runtime exceptions. - /// - /// - public class DesignByContractException : Exception - { - protected DesignByContractException() {} - protected DesignByContractException(string message) : base(message) {} - protected DesignByContractException(string message, Exception inner) : base(message, inner) {} - } - - /// - /// Exception raised when a precondition fails. - /// - public class PreconditionException : DesignByContractException - { - /// - /// Precondition Exception. - /// - public PreconditionException() {} - /// - /// Precondition Exception. - /// - public PreconditionException(string message) : base(message) {} - /// - /// Precondition Exception. - /// - public PreconditionException(string message, Exception inner) : base(message, inner) {} - } - - /// - /// Exception raised when a postcondition fails. - /// - public class PostconditionException : DesignByContractException - { - /// - /// Postcondition Exception. - /// - public PostconditionException() {} - /// - /// Postcondition Exception. - /// - public PostconditionException(string message) : base(message) {} - /// - /// Postcondition Exception. - /// - public PostconditionException(string message, Exception inner) : base(message, inner) {} - } - - /// - /// Exception raised when an invariant fails. - /// - public class InvariantException : DesignByContractException - { - /// - /// Invariant Exception. - /// - public InvariantException() {} - /// - /// Invariant Exception. - /// - public InvariantException(string message) : base(message) {} - /// - /// Invariant Exception. - /// - public InvariantException(string message, Exception inner) : base(message, inner) {} - } - - /// - /// Exception raised when an assertion fails. - /// - public class AssertionException : DesignByContractException - { - /// - /// Assertion Exception. - /// - public AssertionException() {} - /// - /// Assertion Exception. - /// - public AssertionException(string message) : base(message) {} - /// - /// Assertion Exception. - /// - public AssertionException(string message, Exception inner) : base(message, inner) {} - } - - #endregion // Exception classes - -} // End Design By Contract diff --git a/Utilities/FastConcatUtility.cs b/Utilities/FastConcatUtility.cs deleted file mode 100644 index db83efa..0000000 --- a/Utilities/FastConcatUtility.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System.Text; - -public static class FastConcatUtility -{ - static readonly StringBuilder _stringBuilder = new StringBuilder(256); - - public static string FastConcat(this string str1, T str2) - { - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - - _stringBuilder.Append(str1); - _stringBuilder.Append(str2); - - return _stringBuilder.ToString(); - } - } - - public static string FastConcat(this string str1, string str2, string str3) - { - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - - _stringBuilder.Append(str1); - _stringBuilder.Append(str2); - _stringBuilder.Append(str3); - - return _stringBuilder.ToString(); - } - } - - public static string FastConcat(this string str1, string str2, string str3, string str4) - { - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - - _stringBuilder.Append(str1); - _stringBuilder.Append(str2); - _stringBuilder.Append(str3); - _stringBuilder.Append(str4); - - - return _stringBuilder.ToString(); - } - } - - public static string FastConcat(this string str1, string str2, string str3, string str4, string str5) - { - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - - _stringBuilder.Append(str1); - _stringBuilder.Append(str2); - _stringBuilder.Append(str3); - _stringBuilder.Append(str4); - _stringBuilder.Append(str5); - - return _stringBuilder.ToString(); - } - } - - public static string FastJoin(this string[] str) - { - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - - for (int i = 0; i < str.Length; i++) - _stringBuilder.Append(str[i]); - - return _stringBuilder.ToString(); - } - } - - public static string FastJoin(this string[] str, string str1) - { - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - - for (int i = 0; i < str.Length; i++) - _stringBuilder.Append(str[i]); - - _stringBuilder.Append(str1); - - return _stringBuilder.ToString(); - } - } -} - -namespace Utility -{ -#if UNITY_5 || UNITY_5_3_OR_NEWER -#endif -} diff --git a/Utilities/ILogger.cs b/Utilities/ILogger.cs deleted file mode 100644 index 20eaa23..0000000 --- a/Utilities/ILogger.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Utility -{ - public enum LogType - { - Log, - Exception, - Warning, - Error - } - public interface ILogger - { - void Log (string txt, string stack = null, LogType type = LogType.Log); - } -} \ No newline at end of file diff --git a/Utilities/Murmur3.cs b/Utilities/Murmur3.cs deleted file mode 100644 index 9a0d5d7..0000000 --- a/Utilities/Murmur3.cs +++ /dev/null @@ -1,119 +0,0 @@ -using System; - -/// -/// Murmur hash. -/// -/// Creates an evenly destributed uint hash from a string. -/// Very fast and fairly unique -/// - -public class Murmur3 -{ - static public uint MurmurHash3_x86_32(byte[] data, uint length, uint seed) - { - uint nblocks = length >> 2; - - uint h1 = seed; - - const uint c1 = 0xcc9e2d51; - const uint c2 = 0x1b873593; - - //---------- - // body - - int i = 0 ; - - for (uint j = nblocks; j > 0 ; --j) - { - uint k1l = BitConverter.ToUInt32(data, i); - - k1l *= c1; - k1l = rotl32(k1l, 15); - k1l *= c2; - - h1 ^= k1l; - h1 = rotl32(h1, 13); - h1 = h1 * 5 + 0xe6546b64; - - i+=4; - } - - //---------- - // tail - - nblocks <<= 2; - - uint k1 = 0; - - uint tailLength = length & 3; - - if (tailLength == 3) - k1 ^= (uint)data[2 + nblocks] << 16; - if (tailLength >= 2) - k1 ^= (uint)data[1 + nblocks] << 8; - if (tailLength >= 1) - { - k1 ^= data[nblocks]; - k1 *= c1; k1 = rotl32(k1, 15); k1 *= c2; h1 ^= k1; - } - - //---------- - // finalization - - h1 ^= length; - - h1 = fmix32(h1); - - return h1; - } - - static uint fmix32(uint h) - { - h ^= h >> 16; - h *= 0x85ebca6b; - h ^= h >> 13; - h *= 0xc2b2ae35; - h ^= h >> 16; - - return h; - } - - static uint rotl32(uint x, byte r) - { - return (x << r) | (x >> (32 - r)); - } - - static public bool VerificationTest() - { - byte[] key = new byte[256]; - byte[] hashes = new byte[1024]; - - for (uint i = 0; i < 256; i++) - { - key[i] = (byte)i; - - uint result = MurmurHash3_x86_32(key, i, 256 - i); - - Buffer.BlockCopy(BitConverter.GetBytes(result), 0, hashes, (int)i * 4, 4); - } - - // Then hash the result array - - uint finalr = MurmurHash3_x86_32(hashes, 1024, 0); - - uint verification = 0xB0F57EE3; - - //---------- - - if (verification != finalr) - { - return false; - } - else - { - System.Diagnostics.Debug.WriteLine("works"); - - return true; - } - } -} diff --git a/Utilities/SimpleLogger.cs b/Utilities/SimpleLogger.cs deleted file mode 100644 index 454e1dc..0000000 --- a/Utilities/SimpleLogger.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace Utility -{ - public class SimpleLogger : ILogger - { - public void Log(string txt, string stack = null, LogType type = LogType.Log) - { - switch (type) - { - case LogType.Log: - Console.SystemLog(stack != null ? txt.FastConcat(stack) : txt); - break; - case LogType.Exception: - Console.SystemLog("Log of exceptions not supported"); - break; - case LogType.Warning: - Console.SystemLog(stack != null ? txt.FastConcat(stack) : txt); - break; - case LogType.Error: - Console.SystemLog(stack != null ? txt.FastConcat(stack) : txt); - break; - } - } - } -} \ No newline at end of file diff --git a/Utilities/SlowLoggerUnity.cs b/Utilities/SlowLoggerUnity.cs deleted file mode 100644 index 6d5a33d..0000000 --- a/Utilities/SlowLoggerUnity.cs +++ /dev/null @@ -1,26 +0,0 @@ -#if UNITY_5_3_OR_NEWER || UNITY_5 -namespace Utility -{ - public class SlowLoggerUnity : ILogger - { - public void Log(string txt, string stack = null, LogType type = LogType.Log) - { - switch (type) - { - case LogType.Log: - UnityEngine.Debug.Log(stack != null ? txt.FastConcat(stack) : txt); - break; - case LogType.Exception: - UnityEngine.Debug.LogError("Log of exceptions not supported"); - break; - case LogType.Warning: - UnityEngine.Debug.LogWarning(stack != null ? txt.FastConcat(stack) : txt); - break; - case LogType.Error: - UnityEngine.Debug.LogError(stack != null ? txt.FastConcat(stack) : txt); - break; - } - } - } -} -#endif \ No newline at end of file diff --git a/WeakEvents/SafeEvent.cs b/WeakEvents/SafeEvent.cs deleted file mode 100644 index 846e58c..0000000 --- a/WeakEvents/SafeEvent.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; - -public static class SafeEvent -{ - public static void SafeRaise(this Action onEvent, T val) - { - if (onEvent != null) - { - var length = onEvent.GetInvocationList().Length; - for (int index = 0; index < length; index++) - { - Action handler = (Action) onEvent.GetInvocationList()[index]; - - try - { - if (handler != null) handler.Invoke(val); - } - catch (Exception e) - { - Utility.Console.LogException(e); - } - } - } - } - - public static void SafeRaise(this Action onEvent) - { - if (onEvent != null) - { - var length = onEvent.GetInvocationList().Length; - for (int index = 0; index < length; index++) - { - Action handler = (Action)onEvent.GetInvocationList()[index]; - - try - { - if (handler != null) handler.Invoke(); - } - catch (Exception e) - { - Utility.Console.LogException(e); - } - } - } - } -} - diff --git a/WeakEvents/WeakAction.cs b/WeakEvents/WeakAction.cs deleted file mode 100644 index e7b6470..0000000 --- a/WeakEvents/WeakAction.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using System.Reflection; -using Svelto.Utilities; - -namespace Svelto.WeakEvents -{ - public class WeakAction : WeakAction - { - public WeakAction(Action listener) - : base(listener.Target, listener.GetMethodInfoEx()) - {} - - public void Invoke(T1 data1, T2 data2) - { - _data[0] = data1; - _data[1] = data2; - - Invoke_Internal(_data); - } - - readonly object[] _data = new object[2]; - } - - public class WeakAction : WeakActionBase - { - public WeakAction(Action listener) - : base(listener.Target, listener.GetMethodInfoEx()) - {} - - public void Invoke(T data) - { - _data[0] = data; - - Invoke_Internal(_data); - } - - readonly object[] _data = new object[1]; - } - - public class WeakAction : WeakActionBase - { - public WeakAction(Action listener) : base(listener) - {} - - public WeakAction(object listener, MethodInfo method) : base(listener, method) - {} - - public void Invoke() - { - Invoke_Internal(null); - } - } - - public abstract class WeakActionBase - { - protected readonly DataStructures.WeakReference ObjectRef; - protected readonly MethodInfo Method; - - public bool IsValid - { - get { return ObjectRef.IsValid; } - } - - protected WeakActionBase(Action listener) - : this(listener.Target, listener.GetMethodInfoEx()) - {} - - protected WeakActionBase(object listener, MethodInfo method) - { - ObjectRef = new DataStructures.WeakReference(listener); - - Method = method; - - if (method.IsCompilerGenerated() == true) - throw new ArgumentException("Cannot create weak event to anonymous method with closure."); - } - - protected void Invoke_Internal(object[] data) - { - if (ObjectRef.IsValid) - Method.Invoke(ObjectRef.Target, data); - else - Utility.Console.LogWarning("Target of weak action has been garbage collected"); - } - } -} \ No newline at end of file diff --git a/WeakEvents/WeakActionStruct.cs b/WeakEvents/WeakActionStruct.cs deleted file mode 100644 index 0df2e54..0000000 --- a/WeakEvents/WeakActionStruct.cs +++ /dev/null @@ -1,147 +0,0 @@ -using System; -using System.Reflection; -using System.Runtime.InteropServices; -using Svelto.Utilities; - -//careful, you must handle the destruction of the GCHandles! -namespace Svelto.WeakEvents -{ - public struct WeakActionStruct : IEquatable>, IDisposable - { - public WeakActionStruct(Action listener) - { - WeakActionStructUtility.Init(listener.Target, listener.GetMethodInfoEx(), out _objectRef, out _method); - } - - public bool Invoke(object[] args) - { - return WeakActionStructUtility.Invoke(ref _objectRef, _method, args); - } - - public bool Equals(WeakActionStruct other) - { - return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, - other._objectRef.Target, other._method); - } - - public void Dispose() - { - _objectRef.Free(); - } - - public bool IsMatch(object otherObject, MethodInfo otherMethod) - { - return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, - otherObject, otherMethod); - } - - GCHandle _objectRef; - readonly MethodInfo _method; - } - - public struct WeakActionStruct : IEquatable>, IDisposable - { - public WeakActionStruct(Action listener) - { - WeakActionStructUtility.Init(listener.Target, listener.GetMethodInfoEx(), - out _objectRef, out _method); - } - - public bool Invoke(object[] args) - { - return WeakActionStructUtility.Invoke(ref _objectRef, _method, args); - } - - public bool Equals(WeakActionStruct other) - { - return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, - other._objectRef.Target, other._method); - } - - public void Dispose() - { - _objectRef.Free(); - } - - public bool IsMatch(object otherObject, MethodInfo otherMethod) - { - return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, - otherObject, otherMethod); - } - - GCHandle _objectRef; - readonly MethodInfo _method; - } - - public struct WeakActionStruct : IEquatable, IDisposable - { - public WeakActionStruct(Action listener) - { - WeakActionStructUtility.Init(listener.Target, listener.GetMethodInfoEx(), - out _objectRef, out _method); - } - - public bool Invoke() - { - return WeakActionStructUtility.Invoke(ref _objectRef, _method, null); - } - - public bool Equals(WeakActionStruct other) - { - return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, - other._objectRef.Target, other._method); - } - - public void Dispose() - { - _objectRef.Free(); - } - - public bool IsMatch(object otherObject, MethodInfo otherMethod) - { - return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, - otherObject, otherMethod); - } - - GCHandle _objectRef; - readonly MethodInfo _method; - } - - static class WeakActionStructUtility - { - internal static void Init(object target, MethodInfo method, - out GCHandle objectRef, out MethodInfo methodOut) - { - objectRef = GCHandle.Alloc(target, GCHandleType.Weak); - methodOut = method; - -#if DEBUG && !PROFILER - if (method.IsCompilerGenerated() == true) - throw new ArgumentException("Cannot create weak event to anonymous method with closure."); -#endif - } - - public static bool Invoke(ref GCHandle objectRef, MethodInfo method, object[] args) - { - if (objectRef.IsAllocated && objectRef.Target != null) - { - method.Invoke(objectRef.Target, args); - return true; - } - - Dispose(ref objectRef); - return false; - } - - public static void Dispose(ref GCHandle objectRef) - { - objectRef.Free(); - } - - public static bool IsMatch(object objectRef, MethodInfo method, - object _objectRef, MethodInfo _method) - { - return _method.Equals(method) && objectRef.Equals(_objectRef); - } - } -} \ No newline at end of file diff --git a/WeakEvents/WeakEvent.cs b/WeakEvents/WeakEvent.cs deleted file mode 100644 index bcef44f..0000000 --- a/WeakEvents/WeakEvent.cs +++ /dev/null @@ -1,193 +0,0 @@ -using Svelto.DataStructures; -using System; -using System.Reflection; - -namespace Svelto.WeakEvents -{ - public class WeakEvent - { - public static WeakEvent operator+(WeakEvent c1, Action x) - { - if (c1 == null) c1 = new WeakEvent(); - c1.Add(x); - - return c1; - } - - public static WeakEvent operator-(WeakEvent c1, Action x) - { - DesignByContract.Check.Require(x != null); - c1.Remove(x); - - return c1; - } - - public void Add(Action x) - { - _subscribers.Add(new WeakActionStruct(x)); - } - - public void Remove(Action x) - { - RemoveInternal(x.Target, x.GetMethodInfoEx()); - } - - public void Invoke() - { - for (int i = 0; i < _subscribers.Count; i++) - if (_subscribers[i].Invoke() == false) - _subscribers.UnorderedRemoveAt(i--); - } - - void RemoveInternal(object thisObject, MethodInfo thisMethod) - { - for (int i = 0; i < _subscribers.Count; ++i) - { - var otherObject = _subscribers[i]; - - if (otherObject.IsMatch(thisObject, thisMethod)) - { - _subscribers.UnorderedRemoveAt(i); - break; - } - } - } - - ~WeakEvent() - { - for (int i = 0; i < _subscribers.Count; i++) - _subscribers[i].Dispose(); - } - - readonly FasterList - _subscribers = new FasterList(); - } - - public class WeakEvent - { - public static WeakEvent operator+(WeakEvent c1, Action x) - { - if (c1 == null) c1 = new WeakEvent(); - c1.Add(x); - - return c1; - } - - public static WeakEvent operator-(WeakEvent c1, Action x) - { - DesignByContract.Check.Require(x != null); - c1.Remove(x); - - return c1; - } - - public void Add(Action x) - { - _subscribers.Add(new WeakActionStruct(x)); - } - - public void Remove(Action x) - { - RemoveInternal(x.Target, x.GetMethodInfoEx()); - } - - public void Invoke(T1 arg1) - { - args[0] = arg1; - - for (int i = 0; i < _subscribers.Count; i++) - if (_subscribers[i].Invoke(args) == false) - _subscribers.UnorderedRemoveAt(i--); - } - - void RemoveInternal(object thisObject, MethodInfo thisMethod) - { - for (int i = 0; i < _subscribers.Count; ++i) - { - var otherObject = _subscribers[i]; - - if (otherObject.IsMatch(thisObject, thisMethod)) - { - _subscribers.UnorderedRemoveAt(i); - break; - } - } - } - - ~WeakEvent() - { - for (int i = 0; i < _subscribers.Count; i++) - _subscribers[i].Dispose(); - } - - readonly object[] args = new object[1]; - - readonly FasterList> - _subscribers = new FasterList>(); - } - - public class WeakEvent - { - public static WeakEvent operator+(WeakEvent c1, Action x) - { - if (c1 == null) c1 = new WeakEvent(); - c1._subscribers.Add(new WeakActionStruct(x)); - - return c1; - } - - public static WeakEvent operator-(WeakEvent c1, Action x) - { - DesignByContract.Check.Require(x != null); - c1.Remove(x); - - return c1; - } - - public void Add(Action x) - { - _subscribers.Add(new WeakActionStruct(x)); - } - - public void Remove(Action x) - { - RemoveInternal(x.Target, x.GetMethodInfoEx()); - } - - public void Invoke(T1 arg1, T2 arg2) - { - args[0] = arg1; - args[1] = arg2; - - for (int i = 0; i < _subscribers.Count; i++) - if (_subscribers[i].Invoke(args) == false) - _subscribers.UnorderedRemoveAt(i--); - } - - void RemoveInternal(object thisObject, MethodInfo thisMethod) - { - for (int i = 0; i < _subscribers.Count; ++i) - { - var otherObject = _subscribers[i]; - - if (otherObject.IsMatch(thisObject, thisMethod)) - { - _subscribers.UnorderedRemoveAt(i); - - break; - } - } - } - - ~WeakEvent() - { - for (int i = 0; i < _subscribers.Count; i++) - _subscribers[i].Dispose(); - } - - readonly object[] args = new object[2]; - - readonly FasterList> - _subscribers = new FasterList>(); - } -}