diff --git a/src/EcsPipeline.Builder.cs b/src/EcsPipeline.Builder.cs index f81533b..8a6872e 100644 --- a/src/EcsPipeline.Builder.cs +++ b/src/EcsPipeline.Builder.cs @@ -1,12 +1,11 @@ #if DISABLE_DEBUG #undef DEBUG #endif +using DCFApixels.DragonECS.Core; using DCFApixels.DragonECS.Internal; using DCFApixels.DragonECS.RunnersCore; using System; -using System.Collections; using System.Collections.Generic; -using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; @@ -25,7 +24,7 @@ namespace DCFApixels.DragonECS public sealed partial class EcsPipeline { - public class Builder : IEcsModule + public partial class Builder : IEcsModule { private SystemNode[] _systemNodes = new SystemNode[256]; private int _startIndex = -1; @@ -37,7 +36,7 @@ namespace DCFApixels.DragonECS private readonly Dictionary _layerLists = new Dictionary(8); private readonly List _initDeclaredRunners = new List(4); - public readonly LayerList Layers; + public readonly LayersMap Layers; public readonly Injector.Builder Injector; public readonly Configurator Configs; @@ -64,7 +63,8 @@ namespace DCFApixels.DragonECS Injector.AddNode(); Injector.AddNode(); - Layers = new LayerList(this, PRE_BEGIN_LAYER, BEGIN_LAYER, BASIC_LAYER, END_LAYER, POST_END_LAYER); + var graph = new DependencyGraph(BASIC_LAYER); + Layers = new LayersMap(graph, this, PRE_BEGIN_LAYER, BEGIN_LAYER, BASIC_LAYER, END_LAYER, POST_END_LAYER); } #endregion @@ -234,21 +234,22 @@ namespace DCFApixels.DragonECS } private void MergeWith(Builder other) { - Injector.Add(other.Injector); - foreach (var declaredRunners in other._initDeclaredRunners) - { - _initDeclaredRunners.Add(declaredRunners); - } - foreach (var config in other.Configs.Instance.GetAllConfigs()) - { - Configs.Instance.Set(config.Key, config.Value); - } - Layers.MergeWith(other.Layers); - - foreach (ref readonly SystemNode otherRecord in new LinkedListIterator(_systemNodes, _systemNodesCount, _startIndex)) - { - AddNode_Internal(otherRecord.system, otherRecord.layerName, otherRecord.sortOrder, otherRecord.isUnique); - } + throw new NotImplementedException(); + //Injector.Add(other.Injector); + //foreach (var declaredRunners in other._initDeclaredRunners) + //{ + // _initDeclaredRunners.Add(declaredRunners); + //} + //foreach (var config in other.Configs.Instance.GetAllConfigs()) + //{ + // Configs.Instance.Set(config.Key, config.Value); + //} + //Layers.MergeWith(other.Layers); + // + //foreach (ref readonly SystemNode otherRecord in new LinkedListCountIterator(_systemNodes, _systemNodesCount, _startIndex)) + //{ + // AddNode_Internal(otherRecord.system, otherRecord.layerName, otherRecord.sortOrder, otherRecord.isUnique); + //} } #endregion @@ -309,7 +310,7 @@ namespace DCFApixels.DragonECS #if DEBUG _buildMarker.Begin(); #endif - var it = new LinkedListIterator(_systemNodes, _systemNodesCount, _startIndex); + var it = new LinkedListCountIterator(_systemNodes, _systemNodesCount, _startIndex); LayerSystemsList basicLayerList; if (_layerLists.TryGetValue(BASIC_LAYER, out basicLayerList) == false) @@ -354,7 +355,7 @@ namespace DCFApixels.DragonECS IEcsProcess[] allSystems = new IEcsProcess[allSystemsLength]; { int i = 0; - foreach (var item in Layers) + foreach (var item in Layers.Build()) { if (_layerLists.TryGetValue(item, out var list) && list.IsInit) { @@ -413,217 +414,10 @@ namespace DCFApixels.DragonECS return _builder; } } + #endregion - #region LayerList - public class LayerList : IEnumerable - { - private Builder _source; - private List _layers; - private string _basicLayerName; - private string _addLayerName; - - #region Properties - public int Count { get { return _layers.Count; } } - public object this[int index] { get { return _layers[index]; } } - #endregion - - #region Constructors - public LayerList(Builder source, string basicLayerName) - { - _source = source; - _layers = new List(16) { basicLayerName }; - _basicLayerName = basicLayerName; - _addLayerName = _basicLayerName; - } - public LayerList(Builder source, string preBeginlayer, string beginlayer, string basicLayer, string endLayer, string postEndLayer) - { - _source = source; - _layers = new List(16) { preBeginlayer, beginlayer, basicLayer, endLayer, postEndLayer }; - _basicLayerName = basicLayer; - _addLayerName = _basicLayerName; - } - #endregion - - #region Edit - - #region Single - public Builder Add(string newLayer) - { - InsertAfter(_addLayerName, newLayer); - _addLayerName = newLayer; - return _source; - } - public Builder Insert(string targetLayer, string newLayer) - { - if (Contains(newLayer)) { return _source; } - - int index = _layers.IndexOf(targetLayer); - if (index < 0) - { - throw new KeyNotFoundException($"Layer {targetLayer} not found"); - } - _layers.Insert(index, newLayer); - return _source; - } - public Builder InsertAfter(string targetLayer, string newLayer) - { - if (Contains(newLayer)) { return _source; } - - int index = _layers.IndexOf(targetLayer); - if (index < 0) - { - throw new KeyNotFoundException($"Layer {targetLayer} not found"); - } - - _layers.Insert(++index, newLayer); - return _source; - } - public Builder Move(string targetLayer, string movingLayer) - { - _layers.Remove(movingLayer); - return Insert(targetLayer, movingLayer); - } - public Builder MoveAfter(string targetLayer, string movingLayer) - { - _layers.Remove(movingLayer); - return InsertAfter(targetLayer, movingLayer); - } - #endregion - - #region Range - public Builder Add(params string[] newLayers) - { - InsertAfter(_addLayerName, newLayers); - _addLayerName = newLayers[newLayers.Length - 1]; - return _source; - } - public Builder Insert(string targetLayer, params string[] newLayers) - { - int index = _layers.IndexOf(targetLayer); - if (index < 0) - { - throw new KeyNotFoundException($"Layer {targetLayer} not found"); - } - _layers.InsertRange(index, newLayers.Where(o => !Contains(o))); - return _source; - } - public Builder InsertAfter(string targetLayer, params string[] newLayers) - { - int index = _layers.IndexOf(targetLayer); - if (index < 0) - { - throw new KeyNotFoundException($"Layer {targetLayer} not found"); - } - - _layers.InsertRange(++index, newLayers.Where(o => !Contains(o))); - return _source; - } - public Builder Move(string targetLayer, params string[] movingLayers) - { - foreach (var movingLayer in movingLayers) - { - _layers.Remove(movingLayer); - } - return Insert(targetLayer, movingLayers); - } - public Builder MoveAfter(string targetLayer, params string[] movingLayers) - { - foreach (var movingLayer in movingLayers) - { - _layers.Remove(movingLayer); - } - return InsertAfter(targetLayer, movingLayers); - } - #endregion - - #endregion - - #region MergeWith - private static bool CheckOverlapsOrder(List listA, IReadOnlyList listB) - { - int lastIndexof = 0; - for (int i = 0; i < listB.Count; i++) - { - var a = listB[i]; - int indexof = listA.IndexOf(a); - - if (indexof < 0) { continue; } - if (indexof < lastIndexof) - { - return false; - } - lastIndexof = indexof; - } - return true; - } - public void MergeWith(IReadOnlyList other) - { - List listA = _layers; - IReadOnlyList listB = other; - - if (CheckOverlapsOrder(listA, listB) == false) - { - //Для слияния списков слоев, нужно чтобы в пересечении порядок записей совпадал - Throw.Exception("To merge layer lists, the names of the layers present in both lists must appear in the same order in both lists."); - } - - HashSet seen = new HashSet(); - List result = new List(); - - foreach (string item in listA) - { - seen.Add(item); - } - foreach (string item in listB) - { - if (seen.Add(item) == false) - { - seen.Remove(item); - } - } - - int i = 0, j = 0; - while (i < listA.Count || j < listB.Count) - { - while (i < listA.Count && seen.Contains(listA[i])) - { - result.Add(listA[i]); - i++; - } - while (j < listB.Count && seen.Contains(listB[j])) - { - result.Add(listB[j]); - j++; - } - - if (i < listA.Count) { i++; } - if (j < listB.Count) - { - result.Add(listB[j]); - j++; - } - } - - _layers = result; - } - public void MergeWith(LayerList other) - { - MergeWith(other._layers); - } - #endregion - - #region Other - public bool Contains(string layer) { return _layers.Contains(layer); } - - public List.Enumerator GetEnumerator() { return _layers.GetEnumerator(); } - IEnumerator IEnumerable.GetEnumerator() { return _layers.GetEnumerator(); } - IEnumerator IEnumerable.GetEnumerator() { return _layers.GetEnumerator(); } - #endregion - } - #endregion - - #region SystemsList + #region LayerSystemsList private class LayerSystemsList { public int lasyInitSystemsCount = 0; @@ -768,6 +562,18 @@ namespace DCFApixels.DragonECS } } #endregion + + #region Obsolete + [Obsolete("Use LayersMap")] + public class LayerList : LayersMap + { + //public LayerList(Builder source, string basicLayerName) : base(source, basicLayerName) { } + //public LayerList(Builder source, string preBeginlayer, string beginlayer, string basicLayer, string endLayer, string postEndLayer) : base(source, preBeginlayer, beginlayer, basicLayer, endLayer, postEndLayer) { } + public LayerList(IDependencyGraph graph, Builder pipelineBuilder) : base(graph, pipelineBuilder) + { + } + } + #endregion } } diff --git a/src/Utils/DependencyGraph.cs b/src/Utils/DependencyGraph.cs new file mode 100644 index 0000000..c499959 --- /dev/null +++ b/src/Utils/DependencyGraph.cs @@ -0,0 +1,549 @@ +using DCFApixels.DragonECS.Internal; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + +namespace DCFApixels.DragonECS.Core +{ + using VertexID = DependencyGraphVertextID; + public enum DependencyGraphVertextID : short { NULL = 0 } + public interface IDependencyGraph : IReadOnlyCollection + { + ReadonlyDependenciesCollection Dependencies { get; } + VertexID AddVertex(T vertex, bool isLocked); + bool ContainsVertex(T vertex); + VertexID GetVertexID(T vertex); + T GetVertexFromID(VertexID vertexID); + bool RemoveVertex(T vertex); + void AddDependency(VertexID fromID, VertexID toID, bool moveToRight); + void MergeWith(IDependencyGraph other); + T[] Sort(); + } + public static class DependencyGraphExtensions + { + public static void AddDependency(this IDependencyGraph self, T from, T to, bool moveToRight) + { + self.AddDependency(self.GetVertexID(from), self.GetVertexID(to), moveToRight); + } + } + public struct ReadonlyDependenciesCollection : IReadOnlyCollection<(T from, T to)> + { + private IDependencyGraph _graph; + private IReadOnlyCollection<(VertexID from, VertexID to)> _source; + public int Count + { + get { return _source.Count; } + } + public ReadonlyDependenciesCollection(IDependencyGraph graph, IReadOnlyCollection<(VertexID from, VertexID to)> source) + { + _graph = graph; + _source = source; + } + public Enumerator GetEnumerator() { return new Enumerator(_graph, _source.GetEnumerator()); } + IEnumerator<(T from, T to)> IEnumerable<(T from, T to)>.GetEnumerator() { return GetEnumerator(); } + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + public struct Enumerator : IEnumerator<(T from, T to)> + { + private IDependencyGraph _graph; + private IEnumerator<(VertexID from, VertexID to)> _source; + public Enumerator(IDependencyGraph graph, IEnumerator<(VertexID from, VertexID to)> source) + { + _graph = graph; + _source = source; + } + public (T from, T to) Current + { + get + { + var (from, to) = _source.Current; + return (_graph.GetVertexFromID(from), _graph.GetVertexFromID(to)); + } + } + object IEnumerator.Current { get { return Current; } } + public bool MoveNext() { return _source.MoveNext(); } + public void Reset() { _source.Reset(); } + public void Dispose() { } + } + } + + + + public unsafe class DependencyGraph : IDependencyGraph + { + private readonly Dictionary _vertexIDs = new Dictionary(32); + private StructList _vertexInfos = new StructList(32); + + private List<(VertexID from, VertexID to)> _dependencies = new List<(VertexID, VertexID)>(16); + private readonly VertexID _basicVertexID; + private int _increment = 1; + private int _count; + + #region Properties + public int Count + { + get { return _count; } + } + public ReadonlyDependenciesCollection Dependencies + { + get { return new ReadonlyDependenciesCollection(this, _dependencies); } + } + #endregion + + #region Constructors + public DependencyGraph() + { + //GetVertexID(""); + _vertexInfos.Add(default); + _basicVertexID = VertexID.NULL; + } + public DependencyGraph(T basicVertexName) + { + //GetVertexID(""); + _vertexInfos.Add(default); + _basicVertexID = GetVertexID(basicVertexName); + LockVertex(basicVertexName); + } + #endregion + + #region Methods + public VertexID GetVertexID(T vertext) + { + if (_vertexIDs.TryGetValue(vertext, out VertexID layerID) == false) + { + layerID = (VertexID)_vertexInfos.Count; + _vertexInfos.Add(default); + + _vertexIDs[vertext] = layerID; + ref var layerInfo = ref GetVertexInfo(layerID); + layerInfo.value = vertext; + } + return layerID; + } + public T GetVertexFromID(VertexID vertexID) + { + return GetVertexInfo(vertexID).value; + } + private ref VertexInfo GetVertexInfo(VertexID vertexID) + { + return ref _vertexInfos._items[(int)vertexID]; + } + private ref VertexInfo GetVertexInfo(int vertexID) + { + return ref _vertexInfos._items[(int)vertexID]; + } + private int GetVertexInfosCount() + { + return _vertexInfos.Count; + } + public VertexID AddVertex(T vertex, bool isLocked) + { + var result = GetVertexID(vertex); + AddVertexByID(result); + if (isLocked) + { + LockVertex(result); + } + return result; + } + private void LockVertex(T vertex) + { + LockVertex(GetVertexID(vertex)); + } + private void LockVertex(VertexID vertexID) + { + GetVertexInfo(vertexID).isLocked = true; + } + private void AddVertexByID(VertexID id) + { + ref var info = ref GetVertexInfo(id); + if (info.isContained == false || info.isLocked == false) + { + _count++; + info.isContained = true; + } + info.insertionIndex = _increment++; + } + public bool RemoveVertex(T vertex) + { + var result = GetVertexID(vertex); + return RemoveVertexByID(result); + } + private bool RemoveVertexByID(VertexID id) + { + ref var info = ref GetVertexInfo(id); + bool result = false; + if (info.isLocked) { throw new Exception($"The {info.value} vertex cannot be removed"); } + if (info.isContained) + { + _count--; + info.isContained = false; + result = true; + } + info.insertionIndex = 0; + return result; + } + public void AddDependency(VertexID fromVertexID, VertexID toVertexID, bool moveToRight) + { + ref var fromInfo = ref GetVertexInfo(fromVertexID); + ref var toInfo = ref GetVertexInfo(toVertexID); + fromInfo.hasAnyDependency = true; + toInfo.hasAnyDependency = true; + fromInfo.moveToRight = moveToRight; + _dependencies.Add((fromVertexID, toVertexID)); + } + #endregion + + #region MergeWith + public void MergeWith(IDependencyGraph other) + { + if (other is DependencyGraph graph) + { + foreach (var otherDependency in graph._dependencies) + { + this.AddDependency(graph.GetVertexFromID(otherDependency.from), graph.GetVertexFromID(otherDependency.to), false); + } + for (int i = 0; i < graph.GetVertexInfosCount(); i++) + { + ref var otherLayerInfo = ref graph.GetVertexInfo(i); + AddVertexByID(GetVertexID(graph.GetVertexFromID((VertexID)i))); + } + } + foreach (var otherDependency in other.Dependencies) + { + this.AddDependency(otherDependency.from, otherDependency.to, false); + } + foreach (var vertex in other) + { + AddVertex(vertex, false); + } + } + #endregion + + #region Sort + public T[] Sort() + { + const int BUFFER_THRESHOLD = 256; + if (_count <= BUFFER_THRESHOLD) + { + var ptr = stackalloc VertexID[_count]; + var buffer = UnsafeArray.Manual(ptr, _count); + TopoSorting(buffer); + ReoderInsertionIndexes(buffer); + TopoSorting(buffer); + return ConvertIdsToTsArray(buffer); + } + else + { + var ptr = TempBuffer.Get(_count); + var buffer = UnsafeArray.Manual(ptr, _count); + TopoSorting(buffer); + ReoderInsertionIndexes(buffer); + TopoSorting(buffer); + return ConvertIdsToTsArray(buffer); + } + } + private void TopoSorting(UnsafeArray sortingBuffer) + { + VertexID[] nodes = new VertexID[_count]; + var adjacency = new List<(VertexID To, int DependencyIndex)>[GetVertexInfosCount()]; + + for (int i = 0, j = 0; i < GetVertexInfosCount(); i++) + { + VertexID layerID = (VertexID)i; + ref var info = ref GetVertexInfo(layerID); + adjacency[(int)layerID] = new List<(VertexID To, int DependencyIndex)>(); + GetVertexInfo(layerID).inDegree = 0; + if (info.isContained) + { + nodes[j++] = layerID; + } + } + + for (int i = 0; i < _dependencies.Count; i++) + { + var (from, to) = _dependencies[i]; + ref var fromInfo = ref GetVertexInfo(from); + ref var toInfo = ref GetVertexInfo(to); + + if (fromInfo.isContained && toInfo.isContained) + { + adjacency[(int)from].Add((to, i)); + toInfo.inDegree += 1; + } + } + + // добавление зависимостей для нод без зависимостей. + if (_basicVertexID != VertexID.NULL) + { + var basicLayerAdjacencyList = adjacency[(int)_basicVertexID]; + int inserIndex = basicLayerAdjacencyList.Count; + for (int i = 0; i < GetVertexInfosCount(); i++) + { + var toID = (VertexID)i; + ref var toInfo = ref GetVertexInfo(i); + if (toInfo.isContained && toInfo.hasAnyDependency == false) + { + basicLayerAdjacencyList.Insert(inserIndex, (toID, toInfo.insertionIndex)); + toInfo.inDegree += 1; + } + } + } + + List zeroInDegree = new List(nodes.Length); + zeroInDegree.AddRange(nodes.Where(id => GetVertexInfo(id).inDegree == 0).OrderBy(id => GetVertexInfo(id).insertionIndex)); + + int resultCount = 0; + + while (zeroInDegree.Count > 0) + { + var current = zeroInDegree[0]; + zeroInDegree.RemoveAt(0); + + GetVertexInfo(current).sortingIndex = resultCount; + sortingBuffer.ptr[resultCount++] = current; + + var adjacencyList = adjacency[(int)current]; + for (int i = 0; i < adjacencyList.Count; i++) + { + var (neighbor, _) = adjacencyList[i]; + ref var neighborInfo = ref GetVertexInfo(neighbor); + neighborInfo.inDegree--; + if (neighborInfo.inDegree == 0) + { + var neighborInsertionIndex = neighborInfo.insertionIndex; + int insertIndex = zeroInDegree.FindIndex(id => GetVertexInfo(id).insertionIndex < neighborInsertionIndex); + insertIndex = insertIndex < 0 ? 0 : insertIndex; + zeroInDegree.Insert(insertIndex, neighbor); + } + } + } + + if (resultCount != nodes.Length) + { + var cycle = FindCycle(adjacency, nodes); + string details = string.Empty; + if (cycle != null) + { + var cycleDependencies = GetCycleDependencies(cycle, adjacency); + details = $" Cycle edges path: {string.Join(", ", cycleDependencies)}"; + } + throw new InvalidOperationException("Cyclic dependency detected." + details); + } + } + private void ReoderInsertionIndexes(UnsafeArray sortingBuffer) + { + for (int i = 0; i < GetVertexInfosCount(); i++) + { + ref var info = ref GetVertexInfo(i); + if (info.isContained == false) { continue; } + info.leftBeforeIndex = info.moveToRight ? int.MaxValue : 0; + } + + foreach (var dependency in _dependencies) + { + ref var fromInfo = ref GetVertexInfo(dependency.from); + if (fromInfo.moveToRight) + { + ref var toInfo = ref GetVertexInfo(dependency.to); + fromInfo.leftBeforeIndex = Math.Min(toInfo.sortingIndex, fromInfo.leftBeforeIndex); + } + } + + for (int i = sortingBuffer.Length - 1; i >= 0; i--) + { + var id = sortingBuffer.ptr[i]; + ref var info = ref GetVertexInfo(id); + if (info.moveToRight) + { + if (info.leftBeforeIndex < sortingBuffer.Length) + { + MoveElement(ref sortingBuffer, i, info.leftBeforeIndex - 1); + } + } + } + + for (int i = 0; i < sortingBuffer.Length; i++) + { + ref var info = ref GetVertexInfo(sortingBuffer.ptr[i]); + info.insertionIndex = i; + + } + } + private static void MoveElement(ref UnsafeArray array, int oldIndex, int newIndex) where TValue : unmanaged + { + if (oldIndex == newIndex) return; + + var ptr = array.ptr; + TValue item = ptr[oldIndex]; + + int elementSize = sizeof(TValue); + int copyLength = Math.Abs(newIndex - oldIndex); + + byte* source; + byte* destination; + long bytesToCopy = copyLength * elementSize; + + if (oldIndex < newIndex) + { + // Сдвиг вправо: копируем блок [oldIndex+1 ... newIndex] в [oldIndex ... newIndex-1] + source = (byte*)(ptr + oldIndex + 1); + destination = (byte*)(ptr + oldIndex); + } + else + { + // Сдвиг влево: копируем блок [newIndex ... oldIndex-1] в [newIndex+1 ... oldIndex] + source = (byte*)(ptr + newIndex); + destination = (byte*)(ptr + newIndex + 1); + } + Buffer.MemoryCopy(source: source, destination: destination, destinationSizeInBytes: bytesToCopy, sourceBytesToCopy: bytesToCopy); + + ptr[newIndex] = item; + } + private T[] ConvertIdsToTsArray(UnsafeArray buffer) + { + T[] result = new T[buffer.Length]; + for (int i = 0; i < result.Length; i++) + { + result[i] = GetVertexInfo(buffer.ptr[i]).value; + } + return result; + } + #endregion + + #region FindCycles + private List FindCycle( + List<(VertexID To, int DependencyIndex)>[] adjacency, + VertexID[] nodes) + { + var visited = new Dictionary(); + var recursionStack = new Stack(); + + foreach (var node in nodes) + { + if (FindCycleDFS(node, adjacency, visited, recursionStack)) + { + return recursionStack.Reverse().ToList(); + } + } + return null; + } + private bool FindCycleDFS( + VertexID node, + List<(VertexID To, int DependencyIndex)>[] adjacency, + Dictionary visited, + Stack recursionStack) + { + if (!visited.TryGetValue(node, out bool isVisited)) + { + visited[node] = true; + recursionStack.Push(node); + + foreach (var (neighbor, _) in adjacency[(int)node]) + { + if (!visited.ContainsKey(neighbor) && FindCycleDFS(neighbor, adjacency, visited, recursionStack)) + { + return true; + } + else if (recursionStack.Contains(neighbor)) + { + recursionStack.Push(neighbor); + return true; + } + } + + recursionStack.Pop(); + return false; + } + return isVisited && recursionStack.Contains(node); + } + + private string[] GetCycleDependencies( + List cycle, + List<(VertexID To, int DependencyIndex)>[] adjacency) + { + var cycleEdges = new HashSet<(VertexID, VertexID)>(); + for (int i = 0; i < cycle.Count - 1; i++) + { + cycleEdges.Add((cycle[i], cycle[i + 1])); + } + + var dependencies = new List(); + foreach (var from in cycle) + { + foreach (var (to, depIndex) in adjacency[(int)from]) + { + if (cycleEdges.Contains((from, to)) && _dependencies.Count > depIndex) + { + var dep = _dependencies[depIndex]; + dependencies.Add($"{GetVertexInfo(dep.from).value}->{GetVertexInfo(dep.to).value}"); + } + } + } + return dependencies.Distinct().ToArray(); + } + #endregion + + #region Other + public bool ContainsVertex(T vertex) + { + return GetVertexInfo(GetVertexID(vertex)).isContained; + } + public Enumerator GetEnumerator() { return new Enumerator(this); } + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + public struct Enumerator : IEnumerator + { + private DependencyGraph _graph; + private int _index; + public Enumerator(DependencyGraph graph) + { + _graph = graph; + _index = -1; + } + public T Current + { + get { return _graph.GetVertexInfo(_index).value; } + } + object IEnumerator.Current { get { return Current; } } + public bool MoveNext() + { + if (_index++ >= _graph.GetVertexInfosCount()) { return false; } + ref var info = ref _graph.GetVertexInfo(_index); + if (info.isContained == false) + { + return MoveNext(); + } + else + { + return true; + } + } + public void Reset() { _index = -1; } + public void Dispose() { } + } + #endregion + + #region VertexInfo + [DebuggerDisplay("{value}")] + private struct VertexInfo + { + public T value; + public int insertionIndex; + public bool isLocked; + public bool isContained; + public bool moveToRight; + //build + public bool hasAnyDependency; + public int inDegree; + public int sortingIndex; + public int leftBeforeIndex; + public VertexInfo(T name) : this() + { + this.value = name; + } + } + #endregion + } +} \ No newline at end of file diff --git a/src/Utils/LayersMap.cs b/src/Utils/LayersMap.cs new file mode 100644 index 0000000..8ee47a8 --- /dev/null +++ b/src/Utils/LayersMap.cs @@ -0,0 +1,325 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace DCFApixels.DragonECS.Core +{ + using VertexID = DependencyGraphVertextID; + public class LayersMap : IDependencyGraph + { + #region IDependencyGraph + VertexID IDependencyGraph.AddVertex(string vertex, bool isLocked) { return _graph.AddVertex(vertex, isLocked); } + bool IDependencyGraph.ContainsVertex(string vertex) { return _graph.ContainsVertex(vertex); } + VertexID IDependencyGraph.GetVertexID(string vertex) { return _graph.GetVertexID(vertex); } + string IDependencyGraph.GetVertexFromID(VertexID vertexID) { return _graph.GetVertexFromID(vertexID); } + bool IDependencyGraph.RemoveVertex(string vertex) { return _graph.RemoveVertex(vertex); } + void IDependencyGraph.AddDependency(VertexID fromID, VertexID toID, bool moveToRight) { _graph.AddDependency(fromID, toID, moveToRight); } + string[] IDependencyGraph.Sort() { return _graph.Sort(); } + #endregion + + private readonly IDependencyGraph _graph; + private readonly EcsPipeline.Builder _pipelineBuilder; + private readonly string _preBeginLayer; + + #region Properties + public EcsPipeline.Builder Back + { + get { return _pipelineBuilder; } + } + public int Count + { + get { return _graph.Count; } + } + public ReadonlyDependenciesCollection Dependencies + { + get { return _graph.Dependencies; } + } + #endregion + + #region Constructors + public LayersMap(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder) + { + _graph = graph; + _pipelineBuilder = pipelineBuilder; + } + public LayersMap(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder, string preBeginlayer, string beginlayer, string basicLayer, string endLayer, string postEndLayer) + { + _graph = graph; + _pipelineBuilder = pipelineBuilder; + + graph.AddVertex(preBeginlayer, true); + graph.AddVertex(beginlayer, true); + graph.AddVertex(basicLayer, true); + graph.AddVertex(endLayer, true); + graph.AddVertex(postEndLayer, true); + + Move(preBeginlayer); + //.Before(beginlayer); + Move(beginlayer) + //.Before(basicLayer) + .After(preBeginlayer); + Move(basicLayer) + //.Before(endLayer) + .After(beginlayer); + Move(endLayer) + //.Before(postEndLayer) + .After(basicLayer); + Move(postEndLayer) + .After(endLayer); + } + #endregion + + #region Add + public MoveHandler Add(string layer) + { + VertexID id = _graph.AddVertex(layer, false); + return new MoveHandler(_graph, _pipelineBuilder, id); + } + public MoveHandler Add(params string[] layers) + { + return Add(layersRange: layers); + } + public MoveHandler Add(IEnumerable layersRange) + { + foreach (var layer in layersRange) + { + Add(layer); + } + return new MoveHandler(_graph, _pipelineBuilder, layersRange); + } + #endregion + + #region Move + public MoveHandler Move(string layer) + { + VertexID id = _graph.GetVertexID(layer); + return new MoveHandler(_graph, _pipelineBuilder, id); + } + public MoveHandler Move(params string[] layers) + { + return new MoveHandler(_graph, _pipelineBuilder, layers); + } + public MoveHandler Move(IEnumerable layersRange) + { + return new MoveHandler(_graph, _pipelineBuilder, layersRange); + } + #endregion + + #region MoveHandler + public struct MoveHandler + { + private readonly IDependencyGraph _graph; + private readonly EcsPipeline.Builder _pipelineBuilder; + private readonly VertexID _layerID; + private readonly IEnumerable _layersRange; + + #region Properties + public EcsPipeline.Builder Back + { + get { return _pipelineBuilder; } + } + #endregion + + #region Constructors + public MoveHandler(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder, VertexID id) + { + _graph = graph; + _pipelineBuilder = pipelineBuilder; + _layerID = id; + _layersRange = null; + } + public MoveHandler(IDependencyGraph graph, EcsPipeline.Builder pipelineBuilder, IEnumerable layersRange) + { + _graph = graph; + _pipelineBuilder = pipelineBuilder; + _layerID = VertexID.NULL; + _layersRange = layersRange; + } + #endregion + + #region Before + public MoveHandler Before(params string[] targets) + { + return Before(targetsRange: targets); + } + public MoveHandler Before(IEnumerable targetsRange) + { + foreach (var target in targetsRange) + { + Before(target); + } + return this; + } + public MoveHandler Before(string targetLayer) + { + if (_layerID != VertexID.NULL) + { + _graph.AddDependency(_layerID, _graph.GetVertexID(targetLayer), true); + } + if (_layersRange != null) + { + foreach (var layer in _layersRange) + { + _graph.AddDependency(_graph.GetVertexID(layer), _graph.GetVertexID(targetLayer), true); + } + } + return this; + } + #endregion + + #region After + public MoveHandler After(params string[] targets) + { + return After(targetsRange: targets); + } + public MoveHandler After(IEnumerable targetsRange) + { + foreach (var target in targetsRange) + { + After(target); + } + return this; + } + public MoveHandler After(string targetLayer) + { + if (_layerID != VertexID.NULL) + { + _graph.AddDependency(_graph.GetVertexID(targetLayer), _layerID, false); + } + if (_layersRange != null) + { + foreach (var layer in _layersRange) + { + _graph.AddDependency(_graph.GetVertexID(targetLayer), _graph.GetVertexID(layer), false); + } + } + return this; + } + #endregion + } + #endregion + + #region MergeWith + public void MergeWith(IDependencyGraph other) + { + _graph.MergeWith(other); + } + //[Obsolete("Use MergeWith(LayersMap)")] + public void MergeWith(IReadOnlyList other) + { + var enumerator = other.GetEnumerator(); + string prev = null; + if (_preBeginLayer != null) + { + while (enumerator.MoveNext()) + { + var layer = enumerator.Current; + if (layer == _preBeginLayer) { break; } + + Add(layer); + if (prev != null) + { + Move(prev).Before(layer); + } + prev = layer; + } + } + while (enumerator.MoveNext()) + { + var layer = enumerator.Current; + Add(layer); + if (prev != null) + { + Move(layer).After(prev); + } + prev = layer; + } + } + #endregion; + + #region Other + public bool Contains(string layer) + { + return _graph.ContainsVertex(layer); + } + public IEnumerator GetEnumerator() { return _graph.GetEnumerator(); } + IEnumerator IEnumerable.GetEnumerator() { return _graph.GetEnumerator(); } + #endregion + + #region Build + public string[] Build() + { + return _graph.Sort(); + } + #endregion + + #region Obsolete + [Obsolete("Use " + nameof(LayersMap) + ".Add(layer).Before(targetLayer).Back;")] + public EcsPipeline.Builder Insert(string targetLayer, string newLayer) + { + Add(newLayer).Before(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(LayersMap) + ".Add(layer).After(targetLayer).Back;")] + public EcsPipeline.Builder InsertAfter(string targetLayer, string newLayer) + { + Add(newLayer).After(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(LayersMap) + ".Move(layer).Before(targetLayer).Back;")] + public EcsPipeline.Builder Move(string targetLayer, string newLayer) + { + Move(newLayer).Before(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(LayersMap) + ".Move(layer).After(targetLayer).Back;")] + public EcsPipeline.Builder MoveAfter(string targetLayer, string newLayer) + { + Move(newLayer).After(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(LayersMap) + ".Add(layers).Before(targetLayer).Back;")] + public EcsPipeline.Builder Insert(string targetLayer, params string[] newLayers) + { + Add(newLayers).Before(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(LayersMap) + ".Add(layers).After(targetLayer).Back;")] + public EcsPipeline.Builder InsertAfter(string targetLayer, params string[] newLayers) + { + Add(newLayers).After(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(LayersMap) + ".Move(layers).Before(targetLayer).Back;")] + public EcsPipeline.Builder Move(string targetLayer, params string[] movingLayers) + { + Move(movingLayers).Before(targetLayer); + return _pipelineBuilder; + } + [Obsolete("Use " + nameof(LayersMap) + ".Move(layers).After(targetLayer).Back;")] + public EcsPipeline.Builder MoveAfter(string targetLayer, params string[] movingLayers) + { + Move(movingLayers).After(targetLayer); + return _pipelineBuilder; + } + + [Obsolete] + public object this[int index] + { + get + { + int i = 0; + foreach (var item in this) + { + if (i == index) + { + return item; + } + i++; + } + return null; + } + } + #endregion + } +} \ No newline at end of file